1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* net/atm/addr.c - Local ATM address registry */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/atm.h>
7*4882a593Smuzhiyun #include <linux/atmdev.h>
8*4882a593Smuzhiyun #include <linux/slab.h>
9*4882a593Smuzhiyun #include <linux/uaccess.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include "signaling.h"
12*4882a593Smuzhiyun #include "addr.h"
13*4882a593Smuzhiyun
check_addr(const struct sockaddr_atmsvc * addr)14*4882a593Smuzhiyun static int check_addr(const struct sockaddr_atmsvc *addr)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun int i;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun if (addr->sas_family != AF_ATMSVC)
19*4882a593Smuzhiyun return -EAFNOSUPPORT;
20*4882a593Smuzhiyun if (!*addr->sas_addr.pub)
21*4882a593Smuzhiyun return *addr->sas_addr.prv ? 0 : -EINVAL;
22*4882a593Smuzhiyun for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */
23*4882a593Smuzhiyun if (!addr->sas_addr.pub[i])
24*4882a593Smuzhiyun return 0;
25*4882a593Smuzhiyun return -EINVAL;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
identical(const struct sockaddr_atmsvc * a,const struct sockaddr_atmsvc * b)28*4882a593Smuzhiyun static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun if (*a->sas_addr.prv)
31*4882a593Smuzhiyun if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
32*4882a593Smuzhiyun return 0;
33*4882a593Smuzhiyun if (!*a->sas_addr.pub)
34*4882a593Smuzhiyun return !*b->sas_addr.pub;
35*4882a593Smuzhiyun if (!*b->sas_addr.pub)
36*4882a593Smuzhiyun return 0;
37*4882a593Smuzhiyun return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
notify_sigd(const struct atm_dev * dev)40*4882a593Smuzhiyun static void notify_sigd(const struct atm_dev *dev)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun struct sockaddr_atmpvc pvc;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun pvc.sap_addr.itf = dev->number;
45*4882a593Smuzhiyun sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
atm_reset_addr(struct atm_dev * dev,enum atm_addr_type_t atype)48*4882a593Smuzhiyun void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun unsigned long flags;
51*4882a593Smuzhiyun struct atm_dev_addr *this, *p;
52*4882a593Smuzhiyun struct list_head *head;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun spin_lock_irqsave(&dev->lock, flags);
55*4882a593Smuzhiyun if (atype == ATM_ADDR_LECS)
56*4882a593Smuzhiyun head = &dev->lecs;
57*4882a593Smuzhiyun else
58*4882a593Smuzhiyun head = &dev->local;
59*4882a593Smuzhiyun list_for_each_entry_safe(this, p, head, entry) {
60*4882a593Smuzhiyun list_del(&this->entry);
61*4882a593Smuzhiyun kfree(this);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
64*4882a593Smuzhiyun if (head == &dev->local)
65*4882a593Smuzhiyun notify_sigd(dev);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
atm_add_addr(struct atm_dev * dev,const struct sockaddr_atmsvc * addr,enum atm_addr_type_t atype)68*4882a593Smuzhiyun int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
69*4882a593Smuzhiyun enum atm_addr_type_t atype)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun unsigned long flags;
72*4882a593Smuzhiyun struct atm_dev_addr *this;
73*4882a593Smuzhiyun struct list_head *head;
74*4882a593Smuzhiyun int error;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun error = check_addr(addr);
77*4882a593Smuzhiyun if (error)
78*4882a593Smuzhiyun return error;
79*4882a593Smuzhiyun spin_lock_irqsave(&dev->lock, flags);
80*4882a593Smuzhiyun if (atype == ATM_ADDR_LECS)
81*4882a593Smuzhiyun head = &dev->lecs;
82*4882a593Smuzhiyun else
83*4882a593Smuzhiyun head = &dev->local;
84*4882a593Smuzhiyun list_for_each_entry(this, head, entry) {
85*4882a593Smuzhiyun if (identical(&this->addr, addr)) {
86*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
87*4882a593Smuzhiyun return -EEXIST;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
91*4882a593Smuzhiyun if (!this) {
92*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
93*4882a593Smuzhiyun return -ENOMEM;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun this->addr = *addr;
96*4882a593Smuzhiyun list_add(&this->entry, head);
97*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
98*4882a593Smuzhiyun if (head == &dev->local)
99*4882a593Smuzhiyun notify_sigd(dev);
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
atm_del_addr(struct atm_dev * dev,const struct sockaddr_atmsvc * addr,enum atm_addr_type_t atype)103*4882a593Smuzhiyun int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
104*4882a593Smuzhiyun enum atm_addr_type_t atype)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun unsigned long flags;
107*4882a593Smuzhiyun struct atm_dev_addr *this;
108*4882a593Smuzhiyun struct list_head *head;
109*4882a593Smuzhiyun int error;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun error = check_addr(addr);
112*4882a593Smuzhiyun if (error)
113*4882a593Smuzhiyun return error;
114*4882a593Smuzhiyun spin_lock_irqsave(&dev->lock, flags);
115*4882a593Smuzhiyun if (atype == ATM_ADDR_LECS)
116*4882a593Smuzhiyun head = &dev->lecs;
117*4882a593Smuzhiyun else
118*4882a593Smuzhiyun head = &dev->local;
119*4882a593Smuzhiyun list_for_each_entry(this, head, entry) {
120*4882a593Smuzhiyun if (identical(&this->addr, addr)) {
121*4882a593Smuzhiyun list_del(&this->entry);
122*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
123*4882a593Smuzhiyun kfree(this);
124*4882a593Smuzhiyun if (head == &dev->local)
125*4882a593Smuzhiyun notify_sigd(dev);
126*4882a593Smuzhiyun return 0;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
130*4882a593Smuzhiyun return -ENOENT;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
atm_get_addr(struct atm_dev * dev,struct sockaddr_atmsvc __user * buf,size_t size,enum atm_addr_type_t atype)133*4882a593Smuzhiyun int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
134*4882a593Smuzhiyun size_t size, enum atm_addr_type_t atype)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun unsigned long flags;
137*4882a593Smuzhiyun struct atm_dev_addr *this;
138*4882a593Smuzhiyun struct list_head *head;
139*4882a593Smuzhiyun int total = 0, error;
140*4882a593Smuzhiyun struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun spin_lock_irqsave(&dev->lock, flags);
143*4882a593Smuzhiyun if (atype == ATM_ADDR_LECS)
144*4882a593Smuzhiyun head = &dev->lecs;
145*4882a593Smuzhiyun else
146*4882a593Smuzhiyun head = &dev->local;
147*4882a593Smuzhiyun list_for_each_entry(this, head, entry)
148*4882a593Smuzhiyun total += sizeof(struct sockaddr_atmsvc);
149*4882a593Smuzhiyun tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
150*4882a593Smuzhiyun if (!tmp_buf) {
151*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
152*4882a593Smuzhiyun return -ENOMEM;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun list_for_each_entry(this, head, entry)
155*4882a593Smuzhiyun memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
156*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->lock, flags);
157*4882a593Smuzhiyun error = total > size ? -E2BIG : total;
158*4882a593Smuzhiyun if (copy_to_user(buf, tmp_buf, total < size ? total : size))
159*4882a593Smuzhiyun error = -EFAULT;
160*4882a593Smuzhiyun kfree(tmp_buf);
161*4882a593Smuzhiyun return error;
162*4882a593Smuzhiyun }
163