📄 vlan.c
字号:
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", __FUNCTION__, real_dev->name); goto out_put_dev; } if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && (real_dev->vlan_rx_add_vid == NULL || real_dev->vlan_rx_kill_vid == NULL)) { printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", __FUNCTION__, real_dev->name); goto out_put_dev; } /* From this point on, all the data structures must remain * consistent. */ rtnl_lock(); /* The real device must be up and operating in order to * assosciate a VLAN device with it. */ if (!(real_dev->flags & IFF_UP)) goto out_unlock; if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) { /* was already registered. */ printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__); goto out_unlock; } /* Gotta set up the fields for the device. */#ifdef VLAN_DEBUG printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n", vlan_name_type);#endif switch (vlan_name_type) { case VLAN_NAME_TYPE_RAW_PLUS_VID: /* name will look like: eth1.0005 */ snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID); break; case VLAN_NAME_TYPE_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: vlan5 */ snprintf(name, IFNAMSIZ, "vlan%i", VLAN_ID); break; case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: eth0.5 */ snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, VLAN_ID); break; case VLAN_NAME_TYPE_PLUS_VID: /* Put our vlan.VID in the name. * Name will look like: vlan0005 */ default: snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID); }; new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name, vlan_setup); if (new_dev == NULL) goto out_unlock;#ifdef VLAN_DEBUG printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);#endif /* IFF_BROADCAST|IFF_MULTICAST; ??? */ new_dev->flags = real_dev->flags; new_dev->flags &= ~IFF_UP; new_dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); /* need 4 bytes for extra VLAN header info, * hope the underlying device can handle it. */ new_dev->mtu = real_dev->mtu; /* TODO: maybe just assign it to be ETHERNET? */ new_dev->type = real_dev->type; new_dev->hard_header_len = real_dev->hard_header_len; if (!(real_dev->features & NETIF_F_HW_VLAN_TX)) { /* Regular ethernet + 4 bytes (18 total). */ new_dev->hard_header_len += VLAN_HLEN; } VLAN_MEM_DBG("new_dev->priv malloc, addr: %p size: %i\n", new_dev->priv, sizeof(struct vlan_dev_info)); memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len); memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); new_dev->addr_len = real_dev->addr_len; if (real_dev->features & NETIF_F_HW_VLAN_TX) { new_dev->hard_header = real_dev->hard_header; new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit; new_dev->rebuild_header = real_dev->rebuild_header; } else { new_dev->hard_header = vlan_dev_hard_header; new_dev->hard_start_xmit = vlan_dev_hard_start_xmit; new_dev->rebuild_header = vlan_dev_rebuild_header; } new_dev->hard_header_parse = real_dev->hard_header_parse; VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */ VLAN_DEV_INFO(new_dev)->real_dev = real_dev; VLAN_DEV_INFO(new_dev)->dent = NULL; VLAN_DEV_INFO(new_dev)->flags = 1;#ifdef VLAN_DEBUG printk(VLAN_DBG "About to go find the group for idx: %i\n", real_dev->ifindex);#endif if (register_netdevice(new_dev)) goto out_free_newdev; lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key); new_dev->iflink = real_dev->ifindex; vlan_transfer_operstate(real_dev, new_dev); linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */ /* So, got the sucker initialized, now lets place * it into our local structure. */ grp = __vlan_find_group(real_dev->ifindex); /* Note, we are running under the RTNL semaphore * so it cannot "appear" on us. */ if (!grp) { /* need to add a new group */ grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL); if (!grp) goto out_free_unregister; /* printk(KERN_ALERT "VLAN REGISTER: Allocated new group.\n"); */ grp->real_dev_ifindex = real_dev->ifindex; hlist_add_head_rcu(&grp->hlist, &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]); if (real_dev->features & NETIF_F_HW_VLAN_RX) real_dev->vlan_rx_register(real_dev, grp); } grp->vlan_devices[VLAN_ID] = new_dev; if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */ printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n", new_dev->name); if (real_dev->features & NETIF_F_HW_VLAN_FILTER) real_dev->vlan_rx_add_vid(real_dev, VLAN_ID); rtnl_unlock();#ifdef VLAN_DEBUG printk(VLAN_DBG "Allocated new device successfully, returning.\n");#endif return new_dev;out_free_unregister: unregister_netdev(new_dev); goto out_unlock;out_free_newdev: free_netdev(new_dev);out_unlock: rtnl_unlock();out_put_dev: dev_put(real_dev);out_ret_null: return NULL;}static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr){ struct net_device *dev = ptr; struct vlan_group *grp = __vlan_find_group(dev->ifindex); int i, flgs; struct net_device *vlandev; if (!grp) goto out; /* It is OK that we do not hold the group lock right now, * as we run under the RTNL lock. */ switch (event) { case NETDEV_CHANGE: /* Propagate real device state to vlan devices */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { vlandev = grp->vlan_devices[i]; if (!vlandev) continue; vlan_transfer_operstate(dev, vlandev); } break; case NETDEV_DOWN: /* Put all VLANs for this dev in the down state too. */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { vlandev = grp->vlan_devices[i]; if (!vlandev) continue; flgs = vlandev->flags; if (!(flgs & IFF_UP)) continue; dev_change_flags(vlandev, flgs & ~IFF_UP); } break; case NETDEV_UP: /* Put all VLANs for this dev in the up state too. */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { vlandev = grp->vlan_devices[i]; if (!vlandev) continue; flgs = vlandev->flags; if (flgs & IFF_UP) continue; dev_change_flags(vlandev, flgs | IFF_UP); } break; case NETDEV_UNREGISTER: /* Delete all VLANs for this dev. */ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { int ret; vlandev = grp->vlan_devices[i]; if (!vlandev) continue; ret = unregister_vlan_dev(dev, VLAN_DEV_INFO(vlandev)->vlan_id); unregister_netdevice(vlandev); /* Group was destroyed? */ if (ret == 1) break; } break; };out: return NOTIFY_DONE;}/* * VLAN IOCTL handler. * o execute requested action or pass command to the device driver * arg is really a struct vlan_ioctl_args __user *. */static int vlan_ioctl_handler(void __user *arg){ int err = 0; unsigned short vid = 0; struct vlan_ioctl_args args; if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args))) return -EFAULT; /* Null terminate this sucker, just in case. */ args.device1[23] = 0; args.u.device2[23] = 0;#ifdef VLAN_DEBUG printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);#endif switch (args.cmd) { case SET_VLAN_INGRESS_PRIORITY_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; err = vlan_dev_set_ingress_priority(args.device1, args.u.skb_priority, args.vlan_qos); break; case SET_VLAN_EGRESS_PRIORITY_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; err = vlan_dev_set_egress_priority(args.device1, args.u.skb_priority, args.vlan_qos); break; case SET_VLAN_FLAG_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; err = vlan_dev_set_vlan_flag(args.device1, args.u.flag, args.vlan_qos); break; case SET_VLAN_NAME_TYPE_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { vlan_name_type = args.u.name_type; err = 0; } else { err = -EINVAL; } break; case ADD_VLAN_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; /* we have been given the name of the Ethernet Device we want to * talk to: args.dev1 We also have the * VLAN ID: args.u.VID */ if (register_vlan_device(args.device1, args.u.VID)) { err = 0; } else { err = -EINVAL; } break; case DEL_VLAN_CMD: if (!capable(CAP_NET_ADMIN)) return -EPERM; /* Here, the args.dev1 is the actual VLAN we want * to get rid of. */ err = unregister_vlan_device(args.device1); break; case GET_VLAN_INGRESS_PRIORITY_CMD: /* TODO: Implement err = vlan_dev_get_ingress_priority(args); if (copy_to_user((void*)arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; } */ err = -EINVAL; break; case GET_VLAN_EGRESS_PRIORITY_CMD: /* TODO: Implement err = vlan_dev_get_egress_priority(args.device1, &(args.args); if (copy_to_user((void*)arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; } */ err = -EINVAL; break; case GET_VLAN_REALDEV_NAME_CMD: err = vlan_dev_get_realdev_name(args.device1, args.u.device2); if (err) goto out; if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; } break; case GET_VLAN_VID_CMD: err = vlan_dev_get_vid(args.device1, &vid); if (err) goto out; args.u.VID = vid; if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; } break; default: /* pass on to underlying device instead?? */ printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n", __FUNCTION__, args.cmd); return -EINVAL; };out: return err;}MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -