Import 2.3.18pre1
[davej-history.git] / net / atm / addr.c
blobf7d52a824a5bb6cad7bfee4e31b6130d7e66ee81
1 /* net/atm/addr.c - Local ATM address registry */
3 /* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/atm.h>
7 #include <linux/atmdev.h>
8 #include <linux/wait.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)
45 static volatile int local_lock = 0;
46 static wait_queue_head_t local_wait;
49 static void lock_local(void)
51 while (local_lock) sleep_on(&local_wait);
52 local_lock = 1;
56 static void unlock_local(void)
58 local_lock = 0;
59 wake_up(&local_wait);
63 static void notify_sigd(struct atm_dev *dev)
65 struct sockaddr_atmpvc pvc;
67 pvc.sap_addr.itf = dev->number;
68 sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
72 void reset_addr(struct atm_dev *dev)
74 struct atm_dev_addr *this;
76 lock_local();
77 while (dev->local) {
78 this = dev->local;
79 dev->local = this->next;
80 kfree(this);
82 unlock_local();
83 notify_sigd(dev);
87 int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
89 struct atm_dev_addr **walk;
90 int error;
92 error = check_addr(addr);
93 if (error) return error;
94 lock_local();
95 for (walk = &dev->local; *walk; walk = &(*walk)->next)
96 if (identical(&(*walk)->addr,addr)) {
97 unlock_local();
98 return -EEXIST;
100 *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
101 if (!*walk) {
102 unlock_local();
103 return -ENOMEM;
105 (*walk)->addr = *addr;
106 (*walk)->next = NULL;
107 unlock_local();
108 notify_sigd(dev);
109 return 0;
113 int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
115 struct atm_dev_addr **walk,*this;
116 int error;
118 error = check_addr(addr);
119 if (error) return error;
120 lock_local();
121 for (walk = &dev->local; *walk; walk = &(*walk)->next)
122 if (identical(&(*walk)->addr,addr)) break;
123 if (!*walk) {
124 unlock_local();
125 return -ENOENT;
127 this = *walk;
128 *walk = this->next;
129 kfree(this);
130 unlock_local();
131 notify_sigd(dev);
132 return 0;
136 int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
138 struct atm_dev_addr *walk;
139 int total;
141 lock_local();
142 total = 0;
143 for (walk = dev->local; walk; walk = walk->next) {
144 total += sizeof(struct sockaddr_atmsvc);
145 if (total > size) {
146 unlock_local();
147 return -E2BIG;
149 if (copy_to_user(u_buf,&walk->addr,
150 sizeof(struct sockaddr_atmsvc))) {
151 unlock_local();
152 return -EFAULT;
154 u_buf++;
156 unlock_local();
157 return total;
161 void init_addr(void)
163 init_waitqueue_head(&local_wait);