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