patch-2_6_7-vs1_9_1_12
[linux-2.6.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 #include <linux/config.h> /* for CONFIG_DLCI_COUNT */
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/types.h>
35 #include <linux/fcntl.h>
36 #include <linux/interrupt.h>
37 #include <linux/ptrace.h>
38 #include <linux/ioport.h>
39 #include <linux/in.h>
40 #include <linux/init.h>
41 #include <linux/slab.h>
42 #include <linux/string.h>
43 #include <linux/errno.h>
44 #include <linux/netdevice.h>
45 #include <linux/skbuff.h>
46 #include <linux/if_arp.h>
47 #include <linux/if_frad.h>
48
49 #include <net/sock.h>
50
51 #include <asm/system.h>
52 #include <asm/bitops.h>
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, void *daddr, void *saddr, 
71                            unsigned len)
72 {
73         struct frhdr            hdr;
74         struct dlci_local       *dlp;
75         unsigned int            hlen;
76         char                    *dest;
77
78         dlp = dev->priv;
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 = dev->priv;
115         if (!pskb_may_pull(skb, sizeof(*hdr))) {
116                 printk(KERN_NOTICE "%s: invalid data no header\n",
117                        dev->name);
118                 dlp->stats.rx_errors++;
119                 kfree_skb(skb);
120                 return;
121         }
122
123         hdr = (struct frhdr *) skb->data;
124         process = 0;
125         header = 0;
126         skb->dev = dev;
127
128         if (hdr->control != FRAD_I_UI)
129         {
130                 printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
131                 dlp->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                                         printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
140                                         dlp->stats.rx_errors++;
141                                         break;
142                                 }
143          
144                                 if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
145                                 {
146                                         printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
147                                         dlp->stats.rx_errors++;
148                                         break;
149                                 }
150
151                                 /* at this point, it's an EtherType frame */
152                                 header = sizeof(struct frhdr);
153                                 /* Already in network order ! */
154                                 skb->protocol = hdr->PID;
155                                 process = 1;
156                                 break;
157
158                         case FRAD_P_IP:
159                                 header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
160                                 skb->protocol = htons(ETH_P_IP);
161                                 process = 1;
162                                 break;
163
164                         case FRAD_P_SNAP:
165                         case FRAD_P_Q933:
166                         case FRAD_P_CLNP:
167                                 printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
168                                 dlp->stats.rx_errors++;
169                                 break;
170
171                         default:
172                                 printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
173                                 dlp->stats.rx_errors++;
174                                 break;                          
175                 }
176
177         if (process)
178         {
179                 /* we've set up the protocol, so discard the header */
180                 skb->mac.raw = skb->data; 
181                 skb_pull(skb, header);
182                 dlp->stats.rx_bytes += skb->len;
183                 netif_rx(skb);
184                 dlp->stats.rx_packets++;
185                 dev->last_rx = jiffies;
186         }
187         else
188                 dev_kfree_skb(skb);
189 }
190
191 static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
192 {
193         struct dlci_local *dlp;
194         int                                     ret;
195
196         ret = 0;
197
198         if (!skb || !dev)
199                 return(0);
200
201         dlp = dev->priv;
202
203         netif_stop_queue(dev);
204         
205         ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
206         switch (ret)
207         {
208                 case DLCI_RET_OK:
209                         dlp->stats.tx_packets++;
210                         ret = 0;
211                         break;
212                         case DLCI_RET_ERR:
213                         dlp->stats.tx_errors++;
214                         ret = 0;
215                         break;
216                         case DLCI_RET_DROP:
217                         dlp->stats.tx_dropped++;
218                         ret = 1;
219                         break;
220         }
221         /* Alan Cox recommends always returning 0, and always freeing the packet */
222         /* experience suggest a slightly more conservative approach */
223
224         if (!ret)
225         {
226                 dev_kfree_skb(skb);
227                 netif_wake_queue(dev);
228         }
229         return(ret);
230 }
231
232 static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get)
233 {
234         struct dlci_conf        config;
235         struct dlci_local       *dlp;
236         struct frad_local       *flp;
237         int                     err;
238
239         dlp = dev->priv;
240
241         flp = dlp->slave->priv;
242
243         if (!get)
244         {
245                 if(copy_from_user(&config, conf, sizeof(struct dlci_conf)))
246                         return -EFAULT;
247                 if (config.flags & ~DLCI_VALID_FLAGS)
248                         return(-EINVAL);
249                 memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
250                 dlp->configured = 1;
251         }
252
253         err = (*flp->dlci_conf)(dlp->slave, dev, get);
254         if (err)
255                 return(err);
256
257         if (get)
258         {
259                 if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
260                         return -EFAULT;
261         }
262
263         return(0);
264 }
265
266 static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
267 {
268         struct dlci_local *dlp;
269
270         if (!capable(CAP_NET_ADMIN))
271                 return(-EPERM);
272
273         dlp = dev->priv;
274
275         switch(cmd)
276         {
277                 case DLCI_GET_SLAVE:
278                         if (!*(short *)(dev->dev_addr))
279                                 return(-EINVAL);
280
281                         strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
282                         break;
283
284                 case DLCI_GET_CONF:
285                 case DLCI_SET_CONF:
286                         if (!*(short *)(dev->dev_addr))
287                                 return(-EINVAL);
288
289                         return(dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF));
290                         break;
291
292                 default: 
293                         return(-EOPNOTSUPP);
294         }
295         return(0);
296 }
297
298 static int dlci_change_mtu(struct net_device *dev, int new_mtu)
299 {
300         struct dlci_local *dlp;
301
302         dlp = dev->priv;
303
304         return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
305 }
306
307 static int dlci_open(struct net_device *dev)
308 {
309         struct dlci_local       *dlp;
310         struct frad_local       *flp;
311         int                     err;
312
313         dlp = dev->priv;
314
315         if (!*(short *)(dev->dev_addr))
316                 return(-EINVAL);
317
318         if (!netif_running(dlp->slave))
319                 return(-ENOTCONN);
320
321         flp = dlp->slave->priv;
322         err = (*flp->activate)(dlp->slave, dev);
323         if (err)
324                 return(err);
325
326         netif_start_queue(dev);
327
328         return 0;
329 }
330
331 static int dlci_close(struct net_device *dev)
332 {
333         struct dlci_local       *dlp;
334         struct frad_local       *flp;
335         int                     err;
336
337         netif_stop_queue(dev);
338
339         dlp = dev->priv;
340
341         flp = dlp->slave->priv;
342         err = (*flp->deactivate)(dlp->slave, dev);
343
344         return 0;
345 }
346
347 static struct net_device_stats *dlci_get_stats(struct net_device *dev)
348 {
349         struct dlci_local *dlp;
350
351         dlp = dev->priv;
352
353         return(&dlp->stats);
354 }
355
356 static int dlci_add(struct dlci_add *dlci)
357 {
358         struct net_device       *master, *slave;
359         struct dlci_local       *dlp;
360         struct frad_local       *flp;
361         int                     err = -EINVAL;
362
363
364         /* validate slave device */
365         slave = dev_get_by_name(dlci->devname);
366         if (!slave)
367                 return -ENODEV;
368
369         if (slave->type != ARPHRD_FRAD || slave->priv == NULL)
370                 goto err1;
371
372         /* create device name */
373         master = alloc_netdev( sizeof(struct dlci_local), "dlci%d",
374                               dlci_setup);
375         if (!master) {
376                 err = -ENOMEM;
377                 goto err1;
378         }
379
380         /* make sure same slave not already registered */
381         rtnl_lock();
382         list_for_each_entry(dlp, &dlci_devs, list) {
383                 if (dlp->slave == slave) {
384                         err = -EBUSY;
385                         goto err2;
386                 }
387         }
388
389         err = dev_alloc_name(master, master->name);
390         if (err < 0)
391                 goto err2;
392
393         *(short *)(master->dev_addr) = dlci->dlci;
394
395         dlp = (struct dlci_local *) master->priv;
396         dlp->slave = slave;
397         dlp->master = master;
398
399         flp = slave->priv;
400         err = (*flp->assoc)(slave, master);
401         if (err < 0)
402                 goto err2;
403
404         err = register_netdevice(master);
405         if (err < 0) 
406                 goto err2;
407
408         strcpy(dlci->devname, master->name);
409
410         list_add(&dlp->list, &dlci_devs);
411         rtnl_unlock();
412
413         return(0);
414
415  err2:
416         rtnl_unlock();
417         free_netdev(master);
418  err1:
419         dev_put(slave);
420         return(err);
421 }
422
423 static int dlci_del(struct dlci_add *dlci)
424 {
425         struct dlci_local       *dlp;
426         struct frad_local       *flp;
427         struct net_device       *master, *slave;
428         int                     err;
429
430         /* validate slave device */
431         master = __dev_get_by_name(dlci->devname);
432         if (!master)
433                 return(-ENODEV);
434
435         if (netif_running(master)) {
436                 return(-EBUSY);
437         }
438
439         dlp = master->priv;
440         slave = dlp->slave;
441         flp = slave->priv;
442
443         rtnl_lock();
444         err = (*flp->deassoc)(slave, master);
445         if (!err) {
446                 list_del(&dlp->list);
447
448                 unregister_netdevice(master);
449
450                 dev_put(slave);
451         }
452         rtnl_unlock();
453
454         return(err);
455 }
456
457 static int dlci_ioctl(unsigned int cmd, void __user *arg)
458 {
459         struct dlci_add add;
460         int err;
461         
462         if (!capable(CAP_NET_ADMIN))
463                 return(-EPERM);
464
465         if(copy_from_user(&add, arg, sizeof(struct dlci_add)))
466                 return -EFAULT;
467
468         switch (cmd)
469         {
470                 case SIOCADDDLCI:
471                         err = dlci_add(&add);
472
473                         if (!err)
474                                 if(copy_to_user(arg, &add, sizeof(struct dlci_add)))
475                                         return -EFAULT;
476                         break;
477
478                 case SIOCDELDLCI:
479                         err = dlci_del(&add);
480                         break;
481
482                 default:
483                         err = -EINVAL;
484         }
485
486         return(err);
487 }
488
489 static void dlci_setup(struct net_device *dev)
490 {
491         struct dlci_local *dlp = dev->priv;
492
493         dev->flags              = 0;
494         dev->open               = dlci_open;
495         dev->stop               = dlci_close;
496         dev->do_ioctl           = dlci_dev_ioctl;
497         dev->hard_start_xmit    = dlci_transmit;
498         dev->hard_header        = dlci_header;
499         dev->get_stats          = dlci_get_stats;
500         dev->change_mtu         = dlci_change_mtu;
501         dev->destructor         = free_netdev;
502
503         dlp->receive            = dlci_receive;
504
505         dev->type               = ARPHRD_DLCI;
506         dev->hard_header_len    = sizeof(struct frhdr);
507         dev->addr_len           = sizeof(short);
508
509 }
510
511 /* if slave is unregistering, then cleanup master */
512 static int dlci_dev_event(struct notifier_block *unused,
513                           unsigned long event, void *ptr)
514 {
515         struct net_device *dev = (struct net_device *) ptr;
516
517         if (event == NETDEV_UNREGISTER) {
518                 struct dlci_local *dlp;
519
520                 list_for_each_entry(dlp, &dlci_devs, list) {
521                         if (dlp->slave == dev) {
522                                 list_del(&dlp->list);
523                                 unregister_netdevice(dlp->master);
524                                 dev_put(dlp->slave);
525                                 break;
526                         }
527                 }
528         }
529         return NOTIFY_DONE;
530 }
531
532 static struct notifier_block dlci_notifier = {
533         .notifier_call = dlci_dev_event,
534 };
535
536 static int __init init_dlci(void)
537 {
538         dlci_ioctl_set(dlci_ioctl);
539         register_netdevice_notifier(&dlci_notifier);
540
541         printk("%s.\n", version);
542
543         return 0;
544 }
545
546 static void __exit dlci_exit(void)
547 {
548         struct dlci_local       *dlp, *nxt;
549         
550         dlci_ioctl_set(NULL);
551         unregister_netdevice_notifier(&dlci_notifier);
552
553         rtnl_lock();
554         list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
555                 unregister_netdevice(dlp->master);
556                 dev_put(dlp->slave);
557         }
558         rtnl_unlock();
559 }
560
561 module_init(init_dlci);
562 module_exit(dlci_exit);
563
564 MODULE_AUTHOR("Mike McLagan");
565 MODULE_DESCRIPTION("Frame Relay DLCI layer");
566 MODULE_LICENSE("GPL");