Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[pandora-kernel.git] / drivers / net / wan / dlci.c
1 /*
2  * DLCI         Implementation of Frame Relay protocol for Linux, according to
3  *              RFC 1490.  This generic device provides en/decapsulation for an
4  *              underlying hardware driver.  Routes & IPs are assigned to these
5  *              interfaces.  Requires 'dlcicfg' program to create usable 
6  *              interfaces, the initial one, 'dlci' is for IOCTL use only.
7  *
8  * Version:     @(#)dlci.c      0.35    4 Jan 1997
9  *
10  * Author:      Mike McLagan <mike.mclagan@linux.org>
11  *
12  * Changes:
13  *
14  *              0.15    Mike Mclagan    Packet freeing, bug in kmalloc call
15  *                                      DLCI_RET handling
16  *              0.20    Mike McLagan    More conservative on which packets
17  *                                      are returned for retry and which are
18  *                                      are dropped.  If DLCI_RET_DROP is
19  *                                      returned from the FRAD, the packet is
20  *                                      sent back to Linux for re-transmission
21  *              0.25    Mike McLagan    Converted to use SIOC IOCTL calls
22  *              0.30    Jim Freeman     Fixed to allow IPX traffic
23  *              0.35    Michael Elizabeth       Fixed incorrect memcpy_fromfs
24  *
25  *              This program is free software; you can redistribute it and/or
26  *              modify it under the terms of the GNU General Public License
27  *              as published by the Free Software Foundation; either version
28  *              2 of the License, or (at your option) any later version.
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
57 static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
58
59 static LIST_HEAD(dlci_devs);
60
61 static void dlci_setup(struct net_device *);
62
63 /* 
64  * these encapsulate the RFC 1490 requirements as well as 
65  * deal with packet transmission and reception, working with
66  * the upper network layers 
67  */
68
69 static 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                 /* feel free to add other types, if necessary */
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
108 static 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                                 /* at this point, it's an EtherType frame */
156                                 header = sizeof(struct frhdr);
157                                 /* Already in network order ! */
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                 /* we've set up the protocol, so discard the header */
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
196 static 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                 dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave);
202         return NETDEV_TX_OK;
203 }
204
205 static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get)
206 {
207         struct dlci_conf        config;
208         struct dlci_local       *dlp;
209         struct frad_local       *flp;
210         int                     err;
211
212         dlp = netdev_priv(dev);
213
214         flp = netdev_priv(dlp->slave);
215
216         if (!get)
217         {
218                 if (copy_from_user(&config, conf, sizeof(struct dlci_conf)))
219                         return -EFAULT;
220                 if (config.flags & ~DLCI_VALID_FLAGS)
221                         return -EINVAL;
222                 memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
223                 dlp->configured = 1;
224         }
225
226         err = (*flp->dlci_conf)(dlp->slave, dev, get);
227         if (err)
228                 return err;
229
230         if (get)
231         {
232                 if (copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
233                         return -EFAULT;
234         }
235
236         return 0;
237 }
238
239 static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
240 {
241         struct dlci_local *dlp;
242
243         if (!capable(CAP_NET_ADMIN))
244                 return -EPERM;
245
246         dlp = netdev_priv(dev);
247
248         switch (cmd)
249         {
250                 case DLCI_GET_SLAVE:
251                         if (!*(short *)(dev->dev_addr))
252                                 return -EINVAL;
253
254                         strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
255                         break;
256
257                 case DLCI_GET_CONF:
258                 case DLCI_SET_CONF:
259                         if (!*(short *)(dev->dev_addr))
260                                 return -EINVAL;
261
262                         return dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF);
263                         break;
264
265                 default: 
266                         return -EOPNOTSUPP;
267         }
268         return 0;
269 }
270
271 static int dlci_change_mtu(struct net_device *dev, int new_mtu)
272 {
273         struct dlci_local *dlp = netdev_priv(dev);
274
275         return dev_set_mtu(dlp->slave, new_mtu);
276 }
277
278 static int dlci_open(struct net_device *dev)
279 {
280         struct dlci_local       *dlp;
281         struct frad_local       *flp;
282         int                     err;
283
284         dlp = netdev_priv(dev);
285
286         if (!*(short *)(dev->dev_addr))
287                 return -EINVAL;
288
289         if (!netif_running(dlp->slave))
290                 return -ENOTCONN;
291
292         flp = netdev_priv(dlp->slave);
293         err = (*flp->activate)(dlp->slave, dev);
294         if (err)
295                 return err;
296
297         netif_start_queue(dev);
298
299         return 0;
300 }
301
302 static int dlci_close(struct net_device *dev)
303 {
304         struct dlci_local       *dlp;
305         struct frad_local       *flp;
306         int                     err;
307
308         netif_stop_queue(dev);
309
310         dlp = netdev_priv(dev);
311
312         flp = netdev_priv(dlp->slave);
313         err = (*flp->deactivate)(dlp->slave, dev);
314
315         return 0;
316 }
317
318 static int dlci_add(struct dlci_add *dlci)
319 {
320         struct net_device       *master, *slave;
321         struct dlci_local       *dlp;
322         struct frad_local       *flp;
323         int                     err = -EINVAL;
324
325
326         /* validate slave device */
327         slave = dev_get_by_name(&init_net, dlci->devname);
328         if (!slave)
329                 return -ENODEV;
330
331         if (slave->type != ARPHRD_FRAD || netdev_priv(slave) == NULL)
332                 goto err1;
333
334         /* create device name */
335         master = alloc_netdev( sizeof(struct dlci_local), "dlci%d",
336                               dlci_setup);
337         if (!master) {
338                 err = -ENOMEM;
339                 goto err1;
340         }
341
342         /* make sure same slave not already registered */
343         rtnl_lock();
344         list_for_each_entry(dlp, &dlci_devs, list) {
345                 if (dlp->slave == slave) {
346                         err = -EBUSY;
347                         goto err2;
348                 }
349         }
350
351         *(short *)(master->dev_addr) = dlci->dlci;
352
353         dlp = netdev_priv(master);
354         dlp->slave = slave;
355         dlp->master = master;
356
357         flp = netdev_priv(slave);
358         err = (*flp->assoc)(slave, master);
359         if (err < 0)
360                 goto err2;
361
362         err = register_netdevice(master);
363         if (err < 0) 
364                 goto err2;
365
366         strcpy(dlci->devname, master->name);
367
368         list_add(&dlp->list, &dlci_devs);
369         rtnl_unlock();
370
371         return 0;
372
373  err2:
374         rtnl_unlock();
375         free_netdev(master);
376  err1:
377         dev_put(slave);
378         return err;
379 }
380
381 static int dlci_del(struct dlci_add *dlci)
382 {
383         struct dlci_local       *dlp;
384         struct frad_local       *flp;
385         struct net_device       *master, *slave;
386         int                     err;
387
388         /* validate slave device */
389         master = __dev_get_by_name(&init_net, dlci->devname);
390         if (!master)
391                 return -ENODEV;
392
393         if (netif_running(master)) {
394                 return -EBUSY;
395         }
396
397         dlp = netdev_priv(master);
398         slave = dlp->slave;
399         flp = netdev_priv(slave);
400
401         rtnl_lock();
402         err = (*flp->deassoc)(slave, master);
403         if (!err) {
404                 list_del(&dlp->list);
405
406                 unregister_netdevice(master);
407
408                 dev_put(slave);
409         }
410         rtnl_unlock();
411
412         return err;
413 }
414
415 static int dlci_ioctl(unsigned int cmd, void __user *arg)
416 {
417         struct dlci_add add;
418         int err;
419         
420         if (!capable(CAP_NET_ADMIN))
421                 return -EPERM;
422
423         if (copy_from_user(&add, arg, sizeof(struct dlci_add)))
424                 return -EFAULT;
425
426         switch (cmd)
427         {
428                 case SIOCADDDLCI:
429                         err = dlci_add(&add);
430
431                         if (!err)
432                                 if (copy_to_user(arg, &add, sizeof(struct dlci_add)))
433                                         return -EFAULT;
434                         break;
435
436                 case SIOCDELDLCI:
437                         err = dlci_del(&add);
438                         break;
439
440                 default:
441                         err = -EINVAL;
442         }
443
444         return err;
445 }
446
447 static const struct header_ops dlci_header_ops = {
448         .create = dlci_header,
449 };
450
451 static const struct net_device_ops dlci_netdev_ops = {
452         .ndo_open       = dlci_open,
453         .ndo_stop       = dlci_close,
454         .ndo_do_ioctl   = dlci_dev_ioctl,
455         .ndo_start_xmit = dlci_transmit,
456         .ndo_change_mtu = dlci_change_mtu,
457 };
458
459 static void dlci_setup(struct net_device *dev)
460 {
461         struct dlci_local *dlp = netdev_priv(dev);
462
463         dev->flags              = 0;
464         dev->header_ops         = &dlci_header_ops;
465         dev->netdev_ops         = &dlci_netdev_ops;
466         dev->destructor         = free_netdev;
467
468         dlp->receive            = dlci_receive;
469
470         dev->type               = ARPHRD_DLCI;
471         dev->hard_header_len    = sizeof(struct frhdr);
472         dev->addr_len           = sizeof(short);
473
474 }
475
476 /* if slave is unregistering, then cleanup master */
477 static int dlci_dev_event(struct notifier_block *unused,
478                           unsigned long event, void *ptr)
479 {
480         struct net_device *dev = (struct net_device *) ptr;
481
482         if (dev_net(dev) != &init_net)
483                 return NOTIFY_DONE;
484
485         if (event == NETDEV_UNREGISTER) {
486                 struct dlci_local *dlp;
487
488                 list_for_each_entry(dlp, &dlci_devs, list) {
489                         if (dlp->slave == dev) {
490                                 list_del(&dlp->list);
491                                 unregister_netdevice(dlp->master);
492                                 dev_put(dlp->slave);
493                                 break;
494                         }
495                 }
496         }
497         return NOTIFY_DONE;
498 }
499
500 static struct notifier_block dlci_notifier = {
501         .notifier_call = dlci_dev_event,
502 };
503
504 static int __init init_dlci(void)
505 {
506         dlci_ioctl_set(dlci_ioctl);
507         register_netdevice_notifier(&dlci_notifier);
508
509         printk("%s.\n", version);
510
511         return 0;
512 }
513
514 static void __exit dlci_exit(void)
515 {
516         struct dlci_local       *dlp, *nxt;
517         
518         dlci_ioctl_set(NULL);
519         unregister_netdevice_notifier(&dlci_notifier);
520
521         rtnl_lock();
522         list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
523                 unregister_netdevice(dlp->master);
524                 dev_put(dlp->slave);
525         }
526         rtnl_unlock();
527 }
528
529 module_init(init_dlci);
530 module_exit(dlci_exit);
531
532 MODULE_AUTHOR("Mike McLagan");
533 MODULE_DESCRIPTION("Frame Relay DLCI layer");
534 MODULE_LICENSE("GPL");