/* * 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(struct net *net, void __user *arg) { int err; struct vlan_ioctl_args args; struct net_device *dev = NULL; 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; rtnl_lock(); switch (args.cmd) { case SET_VLAN_INGRESS_PRIORITY_CMD: case SET_VLAN_EGRESS_PRIORITY_CMD: case SET_VLAN_FLAG_CMD: case ADD_VLAN_CMD: case DEL_VLAN_CMD: case GET_VLAN_REALDEV_NAME_CMD: case GET_VLAN_VID_CMD: err = -ENODEV; dev = __dev_get_by_name(net, args.device1); if (!dev) goto out; err = -EINVAL; if (args.cmd != ADD_VLAN_CMD && !is_vlan_dev(dev)) goto out; } switch (args.cmd) { case SET_VLAN_INGRESS_PRIORITY_CMD: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; vlan_dev_set_ingress_priority(dev, args.u.skb_priority, args.vlan_qos); err = 0; break; case SET_VLAN_EGRESS_PRIORITY_CMD: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; err = vlan_dev_set_egress_priority(dev, args.u.skb_priority, args.vlan_qos); break; case SET_VLAN_FLAG_CMD: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; err = vlan_dev_change_flags(dev, args.vlan_qos ? args.u.flag : 0, args.u.flag); break; case SET_VLAN_NAME_TYPE_CMD: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { struct vlan_net *vn; vn = net_generic(net, vlan_net_id); vn->name_type = args.u.name_type; err = 0; } else { err = -EINVAL; } break; case ADD_VLAN_CMD: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; err = register_vlan_device(dev, args.u.VID); break; case DEL_VLAN_CMD: err = -EPERM; if (!capable(CAP_NET_ADMIN)) break; unregister_vlan_dev(dev, NULL); err = 0; break; case GET_VLAN_REALDEV_NAME_CMD: err = 0; vlan_dev_get_realdev_name(dev, args.u.device2); if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) err = -EFAULT; break; case GET_VLAN_VID_CMD: err = 0; args.u.VID = vlan_dev_vlan_id(dev); if (copy_to_user(arg, &args, sizeof(struct vlan_ioctl_args))) err = -EFAULT; break; default: err = -EOPNOTSUPP; break; } out: rtnl_unlock(); return err; }
/* * VLAN IOCTL handler. * o execute requested action or pass command to the device driver * arg is really a void* to a vlan_ioctl_args structure. */ int vlan_ioctl_handler(unsigned long arg) { int err = 0; unsigned short vid = 0; struct vlan_ioctl_args args; if (copy_from_user(&args, (void*)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 (copy_to_user((void*)arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; } break; case GET_VLAN_VID_CMD: err = vlan_dev_get_vid(args.device1, &vid); args.u.VID = vid; if (copy_to_user((void*)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; }; return err; }