📄 dev.c
字号:
dev_mc_upload(dev); printk(KERN_INFO "device %s %s promiscuous mode\n", dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "left"); }}void dev_set_allmulti(struct device *dev, int inc){ unsigned short old_flags = dev->flags; dev->flags |= IFF_ALLMULTI; if ((dev->allmulti += inc) == 0) dev->flags &= ~IFF_ALLMULTI; if (dev->flags^old_flags) dev_mc_upload(dev);}int dev_change_flags(struct device *dev, unsigned flags){ int ret; int old_flags = dev->flags; /* * Set the flags on our device. */ dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP| IFF_SLAVE|IFF_MASTER|IFF_DYNAMIC| IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) | (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI)); /* * Load in the correct multicast list now the flags have changed. */ dev_mc_upload(dev); /* * Have we downed the interface. We handle IFF_UP ourselves * according to user attempts to set it, rather than blindly * setting it. */ ret = 0; if ((old_flags^flags)&IFF_UP) /* Bit is different ? */ { ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); if (ret == 0) dev_mc_upload(dev); } if (dev->flags&IFF_UP && ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE))) notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); if ((flags^dev->gflags)&IFF_PROMISC) { int inc = (flags&IFF_PROMISC) ? +1 : -1; dev->gflags ^= IFF_PROMISC; dev_set_promiscuity(dev, inc); } /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI is important. Some (broken) drivers set IFF_PROMISC, when IFF_ALLMULTI is requested not asking us and not reporting. */ if ((flags^dev->gflags)&IFF_ALLMULTI) { int inc = (flags&IFF_ALLMULTI) ? +1 : -1; dev->gflags ^= IFF_ALLMULTI; dev_set_allmulti(dev, inc); } return ret;}#ifdef _HURD_#define dev_ioctl 0#else/* * Perform the SIOCxIFxxx calls. */static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd){ struct device *dev; int err; if ((dev = dev_get(ifr->ifr_name)) == NULL) return -ENODEV; switch(cmd) { case SIOCGIFFLAGS: /* Get interface flags */ ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI)) |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); return 0; case SIOCSIFFLAGS: /* Set interface flags */ return dev_change_flags(dev, ifr->ifr_flags); case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr->ifr_metric = 0; return 0; case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ return -EOPNOTSUPP; case SIOCGIFMTU: /* Get the MTU of a device */ ifr->ifr_mtu = dev->mtu; return 0; case SIOCSIFMTU: /* Set the MTU of a device */ if (ifr->ifr_mtu == dev->mtu) return 0; /* * MTU must be positive. */ if (ifr->ifr_mtu<=0) return -EINVAL; if (dev->change_mtu) err = dev->change_mtu(dev, ifr->ifr_mtu); else { dev->mtu = ifr->ifr_mtu; err = 0; } if (!err && dev->flags&IFF_UP) notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev); return err; case SIOCGIFHWADDR: memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr->ifr_hwaddr.sa_family=dev->type; return 0; case SIOCSIFHWADDR: if(dev->set_mac_address==NULL) return -EOPNOTSUPP; if(ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; 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) 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; 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; 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(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; /* * Unknown or private ioctl */ default: if(cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) { if (dev->do_ioctl) return dev->do_ioctl(dev, ifr, cmd); return -EOPNOTSUPP; }#ifdef CONFIG_NET_RADIO if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { if (dev->do_ioctl) return dev->do_ioctl(dev, ifr, cmd); return -EOPNOTSUPP; }#endif /* CONFIG_NET_RADIO */ } return -EINVAL;}/* * This function handles all "interface"-type I/O control requests. The actual * 'doing' part of this is dev_ifsioc above. */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); ret = dev_ifsioc(&ifr, cmd); 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: if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); rtnl_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); rtnl_lock(); ret = dev_ifsioc(&ifr, cmd); rtnl_unlock(); if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return ret; }#ifdef CONFIG_NET_RADIO if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { dev_load(ifr.ifr_name); if (IW_IS_SET(cmd)) { if (!suser()) return -EPERM; rtnl_lock(); } ret = dev_ifsioc(&ifr, cmd); if (IW_IS_SET(cmd)) rtnl_unlock(); if (!ret && IW_IS_GET(cmd) && copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return ret; }#endif /* CONFIG_NET_RADIO */ return -EINVAL; }}#endifint 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;int register_netdevice(struct device *dev){ struct device *d, **dp; if (dev_boot_phase) { /* This is NOT bug, but I am not sure, that all the devices, initialized before netdev module is started are sane. Now they are chained to device boot list and probed later. If a module is initialized before netdev, but assumes that dev->init is really called by register_netdev(), it will fail. So that this message should be printed for a while. */ printk(KERN_INFO "early initialization of device %s is deferred\n", dev->name); /* 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) return -EEXIST; } dev->next = NULL; *dp = dev; return 0; } dev->iflink = -1; /* Init, if this function is available */ if (dev->init && dev->init(dev) != 0) return -EIO; /* 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) return -EEXIST; } dev->next = NULL; dev_init_scheduler(dev); dev->ifindex = dev_new_index(); if (dev->iflink == -1) dev->iflink = dev->ifindex; *dp = dev; /* Notify protocols, that a new device appeared. */ notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); return 0;}int unregister_netdevice(struct device *dev){ struct device *d, **dp; if (dev_boot_phase == 0) { /* If device is running, close it. It is very bad idea, really we should complain loudly here, but random hackery in linux/drivers/net likes it. */ if (dev->flags & IFF_UP) dev_close(dev);#ifdef CONFIG_NET_FASTROUTE dev_clear_fastroute(dev);#endif /* Shutdown queueing discipline. */ dev_shutdown(dev); /* 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); /* To avoid pointers looking to nowhere, we wait for end of critical section */ dev_lock_wait(); } /* And unlink it from device chain. */ for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) { if (d == dev) { *dp = d->next; synchronize_bh(); d->next = NULL; if (dev->destructor) dev->destructor(dev); return 0; } } return -ENODEV;}/* * Initialize the DEV module. At boot time this walks the device list and * unhooks any devices that fail to initialise (normally hardware not * present) and leaves us with a valid list of present and active devices. * */extern int lance_init(void);extern int bpq_init(void);extern int scc_init(void);extern void sdla_setup(void);extern void sdla_c_setup(void);extern void dlci_setup(void);extern int dmascc_init(void);extern int sm_init(void);extern int baycom_ser_fdx_init(void);extern int baycom_ser_hdx_init(void);extern int baycom_par_init(void);extern int lapbeth_init(void);extern int comx_init(void);extern void arcnet_init(void);extern void ip_auto_config(void);#ifdef CONFIG_8xxextern int cpm_enet_init(void);#endif /* CONFIG_8xx */#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry proc_net_dev = { PROC_NET_DEV, 3, "dev", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, dev_get_info};#endif#ifdef CONFIG_NET_RADIO#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry proc_net_wireless = { PROC_NET_WIRELESS, 8, "wireless", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, dev_get_wireless_info};#endif /* CONFIG_PROC_FS */#endif /* CONFIG_NET_RADIO */__initfunc(int net_dev_init(void)){ struct device *dev, **dp;#ifdef CONFIG_NET_SCHED pktsched_init();#endif /* * Initialise the packet receive queue. */ skb_queue_head_init(&backlog); /* * The bridge has to be up before the devices */#ifdef CONFIG_BRIDGE br_init();#endif /* * This is Very Ugly(tm). * * Some devices want to be initialized early.. */#if defined(CONFIG_SCC) scc_init();#endif#if defined(CONFIG_DMASCC) dmascc_init();#endif#if defined(CONFIG_BPQETHER) bpq_init();#endif#if defined(CONFIG_DLCI) dlci_setup();#endif#if defined(CONFIG_SDLA) sdla_c_setup();#endif#if defined(CONFIG_BAYCOM_PAR) baycom_par_init();#endif#if defined(CONFIG_BAYCOM_SER_FDX) baycom_ser_fdx_init();#endif#if defined(CONFIG_BAYCOM_SER_HDX) baycom_ser_hdx_init();#endif#if defined(CONFIG_SOUNDMODEM) sm_init();#endif#if defined(CONFIG_LAPBETHER) lapbeth_init();#endif#if defined(CONFIG_PLIP) plip_init();#endif#if defined(CONFIG_ARCNET) arcnet_init();#endif#if defined(CONFIG_8xx) cpm_enet_init();#endif#if defined(CONFIG_COMX) comx_init();#endif /* * SLHC if present needs attaching so other people see it * even if not opened. */#ifdef CONFIG_INET#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \ || defined(CONFIG_PPP) \ || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP)) slhc_install();#endif#endif#ifdef CONFIG_NET_PROFILE net_profile_init(); NET_PROFILE_REGISTER(dev_queue_xmit); NET_PROFILE_REGISTER(net_bh);#if 0 NET_PROFILE_REGISTER(net_bh_skb);#endif#endif /* * Add the devices. * If the call to dev->init fails, the dev is removed * from the chain disconnecting the device until the * next reboot. */ dp = &dev_base; while ((dev = *dp) != NULL) { dev->iflink = -1; if (dev->init && dev->init(dev)) { /* * It failed to come up. Unhook it. */ *dp = dev->next; synchronize_bh(); } else { dp = &dev->next; dev->ifindex = dev_new_index(); if (dev->iflink == -1) dev->iflink = dev->ifindex; dev_init_scheduler(dev); } }#ifdef CONFIG_PROC_FS proc_net_register(&proc_net_dev); { struct proc_dir_entry *ent = create_proc_entry("net/dev_stat", 0, 0); ent->read_proc = dev_proc_stats; }#endif#ifdef CONFIG_NET_RADIO#ifdef CONFIG_PROC_FS proc_net_register(&proc_net_wireless);#endif /* CONFIG_PROC_FS */#endif /* CONFIG_NET_RADIO */ init_bh(NET_BH, net_bh); dev_boot_phase = 0; dev_mcast_init();#ifdef CONFIG_BRIDGE /* * Register any statically linked ethernet devices with the bridge */ br_spacedevice_register();#endif#ifdef CONFIG_IP_PNP ip_auto_config();#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -