1 /* net/atm/addr.c - Local ATM address registry */
3 /* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
7 #include <linux/atmdev.h>
8 #include <linux/wait.h>
9 #include <asm/uaccess.h>
11 #include "signaling.h"
15 static int check_addr(struct sockaddr_atmsvc
*addr
)
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;
28 static int identical(struct sockaddr_atmsvc
*a
,struct sockaddr_atmsvc
*b
)
31 if (memcmp(a
->sas_addr
.prv
,b
->sas_addr
.prv
,ATM_ESA_LEN
))
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
);
56 static void unlock_local(void)
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;
79 dev
->local
= this->next
;
87 int add_addr(struct atm_dev
*dev
,struct sockaddr_atmsvc
*addr
)
89 struct atm_dev_addr
**walk
;
92 error
= check_addr(addr
);
93 if (error
) return error
;
95 for (walk
= &dev
->local
; *walk
; walk
= &(*walk
)->next
)
96 if (identical(&(*walk
)->addr
,addr
)) {
100 *walk
= kmalloc(sizeof(struct atm_dev_addr
),GFP_KERNEL
);
105 (*walk
)->addr
= *addr
;
106 (*walk
)->next
= NULL
;
113 int del_addr(struct atm_dev
*dev
,struct sockaddr_atmsvc
*addr
)
115 struct atm_dev_addr
**walk
,*this;
118 error
= check_addr(addr
);
119 if (error
) return error
;
121 for (walk
= &dev
->local
; *walk
; walk
= &(*walk
)->next
)
122 if (identical(&(*walk
)->addr
,addr
)) break;
136 int get_addr(struct atm_dev
*dev
,struct sockaddr_atmsvc
*u_buf
,int size
)
138 struct atm_dev_addr
*walk
;
143 for (walk
= dev
->local
; walk
; walk
= walk
->next
) {
144 total
+= sizeof(struct sockaddr_atmsvc
);
149 if (copy_to_user(u_buf
,&walk
->addr
,
150 sizeof(struct sockaddr_atmsvc
))) {
163 init_waitqueue_head(&local_wait
);