| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /* net/atm/addr.c - Local ATM address registry */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/atm.h>
 | 
					
						
							|  |  |  | #include <linux/atmdev.h>
 | 
					
						
							|  |  |  | #include <asm/uaccess.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "signaling.h"
 | 
					
						
							|  |  |  | #include "addr.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 16:20:06 -07:00
										 |  |  | static int check_addr(const struct sockaddr_atmsvc *addr) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (addr->sas_family != AF_ATMSVC) | 
					
						
							|  |  |  | 		return -EAFNOSUPPORT; | 
					
						
							|  |  |  | 	if (!*addr->sas_addr.pub) | 
					
						
							|  |  |  | 		return *addr->sas_addr.prv ? 0 : -EINVAL; | 
					
						
							|  |  |  | 	for (i = 1; i < ATM_E164_LEN + 1; i++)	/* make sure it's \0-terminated */ | 
					
						
							|  |  |  | 		if (!addr->sas_addr.pub[i]) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	return -EINVAL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 16:20:06 -07:00
										 |  |  | static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (*a->sas_addr.prv) | 
					
						
							|  |  |  | 		if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN)) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	if (!*a->sas_addr.pub) | 
					
						
							|  |  |  | 		return !*b->sas_addr.pub; | 
					
						
							|  |  |  | 	if (!*b->sas_addr.pub) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	return !strcmp(a->sas_addr.pub, b->sas_addr.pub); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 16:20:06 -07:00
										 |  |  | static void notify_sigd(const struct atm_dev *dev) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct sockaddr_atmpvc pvc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pvc.sap_addr.itf = dev->number; | 
					
						
							|  |  |  | 	sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	struct atm_dev_addr *this, *p; | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	struct list_head *head; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&dev->lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	if (atype == ATM_ADDR_LECS) | 
					
						
							|  |  |  | 		head = &dev->lecs; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		head = &dev->local; | 
					
						
							|  |  |  | 	list_for_each_entry_safe(this, p, head, entry) { | 
					
						
							| 
									
										
										
										
											2005-09-28 16:35:22 -07:00
										 |  |  | 		list_del(&this->entry); | 
					
						
							|  |  |  | 		kfree(this); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	if (head == &dev->local) | 
					
						
							|  |  |  | 		notify_sigd(dev); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 16:20:06 -07:00
										 |  |  | int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 		 enum atm_addr_type_t atype) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	struct atm_dev_addr *this; | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	struct list_head *head; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = check_addr(addr); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 	spin_lock_irqsave(&dev->lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	if (atype == ATM_ADDR_LECS) | 
					
						
							|  |  |  | 		head = &dev->lecs; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		head = &dev->local; | 
					
						
							|  |  |  | 	list_for_each_entry(this, head, entry) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (identical(&this->addr, addr)) { | 
					
						
							|  |  |  | 			spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							|  |  |  | 			return -EEXIST; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC); | 
					
						
							|  |  |  | 	if (!this) { | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	this->addr = *addr; | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	list_add(&this->entry, head); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	if (head == &dev->local) | 
					
						
							|  |  |  | 		notify_sigd(dev); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 16:20:06 -07:00
										 |  |  | int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 		 enum atm_addr_type_t atype) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	struct atm_dev_addr *this; | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	struct list_head *head; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = check_addr(addr); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 	spin_lock_irqsave(&dev->lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	if (atype == ATM_ADDR_LECS) | 
					
						
							|  |  |  | 		head = &dev->lecs; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		head = &dev->local; | 
					
						
							|  |  |  | 	list_for_each_entry(this, head, entry) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		if (identical(&this->addr, addr)) { | 
					
						
							|  |  |  | 			list_del(&this->entry); | 
					
						
							|  |  |  | 			spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							|  |  |  | 			kfree(this); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 			if (head == &dev->local) | 
					
						
							|  |  |  | 				notify_sigd(dev); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							|  |  |  | 	return -ENOENT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 		 size_t size, enum atm_addr_type_t atype) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	struct atm_dev_addr *this; | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	struct list_head *head; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	int total = 0, error; | 
					
						
							|  |  |  | 	struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&dev->lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	if (atype == ATM_ADDR_LECS) | 
					
						
							|  |  |  | 		head = &dev->lecs; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		head = &dev->local; | 
					
						
							|  |  |  | 	list_for_each_entry(this, head, entry) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	    total += sizeof(struct sockaddr_atmsvc); | 
					
						
							|  |  |  | 	tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); | 
					
						
							|  |  |  | 	if (!tmp_buf) { | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-10-06 22:19:28 -07:00
										 |  |  | 	list_for_each_entry(this, head, entry) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	    memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&dev->lock, flags); | 
					
						
							|  |  |  | 	error = total > size ? -E2BIG : total; | 
					
						
							|  |  |  | 	if (copy_to_user(buf, tmp_buf, total < size ? total : size)) | 
					
						
							|  |  |  | 		error = -EFAULT; | 
					
						
							|  |  |  | 	kfree(tmp_buf); | 
					
						
							|  |  |  | 	return error; | 
					
						
							|  |  |  | } |