📄 devinet.c
字号:
break; } ret = dev_change_flags(dev, ifr.ifr_flags); break; case SIOCSIFADDR: /* Set interface address (and family) */ if (inet_abc_len(sin->sin_addr.s_addr) < 0) { ret = -EINVAL; break; } if (!ifa) { if ((ifa = inet_alloc_ifa()) == NULL) { ret = -ENOBUFS; 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; inet_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 = inet_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 = inet_set_ifa(dev, ifa); break; case SIOCSIFBRDADDR: /* Set the broadcast address */ if (ifa->ifa_broadcast != sin->sin_addr.s_addr) { inet_del_ifa(in_dev, ifap, 0); ifa->ifa_broadcast = sin->sin_addr.s_addr; inet_insert_ifa(ifa); } break; case SIOCSIFDSTADDR: /* Set the destination address */ if (ifa->ifa_address != sin->sin_addr.s_addr) { if (inet_abc_len(sin->sin_addr.s_addr) < 0) { ret = -EINVAL; break; } inet_del_ifa(in_dev, ifap, 0); ifa->ifa_address = sin->sin_addr.s_addr; inet_insert_ifa(ifa); } break; case SIOCSIFNETMASK: /* Set the netmask for the interface */ /* * The mask we set must be legal. */ if (bad_mask(sin->sin_addr.s_addr, 0)) { ret = -EINVAL; break; } if (ifa->ifa_mask != sin->sin_addr.s_addr) { inet_del_ifa(in_dev, ifap, 0); ifa->ifa_mask = sin->sin_addr.s_addr; ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); inet_insert_ifa(ifa); } break; }done: rtnl_unlock(); dev_probe_unlock(); return ret;rarok: rtnl_unlock(); dev_probe_unlock(); if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return 0;}static intinet_gifconf(struct net_device *dev, char *buf, int len){ struct in_device *in_dev = __in_dev_get(dev); struct in_ifaddr *ifa; struct ifreq ifr; int done=0; if (in_dev==NULL || (ifa=in_dev->ifa_list)==NULL) return 0; for ( ; ifa; ifa = ifa->ifa_next) { if (!buf) { done += sizeof(ifr); continue; } if (len < (int) sizeof(ifr)) return done; 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 = AF_INET; (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local; if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) return -EFAULT; buf += sizeof(struct ifreq); len -= sizeof(struct ifreq); done += sizeof(struct ifreq); } return done;}u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope){ u32 addr = 0; struct in_device *in_dev; read_lock(&inetdev_lock); in_dev = __in_dev_get(dev); if (in_dev == NULL) { read_unlock(&inetdev_lock); return 0; } read_lock(&in_dev->lock); for_primary_ifa(in_dev) { if (ifa->ifa_scope > scope) continue; if (!dst || inet_ifa_match(dst, ifa)) { addr = ifa->ifa_local; break; } if (!addr) addr = ifa->ifa_local; } endfor_ifa(in_dev); read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); if (addr) return addr; /* Not loopback addresses on loopback should be preferred in this case. It is importnat that lo is the first interface in dev_base list. */ read_lock(&dev_base_lock); read_lock(&inetdev_lock); for (dev=dev_base; dev; dev=dev->next) { if ((in_dev=__in_dev_get(dev)) == NULL) continue; read_lock(&in_dev->lock); for_primary_ifa(in_dev) { if (ifa->ifa_scope != RT_SCOPE_LINK && ifa->ifa_scope <= scope) { read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); read_unlock(&dev_base_lock); return ifa->ifa_local; } } endfor_ifa(in_dev); read_unlock(&in_dev->lock); } read_unlock(&inetdev_lock); read_unlock(&dev_base_lock); return 0;}/* * Device notifier */int register_inetaddr_notifier(struct notifier_block *nb){ return notifier_chain_register(&inetaddr_chain, nb);}int unregister_inetaddr_notifier(struct notifier_block *nb){ return notifier_chain_unregister(&inetaddr_chain,nb);}/* Called only under RTNL semaphore */static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get(dev); ASSERT_RTNL(); if (in_dev == NULL) return NOTIFY_DONE; switch (event) { case NETDEV_REGISTER: printk(KERN_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 = inet_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); inet_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; /* MTU falled under 68, disable IP */ case NETDEV_UNREGISTER: inetdev_destroy(in_dev); break; case NETDEV_CHANGENAME: if (in_dev->ifa_list) { struct in_ifaddr *ifa; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); /* Do not notify about label change, this event is not interesting to applications using netlink. */ } break; } return NOTIFY_DONE;}struct notifier_block ip_netdev_notifier={ inetdev_event, NULL, 0};#ifdef CONFIG_RTNETLINKstatic int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event){ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm)); ifm = NLMSG_DATA(nlh); ifm->ifa_family = AF_INET; ifm->ifa_prefixlen = ifa->ifa_prefixlen; ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT; ifm->ifa_scope = ifa->ifa_scope; ifm->ifa_index = ifa->ifa_dev->dev->ifindex; if (ifa->ifa_address) RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address); if (ifa->ifa_local) RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local); if (ifa->ifa_broadcast) RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast); if (ifa->ifa_anycast) RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast); if (ifa->ifa_label[0]) RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label); nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){ int idx, ip_idx; int s_idx, s_ip_idx; struct net_device *dev; struct in_device *in_dev; struct in_ifaddr *ifa; s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; read_lock(&dev_base_lock); for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; if (idx > s_idx) s_ip_idx = 0; read_lock(&inetdev_lock); if ((in_dev = __in_dev_get(dev)) == NULL) { read_unlock(&inetdev_lock); continue; } read_lock(&in_dev->lock); for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; ifa = ifa->ifa_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) { read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); goto done; } } read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); }done: read_unlock(&dev_base_lock); cb->args[0] = idx; cb->args[1] = ip_idx; return skb->len;}static void rtmsg_ifa(int event, struct in_ifaddr * ifa){ struct sk_buff *skb; int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128); skb = alloc_skb(size, GFP_KERNEL); if (!skb) { netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS); return; } if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL); return; } NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR; netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL);}static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX-RTM_BASE+1] ={ { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { inet_rtm_newaddr, NULL, }, { inet_rtm_deladdr, NULL, }, { NULL, inet_dump_ifaddr, }, { NULL, NULL, }, { inet_rtm_newroute, NULL, }, { inet_rtm_delroute, NULL, }, { inet_rtm_getroute, inet_dump_fib, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, },#ifdef CONFIG_IP_MULTIPLE_TABLES { inet_rtm_newrule, NULL, }, { inet_rtm_delrule, NULL, }, { NULL, inet_dump_rules, }, { NULL, NULL, },#else { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, }, { NULL, NULL, },#endif};#endif /* CONFIG_RTNETLINK */#ifdef CONFIG_SYSCTLvoid inet_forward_change(){ struct net_device *dev; int on = ipv4_devconf.forwarding; ipv4_devconf.accept_redirects = !on; ipv4_devconf_dflt.forwarding = on; read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { struct in_device *in_dev; read_lock(&inetdev_lock); in_dev = __in_dev_get(dev); if (in_dev) in_dev->cnf.forwarding = on; read_unlock(&inetdev_lock); } read_unlock(&dev_base_lock); rt_cache_flush(0);}staticint devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp){ int *valp = ctl->data; int val = *valp; int ret; ret = proc_dointvec(ctl, write, filp, buffer, lenp); if (write && *valp != val) { if (valp == &ipv4_devconf.forwarding) inet_forward_change(); else if (valp != &ipv4_devconf_dflt.forwarding) rt_cache_flush(0); } return ret;}static struct devinet_sysctl_table{ struct ctl_table_header *sysctl_header; ctl_table devinet_vars[13]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; ctl_table devinet_root_dir[2];} devinet_sysctl = { NULL, {{NET_IPV4_CONF_FORWARDING, "forwarding", &ipv4_devconf.forwarding, sizeof(int), 0644, NULL, &devinet_sysctl_forward}, {NET_IPV4_CONF_MC_FORWARDING, "mc_forwarding", &ipv4_devconf.mc_forwarding, sizeof(int), 0444, NULL, &proc_dointvec}, {NET_IPV4_CONF_ACCEPT_REDIRECTS, "accept_redirects", &ipv4_devconf.accept_redirects, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_SECURE_REDIRECTS, "secure_redirects", &ipv4_devconf.secure_redirects, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_SHARED_MEDIA, "shared_media", &ipv4_devconf.shared_media, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_RP_FILTER, "rp_filter", &ipv4_devconf.rp_filter, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_SEND_REDIRECTS, "send_redirects", &ipv4_devconf.send_redirects, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, "accept_source_route", &ipv4_devconf.accept_source_route, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_PROXY_ARP, "proxy_arp", &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay", &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_LOG_MARTIANS, "log_martians", &ipv4_devconf.log_martians, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_TAG, "tag", &ipv4_devconf.tag, sizeof(int), 0644, NULL, &proc_dointvec}, {0}}, {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}}, {{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}}, {{NET_IPV4, "ipv4", NULL, 0, 0555, devinet_sysctl.devinet_conf_dir},{0}}, {{CTL_NET, "net", NULL, 0, 0555, devinet_sysctl.devinet_proto_dir},{0}}};static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p){ int i; struct net_device *dev = in_dev ? in_dev->dev : NULL; struct devinet_sysctl_table *t; t = kmalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) return; memcpy(t, &devinet_sysctl, sizeof(*t)); for (i=0; i<sizeof(t->devinet_vars)/sizeof(t->devinet_vars[0])-1; i++) { t->devinet_vars[i].data += (char*)p - (char*)&ipv4_devconf; t->devinet_vars[i].de = NULL; } if (dev) { t->devinet_dev[0].procname = dev->name; t->devinet_dev[0].ctl_name = dev->ifindex; } else { t->devinet_dev[0].procname = "default"; t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT; } t->devinet_dev[0].child = t->devinet_vars; t->devinet_dev[0].de = NULL; t->devinet_conf_dir[0].child = t->devinet_dev; t->devinet_conf_dir[0].de = NULL; t->devinet_proto_dir[0].child = t->devinet_conf_dir; t->devinet_proto_dir[0].de = NULL; t->devinet_root_dir[0].child = t->devinet_proto_dir; t->devinet_root_dir[0].de = NULL; t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0); if (t->sysctl_header == NULL) kfree(t); else p->sysctl = t;}static void devinet_sysctl_unregister(struct ipv4_devconf *p){ if (p->sysctl) { struct devinet_sysctl_table *t = p->sysctl; p->sysctl = NULL; unregister_sysctl_table(t->sysctl_header); kfree(t); }}#endifvoid __init devinet_init(void){ register_gifconf(PF_INET, inet_gifconf); register_netdevice_notifier(&ip_netdev_notifier);#ifdef CONFIG_RTNETLINK rtnetlink_links[PF_INET] = inet_rtnetlink_table;#endif#ifdef CONFIG_SYSCTL devinet_sysctl.sysctl_header = register_sysctl_table(devinet_sysctl.devinet_root_dir, 0); devinet_sysctl_register(NULL, &ipv4_devconf_dflt);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -