📄 dev.c
字号:
* * net_alias_dev_get(): dev_get() with added alias naming magic. * only allow alias creation/deletion if (getset==SIOCSIFADDR) * */ #ifdef CONFIG_KERNELD dev_load(ifr.ifr_name);#endif #ifdef CONFIG_NET_ALIAS if ((dev = net_alias_dev_get(ifr.ifr_name, getset == SIOCSIFADDR, &err, NULL, NULL)) == NULL) return(err);#else if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-ENODEV);#endif switch(getset) { case SIOCGIFFLAGS: /* Get interface flags */ ifr.ifr_flags = (dev->flags & ~IFF_SOFTHEADERS); goto rarok; case SIOCSIFFLAGS: /* Set interface flags */ { int old_flags = dev->flags; if(securelevel>0) ifr.ifr_flags&=~IFF_PROMISC; /* * We are not allowed to potentially close/unload * a device until we get this lock. */ dev_lock_wait(); /* * Set the flags on our device. */ dev->flags = (ifr.ifr_flags & ( IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER | IFF_MULTICAST)) | (dev->flags & (IFF_SOFTHEADERS|IFF_UP)); /* * 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. */ if ((old_flags^ifr.ifr_flags)&IFF_UP) /* Bit is different ? */ { if(old_flags&IFF_UP) /* Gone down */ ret=dev_close(dev); else /* Come up */ { ret=dev_open(dev); if(ret<0) dev->flags&=~IFF_UP; /* Open failed */ } } else ret=0; /* * Load in the correct multicast list now the flags have changed. */ dev_mc_upload(dev); } break; case SIOCGIFADDR: /* Get interface address (and family) */ if(ifr.ifr_addr.sa_family==AF_UNSPEC) { memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr.ifr_hwaddr.sa_family=dev->type; goto rarok; } else { (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_addr).sin_port = 0; } goto rarok; case SIOCSIFADDR: /* Set interface address (and family) */ /* * BSDism. SIOCSIFADDR family=AF_UNSPEC sets the * physical address. We can cope with this now. */ if(ifr.ifr_addr.sa_family==AF_UNSPEC) { if(dev->set_mac_address==NULL) return -EOPNOTSUPP; if(securelevel>0) return -EPERM; ret=dev->set_mac_address(dev,&ifr.ifr_addr); } else { u32 new_pa_addr = (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr; u16 new_family = ifr.ifr_addr.sa_family; if (new_family == dev->family && new_pa_addr == dev->pa_addr) { ret =0; break; } if (dev->flags & IFF_UP) notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); /* * if dev is an alias, must rehash to update * address change */#ifdef CONFIG_NET_ALIAS if (net_alias_is(dev)) net_alias_dev_rehash(dev ,&ifr.ifr_addr);#endif dev->pa_addr = new_pa_addr; dev->family = new_family; #ifdef CONFIG_INET /* This is naughty. When net-032e comes out It wants moving into the net032 code not the kernel. Till then it can sit here (SIGH) */ if (!dev->pa_mask) dev->pa_mask = ip_get_mask(dev->pa_addr);#endif if (!dev->pa_brdaddr) dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; if (dev->flags & IFF_UP) notifier_call_chain(&netdev_chain, NETDEV_UP, dev); ret = 0; } break; case SIOCGIFBRDADDR: /* Get the broadcast address */ (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_port = 0; goto rarok; case SIOCSIFBRDADDR: /* Set the broadcast address */ dev->pa_brdaddr = (*(struct sockaddr_in *) &ifr.ifr_broadaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_port = 0; goto rarok; case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ dev->pa_dstaddr = (*(struct sockaddr_in *) &ifr.ifr_dstaddr).sin_addr.s_addr; ret = 0; break; case SIOCGIFNETMASK: /* Get the netmask for the interface */ (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_family = dev->family; (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_port = 0; goto rarok; case SIOCSIFNETMASK: /* Set the netmask for the interface */ { unsigned long mask = (*(struct sockaddr_in *) &ifr.ifr_netmask).sin_addr.s_addr; ret = -EINVAL; /* * The mask we set must be legal. */ if (bad_mask(mask,0)) break; dev->pa_mask = mask; ret = 0; } break; case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ifr.ifr_metric = dev->metric; goto rarok; case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ dev->metric = ifr.ifr_metric; ret=0; break; case SIOCGIFMTU: /* Get the MTU of a device */ ifr.ifr_mtu = dev->mtu; goto rarok; case SIOCSIFMTU: /* Set the MTU of a device */ if (dev->change_mtu) ret = dev->change_mtu(dev, ifr.ifr_mtu); else { /* * MTU must be positive. */ if(ifr.ifr_mtu<68) return -EINVAL; dev->mtu = ifr.ifr_mtu; ret = 0; } break; case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently do not support it */ ret = -EINVAL; break; case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ ret = -EINVAL; break; case SIOCGIFHWADDR: memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ifr.ifr_hwaddr.sa_family=dev->type; goto rarok; case SIOCSIFHWADDR: if(dev->set_mac_address==NULL) return -EOPNOTSUPP; if(securelevel > 0) return -EPERM; if(ifr.ifr_hwaddr.sa_family!=dev->type) return -EINVAL; ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr); break; 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; goto rarok; case SIOCSIFMAP: if(dev->set_config==NULL) return -EOPNOTSUPP; return dev->set_config(dev,&ifr.ifr_map); case SIOCADDMULTI: if(dev->set_multicast_list==NULL) return -EINVAL; if(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) return -EINVAL; if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; /* * Unknown or private ioctl */ default: if((getset >= SIOCDEVPRIVATE) && (getset <= (SIOCDEVPRIVATE + 15))) { if(dev->do_ioctl==NULL) return -EOPNOTSUPP; ret=dev->do_ioctl(dev, &ifr, getset); memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); break; }#ifdef CONFIG_NET_RADIO if((getset >= SIOCIWFIRST) && (getset <= SIOCIWLAST)) { if(dev->do_ioctl==NULL) return -EOPNOTSUPP; /* Perform the ioctl */ ret=dev->do_ioctl(dev, &ifr, getset); /* If return args... */ if(IW_IS_GET(getset)) memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); break; }#endif /* CONFIG_NET_RADIO */ ret = -EINVAL; } return(ret);/* * The load of calls that return an ifreq and ok (saves memory). */rarok: memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); return 0;}/* * 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){ switch(cmd) { case SIOCGIFCONF: (void) dev_ifconf((char *) arg); return 0; /* * Ioctl calls that can be done by all. */ case SIOCGIFFLAGS: case SIOCGIFADDR: case SIOCGIFDSTADDR: case SIOCGIFBRDADDR: case SIOCGIFNETMASK: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: case SIOCGIFSLAVE: case SIOCGIFMAP: return dev_ifsioc(arg, cmd); /* * Ioctl calls requiring the power of a superuser */ case SIOCSIFFLAGS: case SIOCSIFADDR: case SIOCSIFDSTADDR: case SIOCSIFBRDADDR: case SIOCSIFNETMASK: case SIOCSIFMETRIC: case SIOCSIFMTU: case SIOCSIFMEM: case SIOCSIFHWADDR: case SIOCSIFMAP: case SIOCSIFSLAVE: case SIOCADDMULTI: case SIOCDELMULTI: if (!suser()) return -EPERM; return dev_ifsioc(arg, cmd); case SIOCSIFLINK: return -EINVAL; /* * Unknown or private ioctl. */ default: if((cmd >= SIOCDEVPRIVATE) && (cmd <= (SIOCDEVPRIVATE + 15))) { return dev_ifsioc(arg, cmd); }#ifdef CONFIG_NET_RADIO if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { if((IW_IS_SET(cmd)) && (!suser())) return -EPERM; return dev_ifsioc(arg, cmd); }#endif /* CONFIG_NET_RADIO */ return -EINVAL; }}/* * 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 pi_init(void);extern int pt_init(void);extern int bpq_init(void);extern void sdla_setup(void);extern int dlci_setup(void);extern int sm_init(void);extern int baycom_init(void);int net_dev_init(void){ struct device *dev, **dp; /* * 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_PI) pi_init();#endif #if defined(CONFIG_PT) pt_init();#endif#if defined(CONFIG_BPQETHER) bpq_init();#endif#if defined(CONFIG_DLCI) dlci_setup();#endif#if defined(CONFIG_SDLA) sdla_setup();#endif#if defined(CONFIG_BAYCOM) baycom_init();#endif#if defined(CONFIG_SOUNDMODEM) sm_init();#endif /* * SLHC if present needs attaching so other people see it * even if not opened. */#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \ || defined(CONFIG_PPP) \ || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP)) slhc_install();#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) { int i; for (i = 0; i < DEV_NUMBUFFS; i++) { skb_queue_head_init(dev->buffs + i); } if (dev->init && dev->init(dev)) { /* * It failed to come up. Unhook it. */ *dp = dev->next; } else { dp = &dev->next; } }#ifdef CONFIG_PROC_FS proc_net_register(&(struct proc_dir_entry) { 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_FS proc_net_register(&(struct proc_dir_entry) { 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 */ /* * Initialise net_alias engine * * - register net_alias device notifier * - register proc entries: /proc/net/alias_types * /proc/net/aliases */#ifdef CONFIG_NET_ALIAS net_alias_init();#endif init_bh(NET_BH, net_bh); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -