📄 devinet.c
字号:
if( !in_dev ){ if( event == NETDEV_REGISTER && dev == &loopback_dev ){ in_dev = myinetdev_init( dev ); if (!in_dev) panic("devinet: Failed to create loopback\n"); in_dev->cnf.no_xfrm = 1; in_dev->cnf.no_policy = 1; } goto out; } switch (event) { case NETDEV_REGISTER: PR_DEBUG( "inetdev_event: bug\n"); dev->ip_ptr = NULL; break; case NETDEV_UP: if( dev->mtu < 68 ) break; if( dev == &loopback_dev ){ struct in_ifaddr *ifa; if( (ifa = myinet_alloc_ifa()) != NULL ){ ifa->ifa_local = ifa->ifa_address = htonl(INADDR_LOOPBACK); ifa->ifa_prefixlen = 8; ifa->ifa_mask = inet_make_mask(8); in_dev_hold(in_dev); ifa->ifa_dev = in_dev; ifa->ifa_scope = RT_SCOPE_HOST; memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); myinet_insert_ifa(ifa); } } //ip_mc_up(in_dev); break; case NETDEV_DOWN: //ip_mc_down(in_dev); break; case NETDEV_CHANGEMTU: if (dev->mtu >= 68) break; case NETDEV_UNREGISTER: //myinetdev_destroy(in_dev); //the kernel's code has done this!!! break; case NETDEV_CHANGENAME: myinetdev_changename(dev, in_dev);/*#ifdef CONFIG_SYSCTL devinet_sysctl_unregister(&in_dev->cnf); neigh_sysctl_unregister(in_dev->arp_parms); neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4", NULL, NULL); devinet_sysctl_register(in_dev, &in_dev->cnf);#endif*/ break; } out: return 0;}static __inline__ int myinet_abc_len(u32 addr){ int rc = -1; if( ZERONET(addr) ) rc = 0; else{ addr = ntohl(addr); if (IN_CLASSA(addr)) rc = 8; else if (IN_CLASSB(addr)) rc = 16; else if (IN_CLASSC(addr)) rc = 24; } return rc;}static int myinet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa){ struct in_device *in_dev = __in_dev_get_rtnl(dev); ASSERT_RTNL(); if (!in_dev) { in_dev = myinetdev_init(dev); if( !in_dev ){ myinet_free_ifa(ifa); return -ENOBUFS; } } if( ifa->ifa_dev != in_dev ){ BUG_TRAP( !ifa->ifa_dev ); in_dev_hold(in_dev); ifa->ifa_dev = in_dev; } if( LOOPBACK(ifa->ifa_local) ) ifa->ifa_scope = RT_SCOPE_HOST; return myinet_insert_ifa(ifa);}int mydevinet_ioctl(unsigned int cmd, void __user *arg){ struct ifreq ifr; struct sockaddr_in sin_orig; struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; char *colon; struct in_device *in_dev; struct in_ifaddr **ifap = NULL; struct in_ifaddr *ifa = NULL; struct net_device *dev; int ret = -EFAULT; int tryaddrmatch = 0; if( copy_from_user(&ifr, arg, sizeof(struct ifreq)) ) goto out; ifr.ifr_name[IFNAMSIZ - 1] = 0; memcpy(&sin_orig, sin, sizeof(*sin)); colon = strchr(ifr.ifr_name, ':'); if( colon ) *colon = 0;#ifdef CONFIG_KMOD dev_load(ifr.ifr_name);#endif switch(cmd) { case SIOCGIFADDR: case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: case SIOCGIFNETMASK: tryaddrmatch = (sin_orig.sin_family == MY_AF_INET); memset( sin, 0, sizeof(*sin) ); sin->sin_family = MY_AF_INET; break; case SIOCSIFFLAGS: ret = -EACCES; if( !capable(CAP_NET_ADMIN) ) goto out; break; case SIOCSIFADDR: case SIOCSIFBRDADDR: case SIOCSIFDSTADDR: case SIOCSIFNETMASK: ret = -EACCES; if (!capable(CAP_NET_ADMIN)) goto out; ret = -EINVAL; if (sin->sin_family != MY_AF_INET) goto out; break; default: ret = -EINVAL; goto out; } rtnl_lock(); ret = -ENODEV; if( (dev = __dev_get_by_name(ifr.ifr_name)) == NULL ) goto done; if( colon ) *colon = ':'; if( (in_dev = __in_dev_get_rtnl(dev)) != NULL ){ if( tryaddrmatch ){ for( ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next ){ if( !strcmp(ifr.ifr_name, ifa->ifa_label) && sin_orig.sin_addr.s_addr == ifa->ifa_address) { break; } } } if( !ifa ){ for( ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next ) if( !strcmp(ifr.ifr_name, ifa->ifa_label) ) break; } } ret = -EADDRNOTAVAIL; if( !ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS ) goto done; switch(cmd) { case SIOCGIFADDR: sin->sin_addr.s_addr = ifa->ifa_local; goto rarok; case SIOCGIFBRDADDR: sin->sin_addr.s_addr = ifa->ifa_broadcast; goto rarok; case SIOCGIFDSTADDR: sin->sin_addr.s_addr = ifa->ifa_address; goto rarok; case SIOCGIFNETMASK: sin->sin_addr.s_addr = ifa->ifa_mask; goto rarok; case SIOCSIFBRDADDR: ret = 0; if( ifa->ifa_broadcast != sin->sin_addr.s_addr ){ myinet_del_ifa(in_dev, ifap, 0); ifa->ifa_broadcast = sin->sin_addr.s_addr; myinet_insert_ifa(ifa); } break; case SIOCSIFADDR: ret = -EINVAL; if( myinet_abc_len(sin->sin_addr.s_addr) < 0) break; if( !ifa ){ ret = -ENOBUFS; if( (ifa = myinet_alloc_ifa()) == NULL ) break; if( colon ) memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); else memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); }else{ ret = 0; if (ifa->ifa_local == sin->sin_addr.s_addr) break; myinet_del_ifa(in_dev, ifap, 0); ifa->ifa_broadcast = 0; ifa->ifa_anycast = 0; } ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr; if( !(dev->flags & IFF_POINTOPOINT) ){ ifa->ifa_prefixlen = myinet_abc_len(ifa->ifa_address); ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); if( (dev->flags & IFF_BROADCAST) && ifa->ifa_prefixlen < 31 ) ifa->ifa_broadcast = ifa->ifa_address | ~ifa->ifa_mask; }else{ ifa->ifa_prefixlen = 32; ifa->ifa_mask = inet_make_mask(32); } ret = myinet_set_ifa(dev, ifa); break; case SIOCSIFFLAGS: if( colon ){ ret = -EADDRNOTAVAIL; if( !ifa ) break; ret = 0; if( !(ifr.ifr_flags & IFF_UP) ) myinet_del_ifa( in_dev, ifap, 1 ); break; } ret = mydev_change_flags( dev, ifr.ifr_flags ); break; case SIOCSIFNETMASK: ret = -EINVAL; if( bad_mask(sin->sin_addr.s_addr, 0) ) break; ret = 0; if (ifa->ifa_mask != sin->sin_addr.s_addr) { u32 old_mask = ifa->ifa_mask; myinet_del_ifa(in_dev, ifap, 0); ifa->ifa_mask = sin->sin_addr.s_addr; ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); if( (dev->flags & IFF_BROADCAST) && (ifa->ifa_prefixlen < 31) && (ifa->ifa_broadcast == (ifa->ifa_local|~old_mask))) { ifa->ifa_broadcast = (ifa->ifa_local | ~sin->sin_addr.s_addr); } myinet_insert_ifa(ifa); } break; case SIOCSIFDSTADDR: ret = 0; if (ifa->ifa_address == sin->sin_addr.s_addr) break; ret = -EINVAL; if( myinet_abc_len(sin->sin_addr.s_addr) < 0 ) break; ret = 0; myinet_del_ifa(in_dev, ifap, 0); ifa->ifa_address = sin->sin_addr.s_addr; myinet_insert_ifa(ifa); break; }done: rtnl_unlock();out: return ret;rarok: rtnl_unlock(); ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0; goto out;}static struct notifier_block myip_netdev_notifier = { .notifier_call = myinetdev_event,};static int myinet_gifconf(struct net_device *dev, char __user *buf, int len){ struct in_device *in_dev = __in_dev_get_rtnl(dev); struct in_ifaddr *ifa; struct ifreq ifr; int done = 0; if( !in_dev || (ifa = in_dev->ifa_list) == NULL ) goto out; for (; ifa; ifa = ifa->ifa_next) { if( !buf ){ done += sizeof(ifr); continue; } if( len < (int) sizeof(ifr) ) break; memset(&ifr, 0, sizeof(struct ifreq)); if( ifa->ifa_label ) strcpy(ifr.ifr_name, ifa->ifa_label); else strcpy(ifr.ifr_name, dev->name); (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = MY_AF_INET; (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local; if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) { done = -EFAULT; break; } buf += sizeof(struct ifreq); len -= sizeof(struct ifreq); done += sizeof(struct ifreq); }out: return done;}void __init mydevinet_init(void){ myregister_gifconf( MY_PF_INET, myinet_gifconf ); myregister_netdevice_notifier( &myip_netdev_notifier );}void __exit mydevinet_exit(void){ myunregister_netdevice_notifier( &myip_netdev_notifier ); myunregister_gifconf( MY_PF_INET );}EXPORT_SYMBOL_GPL( mydevinet_ioctl );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -