📄 dev.c
字号:
if (ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; err = dev->set_mac_address(dev, &ifr->ifr_hwaddr); if (!err) notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; case SIOCSIFHWBROADCAST: if (ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN); notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return 0; case SIOCGIFMAP: ifr->ifr_map.mem_start=dev->mem_start; ifr->ifr_map.mem_end=dev->mem_end; ifr->ifr_map.base_addr=dev->base_addr; ifr->ifr_map.irq=dev->irq; ifr->ifr_map.dma=dev->dma; ifr->ifr_map.port=dev->if_port; return 0; case SIOCSIFMAP: if (dev->set_config) { if (!netif_device_present(dev)) return -ENODEV; return dev->set_config(dev,&ifr->ifr_map); } return -EOPNOTSUPP; case SIOCADDMULTI: if (dev->set_multicast_list == NULL || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1); return 0; case SIOCDELMULTI: if (dev->set_multicast_list == NULL || ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; case SIOCGIFINDEX: ifr->ifr_ifindex = dev->ifindex; return 0; case SIOCGIFTXQLEN: ifr->ifr_qlen = dev->tx_queue_len; return 0; case SIOCSIFTXQLEN: if (ifr->ifr_qlen<0) return -EINVAL; dev->tx_queue_len = ifr->ifr_qlen; return 0; case SIOCSIFNAME: if (dev->flags&IFF_UP) return -EBUSY; if (__dev_get_by_name(ifr->ifr_newname)) return -EEXIST; memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ); dev->name[IFNAMSIZ-1] = 0; notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); return 0;#ifdef WIRELESS_EXT case SIOCGIWSTATS: return dev_iwstats(dev, ifr);#endif /* WIRELESS_EXT */ /* * Unknown or private ioctl */ default: if ((cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) || cmd == SIOCBONDENSLAVE || cmd == SIOCBONDRELEASE || cmd == SIOCBONDSETHWADDR || cmd == SIOCBONDSLAVEINFOQUERY || cmd == SIOCBONDINFOQUERY || cmd == SIOCBONDCHANGEACTIVE || cmd == SIOCETHTOOL || cmd == SIOCGMIIPHY || cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) { if (dev->do_ioctl) { if (!netif_device_present(dev)) return -ENODEV; return dev->do_ioctl(dev, ifr, cmd); } return -EOPNOTSUPP; }#ifdef WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { if (dev->do_ioctl) { if (!netif_device_present(dev)) return -ENODEV; return dev->do_ioctl(dev, ifr, cmd); } return -EOPNOTSUPP; }#endif /* WIRELESS_EXT */ } return -EINVAL;}/* * This function handles all "interface"-type I/O control requests. The actual * 'doing' part of this is dev_ifsioc above. *//** * dev_ioctl - network device ioctl * @cmd: command to issue * @arg: pointer to a struct ifreq in user space * * Issue ioctl functions to devices. This is normally called by the * user space syscall interfaces but can sometimes be useful for * other purposes. The return value is the return from the syscall if * positive or a negative errno code on error. */int dev_ioctl(unsigned int cmd, void *arg){ struct ifreq ifr; int ret; char *colon; /* One special case: SIOCGIFCONF takes ifconf argument and requires shared lock, because it sleeps writing to user space. */ if (cmd == SIOCGIFCONF) { rtnl_shlock(); ret = dev_ifconf((char *) arg); rtnl_shunlock(); return ret; } if (cmd == SIOCGIFNAME) { return dev_ifname((struct ifreq *)arg); } if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; ifr.ifr_name[IFNAMSIZ-1] = 0; colon = strchr(ifr.ifr_name, ':'); if (colon) *colon = 0; /* * See which interface the caller is talking about. */ switch(cmd) { /* * These ioctl calls: * - can be done by all. * - atomic and do not require locking. * - return a value */ case SIOCGIFFLAGS: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFHWADDR: case SIOCGIFSLAVE: case SIOCGIFMAP: case SIOCGIFINDEX: case SIOCGIFTXQLEN: dev_load(ifr.ifr_name); read_lock(&dev_base_lock); ret = dev_ifsioc(&ifr, cmd); read_unlock(&dev_base_lock); if (!ret) { if (colon) *colon = ':'; if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; } return ret; /* * These ioctl calls: * - require superuser power. * - require strict serialization. * - return a value */ case SIOCETHTOOL: case SIOCGMIIPHY: case SIOCGMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); dev_probe_lock(); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); rtnl_unlock(); dev_probe_unlock(); if (!ret) { if (colon) *colon = ':'; if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; } return ret; /* * These ioctl calls: * - require superuser power. * - require strict serialization. * - do not return a value */ case SIOCSIFFLAGS: case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMAP: case SIOCSIFHWADDR: case SIOCSIFSLAVE: case SIOCADDMULTI: case SIOCDELMULTI: case SIOCSIFHWBROADCAST: case SIOCSIFTXQLEN: case SIOCSIFNAME: case SIOCSMIIREG: case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: case SIOCBONDSLAVEINFOQUERY: case SIOCBONDINFOQUERY: case SIOCBONDCHANGEACTIVE: if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); dev_probe_lock(); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); rtnl_unlock(); dev_probe_unlock(); return ret; case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently do not support it */ case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ case SIOCSIFLINK: return -EINVAL; /* * Unknown or private ioctl. */ default: if (cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) { dev_load(ifr.ifr_name); dev_probe_lock(); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); rtnl_unlock(); dev_probe_unlock(); if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return ret; }#ifdef WIRELESS_EXT /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { /* If command is `set a parameter', or * `get the encoding parameters', check if * the user has the right to do it */ if (IW_IS_SET(cmd) || (cmd == SIOCGIWENCODE)) { if(!capable(CAP_NET_ADMIN)) return -EPERM; } dev_load(ifr.ifr_name); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); rtnl_unlock(); if (!ret && IW_IS_GET(cmd) && copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return ret; }#endif /* WIRELESS_EXT */ return -EINVAL; }}/** * dev_new_index - allocate an ifindex * * Returns a suitable unique value for a new device interface * number. The caller must hold the rtnl semaphore or the * dev_base_lock to be sure it remains unique. */ int dev_new_index(void){ static int ifindex; for (;;) { if (++ifindex <= 0) ifindex=1; if (__dev_get_by_index(ifindex) == NULL) return ifindex; }}static int dev_boot_phase = 1;/** * register_netdevice - register a network device * @dev: device to register * * Take a completed network device structure and add it to the kernel * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate. * * Callers must hold the rtnl semaphore. See the comment at the * end of Space.c for details about the locking. You may want * register_netdev() instead of this. * * BUGS: * The locking appears insufficient to guarantee two parallel registers * will not get the same name. */int net_dev_init(void);int register_netdevice(struct net_device *dev){ struct net_device *d, **dp;#ifdef CONFIG_NET_DIVERT int ret;#endif spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->xmit_lock); dev->xmit_lock_owner = -1;#ifdef CONFIG_NET_FASTROUTE dev->fastpath_lock=RW_LOCK_UNLOCKED;#endif if (dev_boot_phase) net_dev_init();#ifdef CONFIG_NET_DIVERT ret = alloc_divert_blk(dev); if (ret) return ret;#endif /* CONFIG_NET_DIVERT */ dev->iflink = -1; /* Init, if this function is available */ if (dev->init && dev->init(dev) != 0) {#ifdef CONFIG_NET_DIVERT free_divert_blk(dev);#endif return -EIO; } dev->ifindex = dev_new_index(); if (dev->iflink == -1) dev->iflink = dev->ifindex; /* Check for existence, and append to tail of chain */ for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) { if (d == dev || strcmp(d->name, dev->name) == 0) {#ifdef CONFIG_NET_DIVERT free_divert_blk(dev);#endif return -EEXIST; } } /* * nil rebuild_header routine, * that should be never called and used as just bug trap. */ if (dev->rebuild_header == NULL) dev->rebuild_header = default_rebuild_header; /* * Default initial state at registry is that the * device is present. */ set_bit(__LINK_STATE_PRESENT, &dev->state); dev->next = NULL; dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); *dp = dev; dev_hold(dev); dev->deadbeaf = 0; write_unlock_bh(&dev_base_lock); /* Notify protocols, that a new device appeared. */ notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); net_run_sbin_hotplug(dev, "register"); return 0;}/** * netdev_finish_unregister - complete unregistration * @dev: device * * Destroy and free a dead device. A value of zero is returned on * success. */ int netdev_finish_unregister(struct net_device *dev){ BUG_TRAP(dev->ip_ptr==NULL); BUG_TRAP(dev->ip6_ptr==NULL); BUG_TRAP(dev->dn_ptr==NULL); if (!dev->deadbeaf) { printk(KERN_ERR "Freeing alive device %p, %s\n", dev, dev->name); return 0; }#ifdef NET_REFCNT_DEBUG printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name, (dev->features & NETIF_F_DYNALLOC)?"":", old style");#endif if (dev->destructor) dev->destructor(dev); if (dev->features & NETIF_F_DYNALLOC) kfree(dev); return 0;}/** * unregister_netdevice - remove device from the kernel * @dev: device * * This function shuts down a device interface and removes it * from the kernel tables. On success 0 is returned, on a failure * a negative errno code is returned. * * Callers must hold the rtnl semaphore. See the comment at the * end of Space.c for details about the locking. You may want * unregister_netdev() instead of this. */int unregister_netdevice(struct net_device *dev){ unsigned long now, warning_time; struct net_device *d, **dp; /* If device is running, close it first. */ if (dev->flags & IFF_UP) dev_close(dev); BUG_TRAP(dev->deadbeaf==0); dev->deadbeaf = 1; /* And unlink it from device chain. */ for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) { if (d == dev) { write_lock_bh(&dev_base_lock); *dp = d->next; write_unlock_bh(&dev_base_lock); break; } } if (d == NULL) { printk(KERN_DEBUG "unregister_netdevice: device %s/%p never was registered\n", dev->name, dev); return -ENODEV; } /* Synchronize to net_rx_action. */ br_write_lock_bh(BR_NETPROTO_LOCK); br_write_unlock_bh(BR_NETPROTO_LOCK); if (dev_boot_phase == 0) {#ifdef CONFIG_NET_FASTROUTE dev_clear_fastroute(dev);#endif /* Shutdown queueing discipline. */ dev_shutdown(dev); net_run_sbin_hotplug(dev, "unregister"); /* Notify protocols, that we are about to destroy this device. They should clean all the things. */ notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); /* * Flush the multicast chain */ dev_mc_discard(dev); } if (dev->uninit) dev->uninit(dev); /* Notifier chain MUST detach us from master device. */ BUG_TRAP(dev->master==NULL);#ifdef CONFIG_NET_DIVERT free_divert_blk(dev);#endif i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -