1 // SPDX-License-Identifier: GPL-2.0
2 /* net/atm/addr.c - Local ATM address registry */
4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
7 #include <linux/atmdev.h>
8 #include <linux/slab.h>
9 #include <linux/uaccess.h>
11 #include "signaling.h"
14 static int check_addr(const struct sockaddr_atmsvc
*addr
)
18 if (addr
->sas_family
!= AF_ATMSVC
)
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
])
28 static int identical(const struct sockaddr_atmsvc
*a
, const struct sockaddr_atmsvc
*b
)
31 if (memcmp(a
->sas_addr
.prv
, b
->sas_addr
.prv
, ATM_ESA_LEN
))
33 if (!*a
->sas_addr
.pub
)
34 return !*b
->sas_addr
.pub
;
35 if (!*b
->sas_addr
.pub
)
37 return !strcmp(a
->sas_addr
.pub
, b
->sas_addr
.pub
);
40 static void notify_sigd(const struct atm_dev
*dev
)
42 struct sockaddr_atmpvc pvc
;
44 pvc
.sap_addr
.itf
= dev
->number
;
45 sigd_enq(NULL
, as_itf_notify
, NULL
, &pvc
, NULL
);
48 void atm_reset_addr(struct atm_dev
*dev
, enum atm_addr_type_t atype
)
51 struct atm_dev_addr
*this, *p
;
52 struct list_head
*head
;
54 spin_lock_irqsave(&dev
->lock
, flags
);
55 if (atype
== ATM_ADDR_LECS
)
59 list_for_each_entry_safe(this, p
, head
, entry
) {
60 list_del(&this->entry
);
63 spin_unlock_irqrestore(&dev
->lock
, flags
);
64 if (head
== &dev
->local
)
68 int atm_add_addr(struct atm_dev
*dev
, const struct sockaddr_atmsvc
*addr
,
69 enum atm_addr_type_t atype
)
72 struct atm_dev_addr
*this;
73 struct list_head
*head
;
76 error
= check_addr(addr
);
79 spin_lock_irqsave(&dev
->lock
, flags
);
80 if (atype
== ATM_ADDR_LECS
)
84 list_for_each_entry(this, head
, entry
) {
85 if (identical(&this->addr
, addr
)) {
86 spin_unlock_irqrestore(&dev
->lock
, flags
);
90 this = kmalloc(sizeof(struct atm_dev_addr
), GFP_ATOMIC
);
92 spin_unlock_irqrestore(&dev
->lock
, flags
);
96 list_add(&this->entry
, head
);
97 spin_unlock_irqrestore(&dev
->lock
, flags
);
98 if (head
== &dev
->local
)
103 int atm_del_addr(struct atm_dev
*dev
, const struct sockaddr_atmsvc
*addr
,
104 enum atm_addr_type_t atype
)
107 struct atm_dev_addr
*this;
108 struct list_head
*head
;
111 error
= check_addr(addr
);
114 spin_lock_irqsave(&dev
->lock
, flags
);
115 if (atype
== ATM_ADDR_LECS
)
119 list_for_each_entry(this, head
, entry
) {
120 if (identical(&this->addr
, addr
)) {
121 list_del(&this->entry
);
122 spin_unlock_irqrestore(&dev
->lock
, flags
);
124 if (head
== &dev
->local
)
129 spin_unlock_irqrestore(&dev
->lock
, flags
);
133 int atm_get_addr(struct atm_dev
*dev
, struct sockaddr_atmsvc __user
* buf
,
134 size_t size
, enum atm_addr_type_t atype
)
137 struct atm_dev_addr
*this;
138 struct list_head
*head
;
139 int total
= 0, error
;
140 struct sockaddr_atmsvc
*tmp_buf
, *tmp_bufp
;
142 spin_lock_irqsave(&dev
->lock
, flags
);
143 if (atype
== ATM_ADDR_LECS
)
147 list_for_each_entry(this, head
, entry
)
148 total
+= sizeof(struct sockaddr_atmsvc
);
149 tmp_buf
= tmp_bufp
= kmalloc(total
, GFP_ATOMIC
);
151 spin_unlock_irqrestore(&dev
->lock
, flags
);
154 list_for_each_entry(this, head
, entry
)
155 memcpy(tmp_bufp
++, &this->addr
, sizeof(struct sockaddr_atmsvc
));
156 spin_unlock_irqrestore(&dev
->lock
, flags
);
157 error
= total
> size
? -E2BIG
: total
;
158 if (copy_to_user(buf
, tmp_buf
, total
< size
? total
: size
))