[NET]: Add some sparse annotations to network driver stack.
[linux-2.6/history.git] / net / atm / addr.c
blob459bdeed05f9e3573cc38bdef9b22afd82ff558c
1 /* net/atm/addr.c - Local ATM address registry */
3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/atm.h>
7 #include <linux/atmdev.h>
8 #include <linux/sched.h>
9 #include <asm/uaccess.h>
11 #include "signaling.h"
12 #include "addr.h"
15 static int check_addr(struct sockaddr_atmsvc *addr)
17 int i;
19 if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
20 if (!*addr->sas_addr.pub)
21 return *addr->sas_addr.prv ? 0 : -EINVAL;
22 for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */
23 if (!addr->sas_addr.pub[i]) return 0;
24 return -EINVAL;
28 static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b)
30 if (*a->sas_addr.prv)
31 if (memcmp(a->sas_addr.prv,b->sas_addr.prv,ATM_ESA_LEN))
32 return 0;
33 if (!*a->sas_addr.pub) return !*b->sas_addr.pub;
34 if (!*b->sas_addr.pub) return 0;
35 return !strcmp(a->sas_addr.pub,b->sas_addr.pub);
39 static void notify_sigd(struct atm_dev *dev)
41 struct sockaddr_atmpvc pvc;
43 pvc.sap_addr.itf = dev->number;
44 sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
48 void atm_reset_addr(struct atm_dev *dev)
50 unsigned long flags;
51 struct atm_dev_addr *this;
53 spin_lock_irqsave(&dev->lock, flags);
54 while (dev->local) {
55 this = dev->local;
56 dev->local = this->next;
57 kfree(this);
59 spin_unlock_irqrestore(&dev->lock, flags);
60 notify_sigd(dev);
64 int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
66 unsigned long flags;
67 struct atm_dev_addr **walk;
68 int error;
70 error = check_addr(addr);
71 if (error)
72 return error;
73 spin_lock_irqsave(&dev->lock, flags);
74 for (walk = &dev->local; *walk; walk = &(*walk)->next)
75 if (identical(&(*walk)->addr,addr)) {
76 spin_unlock_irqrestore(&dev->lock, flags);
77 return -EEXIST;
79 *walk = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
80 if (!*walk) {
81 spin_unlock_irqrestore(&dev->lock, flags);
82 return -ENOMEM;
84 (*walk)->addr = *addr;
85 (*walk)->next = NULL;
86 spin_unlock_irqrestore(&dev->lock, flags);
87 notify_sigd(dev);
88 return 0;
92 int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
94 unsigned long flags;
95 struct atm_dev_addr **walk,*this;
96 int error;
98 error = check_addr(addr);
99 if (error)
100 return error;
101 spin_lock_irqsave(&dev->lock, flags);
102 for (walk = &dev->local; *walk; walk = &(*walk)->next)
103 if (identical(&(*walk)->addr,addr)) break;
104 if (!*walk) {
105 spin_unlock_irqrestore(&dev->lock, flags);
106 return -ENOENT;
108 this = *walk;
109 *walk = this->next;
110 kfree(this);
111 spin_unlock_irqrestore(&dev->lock, flags);
112 notify_sigd(dev);
113 return 0;
117 int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
119 unsigned long flags;
120 struct atm_dev_addr *walk;
121 int total = 0, error;
122 struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
125 spin_lock_irqsave(&dev->lock, flags);
126 for (walk = dev->local; walk; walk = walk->next)
127 total += sizeof(struct sockaddr_atmsvc);
128 tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
129 if (!tmp_buf) {
130 spin_unlock_irqrestore(&dev->lock, flags);
131 return -ENOMEM;
133 for (walk = dev->local; walk; walk = walk->next)
134 memcpy(tmp_bufp++, &walk->addr, sizeof(struct sockaddr_atmsvc));
135 spin_unlock_irqrestore(&dev->lock, flags);
136 error = total > size ? -E2BIG : total;
137 if (copy_to_user(u_buf, tmp_buf, total < size ? total : size))
138 error = -EFAULT;
139 kfree(tmp_buf);
140 return error;