Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / net / atm / addr.c
blob1814a8b212cf368d885accaad9d796b458dd0536
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);
40 * Avoid modification of any list of local interfaces while reading it
41 * (which may involve page faults and therefore rescheduling)
44 static DECLARE_MUTEX(local_lock);
45 extern spinlock_t atm_dev_lock;
47 static void notify_sigd(struct atm_dev *dev)
49 struct sockaddr_atmpvc pvc;
51 pvc.sap_addr.itf = dev->number;
52 sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
56 void reset_addr(struct atm_dev *dev)
58 struct atm_dev_addr *this;
60 down(&local_lock);
61 spin_lock (&atm_dev_lock);
62 while (dev->local) {
63 this = dev->local;
64 dev->local = this->next;
65 kfree(this);
67 up(&local_lock);
68 spin_unlock (&atm_dev_lock);
69 notify_sigd(dev);
73 int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
75 struct atm_dev_addr **walk;
76 int error;
78 error = check_addr(addr);
79 if (error) return error;
80 down(&local_lock);
81 for (walk = &dev->local; *walk; walk = &(*walk)->next)
82 if (identical(&(*walk)->addr,addr)) {
83 up(&local_lock);
84 return -EEXIST;
86 *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
87 if (!*walk) {
88 up(&local_lock);
89 return -ENOMEM;
91 (*walk)->addr = *addr;
92 (*walk)->next = NULL;
93 up(&local_lock);
94 notify_sigd(dev);
95 return 0;
99 int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
101 struct atm_dev_addr **walk,*this;
102 int error;
104 error = check_addr(addr);
105 if (error) return error;
106 down(&local_lock);
107 for (walk = &dev->local; *walk; walk = &(*walk)->next)
108 if (identical(&(*walk)->addr,addr)) break;
109 if (!*walk) {
110 up(&local_lock);
111 return -ENOENT;
113 this = *walk;
114 *walk = this->next;
115 kfree(this);
116 up(&local_lock);
117 notify_sigd(dev);
118 return 0;
122 int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
124 struct atm_dev_addr *walk;
125 int total;
127 down(&local_lock);
128 total = 0;
129 for (walk = dev->local; walk; walk = walk->next) {
130 total += sizeof(struct sockaddr_atmsvc);
131 if (total > size) {
132 up(&local_lock);
133 return -E2BIG;
135 if (copy_to_user(u_buf,&walk->addr,
136 sizeof(struct sockaddr_atmsvc))) {
137 up(&local_lock);
138 return -EFAULT;
140 u_buf++;
142 up(&local_lock);
143 return total;