import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / net / 8021q / vlan.c
1 /*
2  * INET         802.1Q VLAN
3  *              Ethernet-type device handling.
4  *
5  * Authors:     Ben Greear <greearb@candelatech.com>
6  *              Please send support related email to: vlan@scry.wanfear.com
7  *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
8  * 
9  * Fixes:
10  *              Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
11  *              Add HW acceleration hooks - David S. Miller <davem@redhat.com>;
12  *              Correct all the locking - David S. Miller <davem@redhat.com>;
13  *              Use hash table for VLAN groups - David S. Miller <davem@redhat.com>
14  *
15  *              This program is free software; you can redistribute it and/or
16  *              modify it under the terms of the GNU General Public License
17  *              as published by the Free Software Foundation; either version
18  *              2 of the License, or (at your option) any later version.
19  */
20
21 #include <asm/uaccess.h> /* for copy_from_user */
22 #include <linux/module.h>
23 #include <linux/netdevice.h>
24 #include <linux/skbuff.h>
25 #include <net/datalink.h>
26 #include <linux/mm.h>
27 #include <linux/in.h>
28 #include <linux/init.h>
29 #include <net/p8022.h>
30 #include <net/arp.h>
31 #include <linux/rtnetlink.h>
32 #include <linux/brlock.h>
33 #include <linux/notifier.h>
34
35 #include <linux/if_vlan.h>
36 #include "vlan.h"
37 #include "vlanproc.h"
38
39 /* Global VLAN variables */
40
41 /* Our listing of VLAN group(s) */
42 struct vlan_group *vlan_group_hash[VLAN_GRP_HASH_SIZE];
43 spinlock_t vlan_group_lock = SPIN_LOCK_UNLOCKED;
44 #define vlan_grp_hashfn(IDX)    ((((IDX) >> VLAN_GRP_HASH_SHIFT) ^ (IDX)) & VLAN_GRP_HASH_MASK)
45
46 static char vlan_fullname[] = "802.1Q VLAN Support";
47 static unsigned int vlan_version = 1;
48 static unsigned int vlan_release = 8;
49 static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
50 static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
51
52 static int vlan_device_event(struct notifier_block *, unsigned long, void *);
53
54 struct notifier_block vlan_notifier_block = {
55         notifier_call: vlan_device_event,
56 };
57
58 /* These may be changed at run-time through IOCTLs */
59
60 /* Determines interface naming scheme. */
61 unsigned short vlan_name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
62
63 /* DO reorder the header by default */
64 unsigned short vlan_default_dev_flags = 1;
65
66 static struct packet_type vlan_packet_type = {
67         type: __constant_htons(ETH_P_8021Q),
68         dev:  NULL,
69         func: vlan_skb_recv, /* VLAN receive method */
70         data: (void *)(-1),  /* Set here '(void *)1' when this code can SHARE SKBs */
71         next: NULL
72 };
73
74 /* End of global variables definitions. */
75
76 /*
77  * Function vlan_proto_init (pro)
78  *
79  *    Initialize VLAN protocol layer, 
80  *
81  */
82 static int __init vlan_proto_init(void)
83 {
84         int err;
85
86         printk(VLAN_INF "%s v%u.%u %s\n",
87                vlan_fullname, vlan_version, vlan_release, vlan_copyright);
88         printk(VLAN_INF "All bugs added by %s\n",
89                vlan_buggyright);
90
91         /* proc file system initialization */
92         err = vlan_proc_init();
93         if (err < 0) {
94                 printk(KERN_ERR 
95                        "%s %s: can't create entry in proc filesystem!\n",
96                        __FUNCTION__, VLAN_NAME);
97                 return 1;
98         }
99
100         dev_add_pack(&vlan_packet_type);
101
102         /* Register us to receive netdevice events */
103         register_netdevice_notifier(&vlan_notifier_block);
104
105         vlan_ioctl_hook = vlan_ioctl_handler;
106
107         return 0;
108 }
109
110 /*
111  *     Module 'remove' entry point.
112  *     o delete /proc/net/router directory and static entries.
113  */ 
114 static void __exit vlan_cleanup_module(void)
115 {
116         int i;
117
118         /* This table must be empty if there are no module
119          * references left.
120          */
121         for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) {
122                 if (vlan_group_hash[i] != NULL)
123                         BUG();
124         }
125
126         /* Un-register us from receiving netdevice events */
127         unregister_netdevice_notifier(&vlan_notifier_block);
128
129         dev_remove_pack(&vlan_packet_type);
130         vlan_proc_cleanup();
131         vlan_ioctl_hook = NULL;
132 }
133
134 module_init(vlan_proto_init);
135 module_exit(vlan_cleanup_module);
136
137 /* Must be invoked with vlan_group_lock held. */
138 static struct vlan_group *__vlan_find_group(int real_dev_ifindex)
139 {
140         struct vlan_group *grp;
141
142         for (grp = vlan_group_hash[vlan_grp_hashfn(real_dev_ifindex)];
143              grp != NULL;
144              grp = grp->next) {
145                 if (grp->real_dev_ifindex == real_dev_ifindex)
146                         break;
147         }
148
149         return grp;
150 }
151
152 /* Must hold vlan_group_lock. */
153 static void __grp_hash(struct vlan_group *grp)
154 {
155         struct vlan_group **head;
156
157         head = &vlan_group_hash[vlan_grp_hashfn(grp->real_dev_ifindex)];
158         grp->next = *head;
159         *head = grp;
160 }
161
162 /* Must hold vlan_group_lock. */
163 static void __grp_unhash(struct vlan_group *grp)
164 {
165         struct vlan_group *next, **pprev;
166
167         pprev = &vlan_group_hash[vlan_grp_hashfn(grp->real_dev_ifindex)];
168         next = *pprev;
169         while (next != grp) {
170                 pprev = &next->next;
171                 next = *pprev;
172         }
173         *pprev = grp->next;
174 }
175
176 /*  Find the protocol handler.  Assumes VID < VLAN_VID_MASK.
177  *
178  * Must be invoked with vlan_group_lock held.
179  */
180 struct net_device *__find_vlan_dev(struct net_device *real_dev,
181                                    unsigned short VID)
182 {
183         struct vlan_group *grp = __vlan_find_group(real_dev->ifindex);
184
185         if (grp)
186                 return grp->vlan_devices[VID];
187
188         return NULL;
189 }
190
191 /* This returns 0 if everything went fine.
192  * It will return 1 if the group was killed as a result.
193  * A negative return indicates failure.
194  *
195  * The RTNL lock must be held.
196  */
197 static int unregister_vlan_dev(struct net_device *real_dev,
198                                unsigned short vlan_id)
199 {
200         struct net_device *dev = NULL;
201         int real_dev_ifindex = real_dev->ifindex;
202         struct vlan_group *grp;
203         int i, ret;
204
205 #ifdef VLAN_DEBUG
206         printk(VLAN_DBG "%s: VID: %i\n", __FUNCTION__, vlan_id);
207 #endif
208
209         /* sanity check */
210         if (vlan_id >= VLAN_VID_MASK)
211                 return -EINVAL;
212
213         spin_lock_bh(&vlan_group_lock);
214         grp = __vlan_find_group(real_dev_ifindex);
215         spin_unlock_bh(&vlan_group_lock);
216
217         ret = 0;
218
219         if (grp) {
220                 dev = grp->vlan_devices[vlan_id];
221                 if (dev) {
222                         /* Remove proc entry */
223                         vlan_proc_rem_dev(dev);
224
225                         /* Take it out of our own structures, but be sure to
226                          * interlock with HW accelerating devices or SW vlan
227                          * input packet processing.
228                          */
229                         if (real_dev->features &
230                             (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER)) {
231                                 real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
232                         }
233
234                         br_write_lock(BR_NETPROTO_LOCK);
235                         grp->vlan_devices[vlan_id] = NULL;
236                         br_write_unlock(BR_NETPROTO_LOCK);
237
238
239                         /* Caller unregisters (and if necessary, puts)
240                          * VLAN device, but we get rid of the reference to
241                          * real_dev here.
242                          */
243                         dev_put(real_dev);
244
245                         /* If the group is now empty, kill off the
246                          * group.
247                          */
248                         for (i = 0; i < VLAN_VID_MASK; i++)
249                                 if (grp->vlan_devices[i])
250                                         break;
251
252                         if (i == VLAN_VID_MASK) {
253                                 if (real_dev->features & NETIF_F_HW_VLAN_RX)
254                                         real_dev->vlan_rx_register(real_dev, NULL);
255
256                                 spin_lock_bh(&vlan_group_lock);
257                                 __grp_unhash(grp);
258                                 spin_unlock_bh(&vlan_group_lock);
259
260                                 /* Free the group, after we have removed it
261                                  * from the hash.
262                                  */
263                                 kfree(grp);
264                                 grp = NULL;
265
266                                 ret = 1;
267                         }
268
269                         MOD_DEC_USE_COUNT;
270                 }
271         }
272
273         return ret;
274 }
275
276 static int unregister_vlan_device(const char *vlan_IF_name)
277 {
278         struct net_device *dev = NULL;
279         int ret;
280
281
282         dev = dev_get_by_name(vlan_IF_name);
283         ret = -EINVAL;
284         if (dev) {
285                 if (dev->priv_flags & IFF_802_1Q_VLAN) {
286                         rtnl_lock();
287
288                         ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
289                                                   VLAN_DEV_INFO(dev)->vlan_id);
290
291                         dev_put(dev);
292                         unregister_netdevice(dev);
293
294                         rtnl_unlock();
295
296                         if (ret == 1)
297                                 ret = 0;
298                 } else {
299                         printk(VLAN_ERR 
300                                "%s: ERROR:      Tried to remove a non-vlan device "
301                                "with VLAN code, name: %s  priv_flags: %hX\n",
302                                __FUNCTION__, dev->name, dev->priv_flags);
303                         dev_put(dev);
304                         ret = -EPERM;
305                 }
306         } else {
307 #ifdef VLAN_DEBUG
308                 printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__);
309 #endif
310                 ret = -EINVAL;
311         }
312
313         return ret;
314 }
315
316 /*  Attach a VLAN device to a mac address (ie Ethernet Card).
317  *  Returns the device that was created, or NULL if there was
318  *  an error of some kind.
319  */
320 static struct net_device *register_vlan_device(const char *eth_IF_name,
321                                                unsigned short VLAN_ID)
322 {
323         struct vlan_group *grp;
324         struct net_device *new_dev;
325         struct net_device *real_dev; /* the ethernet device */
326         int malloc_size = 0;
327         int r;
328
329 #ifdef VLAN_DEBUG
330         printk(VLAN_DBG "%s: if_name -:%s:-     vid: %i\n",
331                 __FUNCTION__, eth_IF_name, VLAN_ID);
332 #endif
333
334         if (VLAN_ID >= VLAN_VID_MASK)
335                 goto out_ret_null;
336
337         /* find the device relating to eth_IF_name. */
338         real_dev = dev_get_by_name(eth_IF_name);
339         if (!real_dev)
340                 goto out_ret_null;
341
342         if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
343                 printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
344                         __FUNCTION__, real_dev->name);
345                 goto out_put_dev;
346         }
347
348         if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
349             (real_dev->vlan_rx_register == NULL ||
350              real_dev->vlan_rx_kill_vid == NULL)) {
351                 printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
352                         __FUNCTION__, real_dev->name);
353                 goto out_put_dev;
354         }
355
356         if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
357             (real_dev->vlan_rx_add_vid == NULL ||
358              real_dev->vlan_rx_kill_vid == NULL)) {
359                 printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
360                         __FUNCTION__, real_dev->name);
361                 goto out_put_dev;
362         }
363
364         /* From this point on, all the data structures must remain
365          * consistent.
366          */
367         rtnl_lock();
368
369         /* The real device must be up and operating in order to
370          * assosciate a VLAN device with it.
371          */
372         if (!(real_dev->flags & IFF_UP))
373                 goto out_unlock;
374
375         spin_lock_bh(&vlan_group_lock);
376         r = (__find_vlan_dev(real_dev, VLAN_ID) != NULL);
377         spin_unlock_bh(&vlan_group_lock);
378
379         if (r) {
380                 /* was already registered. */
381                 printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
382                 goto out_unlock;
383         }
384
385         malloc_size = (sizeof(struct net_device));
386         new_dev = (struct net_device *) kmalloc(malloc_size, GFP_KERNEL);
387         VLAN_MEM_DBG("net_device malloc, addr: %p  size: %i\n",
388                      new_dev, malloc_size);
389
390         if (new_dev == NULL)
391                 goto out_unlock;
392
393         memset(new_dev, 0, malloc_size);
394
395         /* Set us up to have no queue, as the underlying Hardware device
396          * can do all the queueing we could want.
397          */
398         new_dev->tx_queue_len = 0;
399
400         /* Gotta set up the fields for the device. */
401 #ifdef VLAN_DEBUG
402         printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n",
403                vlan_name_type);
404 #endif
405         switch (vlan_name_type) {
406         case VLAN_NAME_TYPE_RAW_PLUS_VID:
407                 /* name will look like:  eth1.0005 */
408                 sprintf(new_dev->name, "%s.%.4i", real_dev->name, VLAN_ID);
409                 break;
410         case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:
411                 /* Put our vlan.VID in the name.
412                  * Name will look like:  vlan5
413                  */
414                 sprintf(new_dev->name, "vlan%i", VLAN_ID);
415                 break;
416         case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD:
417                 /* Put our vlan.VID in the name.
418                  * Name will look like:  eth0.5
419                  */
420                 sprintf(new_dev->name, "%s.%i", real_dev->name, VLAN_ID);
421                 break;
422         case VLAN_NAME_TYPE_PLUS_VID:
423                 /* Put our vlan.VID in the name.
424                  * Name will look like:  vlan0005
425                  */
426         default:
427                 sprintf(new_dev->name, "vlan%.4i", VLAN_ID);
428         };
429                     
430 #ifdef VLAN_DEBUG
431         printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
432 #endif
433         /* set up method calls */
434         new_dev->init = vlan_dev_init;
435         new_dev->destructor = vlan_dev_destruct;
436         new_dev->features |= NETIF_F_DYNALLOC ; 
437             
438         /* new_dev->ifindex = 0;  it will be set when added to
439          * the global list.
440          * iflink is set as well.
441          */
442         new_dev->get_stats = vlan_dev_get_stats;
443             
444         /* IFF_BROADCAST|IFF_MULTICAST; ??? */
445         new_dev->flags = real_dev->flags;
446         new_dev->flags &= ~IFF_UP;
447
448         /* Make this thing known as a VLAN device */
449         new_dev->priv_flags |= IFF_802_1Q_VLAN;
450                                 
451         /* need 4 bytes for extra VLAN header info,
452          * hope the underlying device can handle it.
453          */
454         new_dev->mtu = real_dev->mtu;
455         new_dev->change_mtu = vlan_dev_change_mtu;
456
457         /* TODO: maybe just assign it to be ETHERNET? */
458         new_dev->type = real_dev->type;
459
460         new_dev->hard_header_len = real_dev->hard_header_len;
461         if (!(real_dev->features & NETIF_F_HW_VLAN_TX)) {
462                 /* Regular ethernet + 4 bytes (18 total). */
463                 new_dev->hard_header_len += VLAN_HLEN;
464         }
465
466         new_dev->priv = kmalloc(sizeof(struct vlan_dev_info),
467                                 GFP_KERNEL);
468         VLAN_MEM_DBG("new_dev->priv malloc, addr: %p  size: %i\n",
469                      new_dev->priv,
470                      sizeof(struct vlan_dev_info));
471             
472         if (new_dev->priv == NULL)
473                 goto out_free_newdev;
474
475         memset(new_dev->priv, 0, sizeof(struct vlan_dev_info));
476
477         memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len);
478         memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
479         new_dev->addr_len = real_dev->addr_len;
480
481         new_dev->open = vlan_dev_open;
482         new_dev->stop = vlan_dev_stop;
483
484         if (real_dev->features & NETIF_F_HW_VLAN_TX) {
485                 new_dev->hard_header = real_dev->hard_header;
486                 new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
487                 new_dev->rebuild_header = real_dev->rebuild_header;
488         } else {
489                 new_dev->hard_header = vlan_dev_hard_header;
490                 new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
491                 new_dev->rebuild_header = vlan_dev_rebuild_header;
492         }
493         new_dev->hard_header_parse = real_dev->hard_header_parse;
494         new_dev->set_mac_address = vlan_dev_set_mac_address;
495         new_dev->set_multicast_list = vlan_dev_set_multicast_list;
496
497         VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
498         VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
499         VLAN_DEV_INFO(new_dev)->dent = NULL;
500         VLAN_DEV_INFO(new_dev)->flags = vlan_default_dev_flags;
501
502 #ifdef VLAN_DEBUG
503         printk(VLAN_DBG "About to go find the group for idx: %i\n",
504                real_dev->ifindex);
505 #endif
506             
507         /* So, got the sucker initialized, now lets place
508          * it into our local structure.
509          */
510         spin_lock_bh(&vlan_group_lock);
511         grp = __vlan_find_group(real_dev->ifindex);
512         spin_unlock_bh(&vlan_group_lock);
513
514         /* Note, we are running under the RTNL semaphore
515          * so it cannot "appear" on us.
516          */
517         if (!grp) { /* need to add a new group */
518                 grp = kmalloc(sizeof(struct vlan_group), GFP_KERNEL);
519                 if (!grp)
520                         goto out_free_newdev_priv;
521                                         
522                 /* printk(KERN_ALERT "VLAN REGISTER:  Allocated new group.\n"); */
523                 memset(grp, 0, sizeof(struct vlan_group));
524                 grp->real_dev_ifindex = real_dev->ifindex;
525
526                 spin_lock_bh(&vlan_group_lock);
527                 __grp_hash(grp);
528                 spin_unlock_bh(&vlan_group_lock);
529
530                 if (real_dev->features & NETIF_F_HW_VLAN_RX)
531                         real_dev->vlan_rx_register(real_dev, grp);
532         }
533             
534         grp->vlan_devices[VLAN_ID] = new_dev;
535
536         vlan_proc_add_dev(new_dev); /* create it's proc entry */
537
538         if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
539                 real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
540
541         register_netdevice(new_dev);
542
543         rtnl_unlock();
544             
545         /* NOTE:  We have a reference to the real device,
546          * so hold on to the reference.
547          */
548         MOD_INC_USE_COUNT; /* Add was a success!! */
549 #ifdef VLAN_DEBUG
550         printk(VLAN_DBG "Allocated new device successfully, returning.\n");
551 #endif
552         return new_dev;
553
554 out_free_newdev_priv:
555         kfree(new_dev->priv);
556
557 out_free_newdev:
558         kfree(new_dev);
559
560 out_unlock:
561         rtnl_unlock();
562
563 out_put_dev:
564         dev_put(real_dev);
565
566 out_ret_null:
567         return NULL;
568 }
569
570 static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
571 {
572         struct net_device *dev = (struct net_device *)(ptr);
573         struct vlan_group *grp = NULL;
574         int i, flgs;
575         struct net_device *vlandev = NULL;
576
577         spin_lock_bh(&vlan_group_lock);
578         grp = __vlan_find_group(dev->ifindex);
579         spin_unlock_bh(&vlan_group_lock);
580
581         if (!grp)
582                 goto out;
583
584         /* It is OK that we do not hold the group lock right now,
585          * as we run under the RTNL lock.
586          */
587
588         switch (event) {
589         case NETDEV_CHANGEADDR:
590         case NETDEV_GOING_DOWN:
591                 /* Ignore for now */
592                 break;
593
594         case NETDEV_DOWN:
595                 /* Put all VLANs for this dev in the down state too.  */
596                 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
597                         vlandev = grp->vlan_devices[i];
598                         if (!vlandev)
599                                 continue;
600
601                         flgs = vlandev->flags;
602                         if (!(flgs & IFF_UP))
603                                 continue;
604
605                         dev_change_flags(vlandev, flgs & ~IFF_UP);
606                 }
607                 break;
608
609         case NETDEV_UP:
610                 /* Put all VLANs for this dev in the up state too.  */
611                 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
612                         vlandev = grp->vlan_devices[i];
613                         if (!vlandev)
614                                 continue;
615                                 
616                         flgs = vlandev->flags;
617                         if (flgs & IFF_UP)
618                                 continue;
619
620                         dev_change_flags(vlandev, flgs | IFF_UP);
621                 }
622                 break;
623                 
624         case NETDEV_UNREGISTER:
625                 /* Delete all VLANs for this dev. */
626                 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
627                         int ret;
628
629                         vlandev = grp->vlan_devices[i];
630                         if (!vlandev)
631                                 continue;
632
633                         ret = unregister_vlan_dev(dev,
634                                                   VLAN_DEV_INFO(vlandev)->vlan_id);
635
636                         dev_put(vlandev);
637                         unregister_netdevice(vlandev);
638
639                         /* Group was destroyed? */
640                         if (ret == 1)
641                                 break;
642                 }
643                 break;
644         };
645
646 out:
647         return NOTIFY_DONE;
648 }
649
650 /*
651  *      VLAN IOCTL handler.
652  *      o execute requested action or pass command to the device driver
653  *   arg is really a void* to a vlan_ioctl_args structure.
654  */
655 int vlan_ioctl_handler(unsigned long arg)
656 {
657         int err = 0;
658         struct vlan_ioctl_args args;
659
660         /* everything here needs root permissions, except aguably the
661          * hack ioctls for sending packets.  However, I know _I_ don't
662          * want users running that on my network! --BLG
663          */
664         if (!capable(CAP_NET_ADMIN))
665                 return -EPERM;
666
667         if (copy_from_user(&args, (void*)arg,
668                            sizeof(struct vlan_ioctl_args)))
669                 return -EFAULT;
670
671         /* Null terminate this sucker, just in case. */
672         args.device1[23] = 0;
673         args.u.device2[23] = 0;
674
675 #ifdef VLAN_DEBUG
676         printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);
677 #endif
678
679         switch (args.cmd) {
680         case SET_VLAN_INGRESS_PRIORITY_CMD:
681                 err = vlan_dev_set_ingress_priority(args.device1,
682                                                     args.u.skb_priority,
683                                                     args.vlan_qos);
684                 break;
685
686         case SET_VLAN_EGRESS_PRIORITY_CMD:
687                 err = vlan_dev_set_egress_priority(args.device1,
688                                                    args.u.skb_priority,
689                                                    args.vlan_qos);
690                 break;
691
692         case SET_VLAN_FLAG_CMD:
693                 err = vlan_dev_set_vlan_flag(args.device1,
694                                              args.u.flag,
695                                              args.vlan_qos);
696                 break;
697
698         case SET_VLAN_NAME_TYPE_CMD:
699                 if ((args.u.name_type >= 0) &&
700                     (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
701                         vlan_name_type = args.u.name_type;
702                         err = 0;
703                 } else {
704                         err = -EINVAL;
705                 }
706                 break;
707
708                 /* TODO:  Figure out how to pass info back...
709                    case GET_VLAN_INGRESS_PRIORITY_IOCTL:
710                    err = vlan_dev_get_ingress_priority(args);
711                    break;
712
713                    case GET_VLAN_EGRESS_PRIORITY_IOCTL:
714                    err = vlan_dev_get_egress_priority(args);
715                    break;
716                 */
717
718         case ADD_VLAN_CMD:
719                 /* we have been given the name of the Ethernet Device we want to
720                  * talk to:  args.dev1   We also have the
721                  * VLAN ID:  args.u.VID
722                  */
723                 if (register_vlan_device(args.device1, args.u.VID)) {
724                         err = 0;
725                 } else {
726                         err = -EINVAL;
727                 }
728                 break;
729
730         case DEL_VLAN_CMD:
731                 /* Here, the args.dev1 is the actual VLAN we want
732                  * to get rid of.
733                  */
734                 err = unregister_vlan_device(args.device1);
735                 break;
736
737         default:
738                 /* pass on to underlying device instead?? */
739                 printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
740                         __FUNCTION__, args.cmd);
741                 return -EINVAL;
742         };
743
744         return err;
745 }
746
747 MODULE_LICENSE("GPL");