1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
32
33#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/types.h>
36#include <linux/fcntl.h>
37#include <linux/interrupt.h>
38#include <linux/ptrace.h>
39#include <linux/ioport.h>
40#include <linux/in.h>
41#include <linux/init.h>
42#include <linux/slab.h>
43#include <linux/string.h>
44#include <linux/errno.h>
45#include <linux/netdevice.h>
46#include <linux/skbuff.h>
47#include <linux/if_arp.h>
48#include <linux/if_frad.h>
49#include <linux/bitops.h>
50
51#include <net/sock.h>
52
53#include <asm/io.h>
54#include <asm/dma.h>
55#include <asm/uaccess.h>
56
57static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
58
59static LIST_HEAD(dlci_devs);
60
61static void dlci_setup(struct net_device *);
62
63
64
65
66
67
68
69static int dlci_header(struct sk_buff *skb, struct net_device *dev,
70 unsigned short type, const void *daddr,
71 const void *saddr, unsigned len)
72{
73 struct frhdr hdr;
74 struct dlci_local *dlp;
75 unsigned int hlen;
76 char *dest;
77
78 dlp = netdev_priv(dev);
79
80 hdr.control = FRAD_I_UI;
81 switch (type)
82 {
83 case ETH_P_IP:
84 hdr.IP_NLPID = FRAD_P_IP;
85 hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
86 break;
87
88
89
90 default:
91 hdr.pad = FRAD_P_PADDING;
92 hdr.NLPID = FRAD_P_SNAP;
93 memset(hdr.OUI, 0, sizeof(hdr.OUI));
94 hdr.PID = htons(type);
95 hlen = sizeof(hdr);
96 break;
97 }
98
99 dest = skb_push(skb, hlen);
100 if (!dest)
101 return 0;
102
103 memcpy(dest, &hdr, hlen);
104
105 return hlen;
106}
107
108static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
109{
110 struct dlci_local *dlp;
111 struct frhdr *hdr;
112 int process, header;
113
114 dlp = netdev_priv(dev);
115 if (!pskb_may_pull(skb, sizeof(*hdr))) {
116 netdev_notice(dev, "invalid data no header\n");
117 dev->stats.rx_errors++;
118 kfree_skb(skb);
119 return;
120 }
121
122 hdr = (struct frhdr *) skb->data;
123 process = 0;
124 header = 0;
125 skb->dev = dev;
126
127 if (hdr->control != FRAD_I_UI)
128 {
129 netdev_notice(dev, "Invalid header flag 0x%02X\n",
130 hdr->control);
131 dev->stats.rx_errors++;
132 }
133 else
134 switch (hdr->IP_NLPID)
135 {
136 case FRAD_P_PADDING:
137 if (hdr->NLPID != FRAD_P_SNAP)
138 {
139 netdev_notice(dev, "Unsupported NLPID 0x%02X\n",
140 hdr->NLPID);
141 dev->stats.rx_errors++;
142 break;
143 }
144
145 if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
146 {
147 netdev_notice(dev, "Unsupported organizationally unique identifier 0x%02X-%02X-%02X\n",
148 hdr->OUI[0],
149 hdr->OUI[1],
150 hdr->OUI[2]);
151 dev->stats.rx_errors++;
152 break;
153 }
154
155
156 header = sizeof(struct frhdr);
157
158 skb->protocol = hdr->PID;
159 process = 1;
160 break;
161
162 case FRAD_P_IP:
163 header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
164 skb->protocol = htons(ETH_P_IP);
165 process = 1;
166 break;
167
168 case FRAD_P_SNAP:
169 case FRAD_P_Q933:
170 case FRAD_P_CLNP:
171 netdev_notice(dev, "Unsupported NLPID 0x%02X\n",
172 hdr->pad);
173 dev->stats.rx_errors++;
174 break;
175
176 default:
177 netdev_notice(dev, "Invalid pad byte 0x%02X\n",
178 hdr->pad);
179 dev->stats.rx_errors++;
180 break;
181 }
182
183 if (process)
184 {
185
186 skb_reset_mac_header(skb);
187 skb_pull(skb, header);
188 dev->stats.rx_bytes += skb->len;
189 netif_rx(skb);
190 dev->stats.rx_packets++;
191 }
192 else
193 dev_kfree_skb(skb);
194}
195
196static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev)
197{
198 struct dlci_local *dlp = netdev_priv(dev);
199
200 if (skb) {
201 struct netdev_queue *txq = skb_get_tx_queue(dev, skb);
202 netdev_start_xmit(skb, dlp->slave, txq, false);
203 }
204 return NETDEV_TX_OK;
205}
206
207static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get)
208{
209 struct dlci_conf config;
210 struct dlci_local *dlp;
211 struct frad_local *flp;
212 int err;
213
214 dlp = netdev_priv(dev);
215
216 flp = netdev_priv(dlp->slave);
217
218 if (!get)
219 {
220 if (copy_from_user(&config, conf, sizeof(struct dlci_conf)))
221 return -EFAULT;
222 if (config.flags & ~DLCI_VALID_FLAGS)
223 return -EINVAL;
224 memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
225 dlp->configured = 1;
226 }
227
228 err = (*flp->dlci_conf)(dlp->slave, dev, get);
229 if (err)
230 return err;
231
232 if (get)
233 {
234 if (copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
235 return -EFAULT;
236 }
237
238 return 0;
239}
240
241static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
242{
243 struct dlci_local *dlp;
244
245 if (!capable(CAP_NET_ADMIN))
246 return -EPERM;
247
248 dlp = netdev_priv(dev);
249
250 switch (cmd)
251 {
252 case DLCI_GET_SLAVE:
253 if (!*(short *)(dev->dev_addr))
254 return -EINVAL;
255
256 strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
257 break;
258
259 case DLCI_GET_CONF:
260 case DLCI_SET_CONF:
261 if (!*(short *)(dev->dev_addr))
262 return -EINVAL;
263
264 return dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF);
265 break;
266
267 default:
268 return -EOPNOTSUPP;
269 }
270 return 0;
271}
272
273static int dlci_change_mtu(struct net_device *dev, int new_mtu)
274{
275 struct dlci_local *dlp = netdev_priv(dev);
276
277 return dev_set_mtu(dlp->slave, new_mtu);
278}
279
280static int dlci_open(struct net_device *dev)
281{
282 struct dlci_local *dlp;
283 struct frad_local *flp;
284 int err;
285
286 dlp = netdev_priv(dev);
287
288 if (!*(short *)(dev->dev_addr))
289 return -EINVAL;
290
291 if (!netif_running(dlp->slave))
292 return -ENOTCONN;
293
294 flp = netdev_priv(dlp->slave);
295 err = (*flp->activate)(dlp->slave, dev);
296 if (err)
297 return err;
298
299 netif_start_queue(dev);
300
301 return 0;
302}
303
304static int dlci_close(struct net_device *dev)
305{
306 struct dlci_local *dlp;
307 struct frad_local *flp;
308 int err;
309
310 netif_stop_queue(dev);
311
312 dlp = netdev_priv(dev);
313
314 flp = netdev_priv(dlp->slave);
315 err = (*flp->deactivate)(dlp->slave, dev);
316
317 return 0;
318}
319
320static int dlci_add(struct dlci_add *dlci)
321{
322 struct net_device *master, *slave;
323 struct dlci_local *dlp;
324 struct frad_local *flp;
325 int err = -EINVAL;
326
327
328
329 slave = dev_get_by_name(&init_net, dlci->devname);
330 if (!slave)
331 return -ENODEV;
332
333 if (slave->type != ARPHRD_FRAD || netdev_priv(slave) == NULL)
334 goto err1;
335
336
337 master = alloc_netdev( sizeof(struct dlci_local), "dlci%d",
338 dlci_setup);
339 if (!master) {
340 err = -ENOMEM;
341 goto err1;
342 }
343
344
345 rtnl_lock();
346 list_for_each_entry(dlp, &dlci_devs, list) {
347 if (dlp->slave == slave) {
348 err = -EBUSY;
349 goto err2;
350 }
351 }
352
353 *(short *)(master->dev_addr) = dlci->dlci;
354
355 dlp = netdev_priv(master);
356 dlp->slave = slave;
357 dlp->master = master;
358
359 flp = netdev_priv(slave);
360 err = (*flp->assoc)(slave, master);
361 if (err < 0)
362 goto err2;
363
364 err = register_netdevice(master);
365 if (err < 0)
366 goto err2;
367
368 strcpy(dlci->devname, master->name);
369
370 list_add(&dlp->list, &dlci_devs);
371 rtnl_unlock();
372
373 return 0;
374
375 err2:
376 rtnl_unlock();
377 free_netdev(master);
378 err1:
379 dev_put(slave);
380 return err;
381}
382
383static int dlci_del(struct dlci_add *dlci)
384{
385 struct dlci_local *dlp;
386 struct frad_local *flp;
387 struct net_device *master, *slave;
388 int err;
389 bool found = false;
390
391 rtnl_lock();
392
393
394 master = __dev_get_by_name(&init_net, dlci->devname);
395 if (!master) {
396 err = -ENODEV;
397 goto out;
398 }
399
400 list_for_each_entry(dlp, &dlci_devs, list) {
401 if (dlp->master == master) {
402 found = true;
403 break;
404 }
405 }
406 if (!found) {
407 err = -ENODEV;
408 goto out;
409 }
410
411 if (netif_running(master)) {
412 err = -EBUSY;
413 goto out;
414 }
415
416 dlp = netdev_priv(master);
417 slave = dlp->slave;
418 flp = netdev_priv(slave);
419
420 err = (*flp->deassoc)(slave, master);
421 if (!err) {
422 list_del(&dlp->list);
423
424 unregister_netdevice(master);
425
426 dev_put(slave);
427 }
428out:
429 rtnl_unlock();
430 return err;
431}
432
433static int dlci_ioctl(unsigned int cmd, void __user *arg)
434{
435 struct dlci_add add;
436 int err;
437
438 if (!capable(CAP_NET_ADMIN))
439 return -EPERM;
440
441 if (copy_from_user(&add, arg, sizeof(struct dlci_add)))
442 return -EFAULT;
443
444 switch (cmd)
445 {
446 case SIOCADDDLCI:
447 err = dlci_add(&add);
448
449 if (!err)
450 if (copy_to_user(arg, &add, sizeof(struct dlci_add)))
451 return -EFAULT;
452 break;
453
454 case SIOCDELDLCI:
455 err = dlci_del(&add);
456 break;
457
458 default:
459 err = -EINVAL;
460 }
461
462 return err;
463}
464
465static const struct header_ops dlci_header_ops = {
466 .create = dlci_header,
467};
468
469static const struct net_device_ops dlci_netdev_ops = {
470 .ndo_open = dlci_open,
471 .ndo_stop = dlci_close,
472 .ndo_do_ioctl = dlci_dev_ioctl,
473 .ndo_start_xmit = dlci_transmit,
474 .ndo_change_mtu_rh74 = dlci_change_mtu,
475};
476
477static void dlci_setup(struct net_device *dev)
478{
479 struct dlci_local *dlp = netdev_priv(dev);
480
481 dev->flags = 0;
482 dev->header_ops = &dlci_header_ops;
483 dev->netdev_ops = &dlci_netdev_ops;
484 dev->extended->needs_free_netdev = true;
485
486 dlp->receive = dlci_receive;
487
488 dev->type = ARPHRD_DLCI;
489 dev->hard_header_len = sizeof(struct frhdr);
490 dev->addr_len = sizeof(short);
491
492}
493
494
495static int dlci_dev_event(struct notifier_block *unused,
496 unsigned long event, void *ptr)
497{
498 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
499
500 if (dev_net(dev) != &init_net)
501 return NOTIFY_DONE;
502
503 if (event == NETDEV_UNREGISTER) {
504 struct dlci_local *dlp;
505
506 list_for_each_entry(dlp, &dlci_devs, list) {
507 if (dlp->slave == dev) {
508 list_del(&dlp->list);
509 unregister_netdevice(dlp->master);
510 dev_put(dlp->slave);
511 break;
512 }
513 }
514 }
515 return NOTIFY_DONE;
516}
517
518static struct notifier_block dlci_notifier = {
519 .notifier_call = dlci_dev_event,
520};
521
522static int __init init_dlci(void)
523{
524 dlci_ioctl_set(dlci_ioctl);
525 register_netdevice_notifier_rh(&dlci_notifier);
526
527 printk("%s.\n", version);
528
529 return 0;
530}
531
532static void __exit dlci_exit(void)
533{
534 struct dlci_local *dlp, *nxt;
535
536 dlci_ioctl_set(NULL);
537 unregister_netdevice_notifier_rh(&dlci_notifier);
538
539 rtnl_lock();
540 list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
541 unregister_netdevice(dlp->master);
542 dev_put(dlp->slave);
543 }
544 rtnl_unlock();
545}
546
547module_init(init_dlci);
548module_exit(dlci_exit);
549
550MODULE_AUTHOR("Mike McLagan");
551MODULE_DESCRIPTION("Frame Relay DLCI layer");
552MODULE_LICENSE("GPL");
553