Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/phonet/pn_dev.c
15109 views
1
/*
2
* File: pn_dev.c
3
*
4
* Phonet network device
5
*
6
* Copyright (C) 2008 Nokia Corporation.
7
*
8
* Contact: Remi Denis-Courmont <[email protected]>
9
* Original author: Sakari Ailus <[email protected]>
10
*
11
* This program is free software; you can redistribute it and/or
12
* modify it under the terms of the GNU General Public License
13
* version 2 as published by the Free Software Foundation.
14
*
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23
* 02110-1301 USA
24
*/
25
26
#include <linux/kernel.h>
27
#include <linux/net.h>
28
#include <linux/slab.h>
29
#include <linux/netdevice.h>
30
#include <linux/phonet.h>
31
#include <linux/proc_fs.h>
32
#include <linux/if_arp.h>
33
#include <net/sock.h>
34
#include <net/netns/generic.h>
35
#include <net/phonet/pn_dev.h>
36
37
struct phonet_routes {
38
struct mutex lock;
39
struct net_device *table[64];
40
};
41
42
struct phonet_net {
43
struct phonet_device_list pndevs;
44
struct phonet_routes routes;
45
};
46
47
int phonet_net_id __read_mostly;
48
49
static struct phonet_net *phonet_pernet(struct net *net)
50
{
51
BUG_ON(!net);
52
53
return net_generic(net, phonet_net_id);
54
}
55
56
struct phonet_device_list *phonet_device_list(struct net *net)
57
{
58
struct phonet_net *pnn = phonet_pernet(net);
59
return &pnn->pndevs;
60
}
61
62
/* Allocate new Phonet device. */
63
static struct phonet_device *__phonet_device_alloc(struct net_device *dev)
64
{
65
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
66
struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC);
67
if (pnd == NULL)
68
return NULL;
69
pnd->netdev = dev;
70
bitmap_zero(pnd->addrs, 64);
71
72
BUG_ON(!mutex_is_locked(&pndevs->lock));
73
list_add_rcu(&pnd->list, &pndevs->list);
74
return pnd;
75
}
76
77
static struct phonet_device *__phonet_get(struct net_device *dev)
78
{
79
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
80
struct phonet_device *pnd;
81
82
BUG_ON(!mutex_is_locked(&pndevs->lock));
83
list_for_each_entry(pnd, &pndevs->list, list) {
84
if (pnd->netdev == dev)
85
return pnd;
86
}
87
return NULL;
88
}
89
90
static struct phonet_device *__phonet_get_rcu(struct net_device *dev)
91
{
92
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
93
struct phonet_device *pnd;
94
95
list_for_each_entry_rcu(pnd, &pndevs->list, list) {
96
if (pnd->netdev == dev)
97
return pnd;
98
}
99
return NULL;
100
}
101
102
static void phonet_device_destroy(struct net_device *dev)
103
{
104
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
105
struct phonet_device *pnd;
106
107
ASSERT_RTNL();
108
109
mutex_lock(&pndevs->lock);
110
pnd = __phonet_get(dev);
111
if (pnd)
112
list_del_rcu(&pnd->list);
113
mutex_unlock(&pndevs->lock);
114
115
if (pnd) {
116
u8 addr;
117
118
for_each_set_bit(addr, pnd->addrs, 64)
119
phonet_address_notify(RTM_DELADDR, dev, addr);
120
kfree(pnd);
121
}
122
}
123
124
struct net_device *phonet_device_get(struct net *net)
125
{
126
struct phonet_device_list *pndevs = phonet_device_list(net);
127
struct phonet_device *pnd;
128
struct net_device *dev = NULL;
129
130
rcu_read_lock();
131
list_for_each_entry_rcu(pnd, &pndevs->list, list) {
132
dev = pnd->netdev;
133
BUG_ON(!dev);
134
135
if ((dev->reg_state == NETREG_REGISTERED) &&
136
((pnd->netdev->flags & IFF_UP)) == IFF_UP)
137
break;
138
dev = NULL;
139
}
140
if (dev)
141
dev_hold(dev);
142
rcu_read_unlock();
143
return dev;
144
}
145
146
int phonet_address_add(struct net_device *dev, u8 addr)
147
{
148
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
149
struct phonet_device *pnd;
150
int err = 0;
151
152
mutex_lock(&pndevs->lock);
153
/* Find or create Phonet-specific device data */
154
pnd = __phonet_get(dev);
155
if (pnd == NULL)
156
pnd = __phonet_device_alloc(dev);
157
if (unlikely(pnd == NULL))
158
err = -ENOMEM;
159
else if (test_and_set_bit(addr >> 2, pnd->addrs))
160
err = -EEXIST;
161
mutex_unlock(&pndevs->lock);
162
return err;
163
}
164
165
int phonet_address_del(struct net_device *dev, u8 addr)
166
{
167
struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev));
168
struct phonet_device *pnd;
169
int err = 0;
170
171
mutex_lock(&pndevs->lock);
172
pnd = __phonet_get(dev);
173
if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) {
174
err = -EADDRNOTAVAIL;
175
pnd = NULL;
176
} else if (bitmap_empty(pnd->addrs, 64))
177
list_del_rcu(&pnd->list);
178
else
179
pnd = NULL;
180
mutex_unlock(&pndevs->lock);
181
182
if (pnd)
183
kfree_rcu(pnd, rcu);
184
185
return err;
186
}
187
188
/* Gets a source address toward a destination, through a interface. */
189
u8 phonet_address_get(struct net_device *dev, u8 daddr)
190
{
191
struct phonet_device *pnd;
192
u8 saddr;
193
194
rcu_read_lock();
195
pnd = __phonet_get_rcu(dev);
196
if (pnd) {
197
BUG_ON(bitmap_empty(pnd->addrs, 64));
198
199
/* Use same source address as destination, if possible */
200
if (test_bit(daddr >> 2, pnd->addrs))
201
saddr = daddr;
202
else
203
saddr = find_first_bit(pnd->addrs, 64) << 2;
204
} else
205
saddr = PN_NO_ADDR;
206
rcu_read_unlock();
207
208
if (saddr == PN_NO_ADDR) {
209
/* Fallback to another device */
210
struct net_device *def_dev;
211
212
def_dev = phonet_device_get(dev_net(dev));
213
if (def_dev) {
214
if (def_dev != dev)
215
saddr = phonet_address_get(def_dev, daddr);
216
dev_put(def_dev);
217
}
218
}
219
return saddr;
220
}
221
222
int phonet_address_lookup(struct net *net, u8 addr)
223
{
224
struct phonet_device_list *pndevs = phonet_device_list(net);
225
struct phonet_device *pnd;
226
int err = -EADDRNOTAVAIL;
227
228
rcu_read_lock();
229
list_for_each_entry_rcu(pnd, &pndevs->list, list) {
230
/* Don't allow unregistering devices! */
231
if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
232
((pnd->netdev->flags & IFF_UP)) != IFF_UP)
233
continue;
234
235
if (test_bit(addr >> 2, pnd->addrs)) {
236
err = 0;
237
goto found;
238
}
239
}
240
found:
241
rcu_read_unlock();
242
return err;
243
}
244
245
/* automatically configure a Phonet device, if supported */
246
static int phonet_device_autoconf(struct net_device *dev)
247
{
248
struct if_phonet_req req;
249
int ret;
250
251
if (!dev->netdev_ops->ndo_do_ioctl)
252
return -EOPNOTSUPP;
253
254
ret = dev->netdev_ops->ndo_do_ioctl(dev, (struct ifreq *)&req,
255
SIOCPNGAUTOCONF);
256
if (ret < 0)
257
return ret;
258
259
ASSERT_RTNL();
260
ret = phonet_address_add(dev, req.ifr_phonet_autoconf.device);
261
if (ret)
262
return ret;
263
phonet_address_notify(RTM_NEWADDR, dev,
264
req.ifr_phonet_autoconf.device);
265
return 0;
266
}
267
268
static void phonet_route_autodel(struct net_device *dev)
269
{
270
struct phonet_net *pnn = phonet_pernet(dev_net(dev));
271
unsigned i;
272
DECLARE_BITMAP(deleted, 64);
273
274
/* Remove left-over Phonet routes */
275
bitmap_zero(deleted, 64);
276
mutex_lock(&pnn->routes.lock);
277
for (i = 0; i < 64; i++)
278
if (dev == pnn->routes.table[i]) {
279
rcu_assign_pointer(pnn->routes.table[i], NULL);
280
set_bit(i, deleted);
281
}
282
mutex_unlock(&pnn->routes.lock);
283
284
if (bitmap_empty(deleted, 64))
285
return; /* short-circuit RCU */
286
synchronize_rcu();
287
for_each_set_bit(i, deleted, 64) {
288
rtm_phonet_notify(RTM_DELROUTE, dev, i);
289
dev_put(dev);
290
}
291
}
292
293
/* notify Phonet of device events */
294
static int phonet_device_notify(struct notifier_block *me, unsigned long what,
295
void *arg)
296
{
297
struct net_device *dev = arg;
298
299
switch (what) {
300
case NETDEV_REGISTER:
301
if (dev->type == ARPHRD_PHONET)
302
phonet_device_autoconf(dev);
303
break;
304
case NETDEV_UNREGISTER:
305
phonet_device_destroy(dev);
306
phonet_route_autodel(dev);
307
break;
308
}
309
return 0;
310
311
}
312
313
static struct notifier_block phonet_device_notifier = {
314
.notifier_call = phonet_device_notify,
315
.priority = 0,
316
};
317
318
/* Per-namespace Phonet devices handling */
319
static int __net_init phonet_init_net(struct net *net)
320
{
321
struct phonet_net *pnn = phonet_pernet(net);
322
323
if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops))
324
return -ENOMEM;
325
326
INIT_LIST_HEAD(&pnn->pndevs.list);
327
mutex_init(&pnn->pndevs.lock);
328
mutex_init(&pnn->routes.lock);
329
return 0;
330
}
331
332
static void __net_exit phonet_exit_net(struct net *net)
333
{
334
struct phonet_net *pnn = phonet_pernet(net);
335
struct net_device *dev;
336
unsigned i;
337
338
rtnl_lock();
339
for_each_netdev(net, dev)
340
phonet_device_destroy(dev);
341
342
for (i = 0; i < 64; i++) {
343
dev = pnn->routes.table[i];
344
if (dev) {
345
rtm_phonet_notify(RTM_DELROUTE, dev, i);
346
dev_put(dev);
347
}
348
}
349
rtnl_unlock();
350
351
proc_net_remove(net, "phonet");
352
}
353
354
static struct pernet_operations phonet_net_ops = {
355
.init = phonet_init_net,
356
.exit = phonet_exit_net,
357
.id = &phonet_net_id,
358
.size = sizeof(struct phonet_net),
359
};
360
361
/* Initialize Phonet devices list */
362
int __init phonet_device_init(void)
363
{
364
int err = register_pernet_device(&phonet_net_ops);
365
if (err)
366
return err;
367
368
proc_net_fops_create(&init_net, "pnresource", 0, &pn_res_seq_fops);
369
register_netdevice_notifier(&phonet_device_notifier);
370
err = phonet_netlink_register();
371
if (err)
372
phonet_device_exit();
373
return err;
374
}
375
376
void phonet_device_exit(void)
377
{
378
rtnl_unregister_all(PF_PHONET);
379
unregister_netdevice_notifier(&phonet_device_notifier);
380
unregister_pernet_device(&phonet_net_ops);
381
proc_net_remove(&init_net, "pnresource");
382
}
383
384
int phonet_route_add(struct net_device *dev, u8 daddr)
385
{
386
struct phonet_net *pnn = phonet_pernet(dev_net(dev));
387
struct phonet_routes *routes = &pnn->routes;
388
int err = -EEXIST;
389
390
daddr = daddr >> 2;
391
mutex_lock(&routes->lock);
392
if (routes->table[daddr] == NULL) {
393
rcu_assign_pointer(routes->table[daddr], dev);
394
dev_hold(dev);
395
err = 0;
396
}
397
mutex_unlock(&routes->lock);
398
return err;
399
}
400
401
int phonet_route_del(struct net_device *dev, u8 daddr)
402
{
403
struct phonet_net *pnn = phonet_pernet(dev_net(dev));
404
struct phonet_routes *routes = &pnn->routes;
405
406
daddr = daddr >> 2;
407
mutex_lock(&routes->lock);
408
if (dev == routes->table[daddr])
409
rcu_assign_pointer(routes->table[daddr], NULL);
410
else
411
dev = NULL;
412
mutex_unlock(&routes->lock);
413
414
if (!dev)
415
return -ENOENT;
416
synchronize_rcu();
417
dev_put(dev);
418
return 0;
419
}
420
421
struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr)
422
{
423
struct phonet_net *pnn = phonet_pernet(net);
424
struct phonet_routes *routes = &pnn->routes;
425
struct net_device *dev;
426
427
daddr >>= 2;
428
dev = rcu_dereference(routes->table[daddr]);
429
return dev;
430
}
431
432
struct net_device *phonet_route_output(struct net *net, u8 daddr)
433
{
434
struct phonet_net *pnn = phonet_pernet(net);
435
struct phonet_routes *routes = &pnn->routes;
436
struct net_device *dev;
437
438
daddr >>= 2;
439
rcu_read_lock();
440
dev = rcu_dereference(routes->table[daddr]);
441
if (dev)
442
dev_hold(dev);
443
rcu_read_unlock();
444
445
if (!dev)
446
dev = phonet_device_get(net); /* Default route */
447
return dev;
448
}
449
450