📄 devinet.c
字号:
/* devinet.c * linqianghe@163.com * 2006-10-15 */#include "devinet.h"#include "log.h"#include "af_inet.h"#include "neighbour.h"#include "igmp.h"#include <linux/inetdevice.h>#include <linux/rtnetlink.h>#include <linux/in.h>extern struct neigh_table myarp_tbl;static struct notifier_block *myinetaddr_chain;static struct ipv4_devconf myipv4_devconf_dflt = { .accept_redirects = 1, .send_redirects = 1, .secure_redirects = 1, .shared_media = 1, .accept_source_route = 1,};static struct in_ifaddr *myinet_alloc_ifa(void){ struct in_ifaddr *ifa = kmalloc( sizeof(*ifa), GFP_KERNEL ); if( ifa ){ memset( ifa, 0, sizeof(*ifa) ); INIT_RCU_HEAD(&ifa->rcu_head); } return ifa;}struct in_device *myinetdev_init( struct net_device *dev ){ struct in_device *in_dev; ASSERT_RTNL(); in_dev = kmalloc( sizeof(*in_dev), GFP_KERNEL ); if( !in_dev ) goto out; memset(in_dev, 0, sizeof(*in_dev)); INIT_RCU_HEAD(&in_dev->rcu_head); memcpy( &in_dev->cnf, &myipv4_devconf_dflt, sizeof(in_dev->cnf) ); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; if( (in_dev->arp_parms = myneigh_parms_alloc(dev, &myarp_tbl)) == NULL ) goto out_kfree; dev_hold(dev);//#ifdef CONFIG_SYSCTL// neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,// NET_IPV4_NEIGH, "ipv4", NULL, NULL);//#endif in_dev_hold(in_dev); rcu_assign_pointer(dev->ip_ptr, in_dev);//#ifdef CONFIG_SYSCTL// devinet_sysctl_register(in_dev, &in_dev->cnf);//#endif myip_mc_init_dev(in_dev); if( dev->flags & IFF_UP ) myip_mc_up( in_dev );out: return in_dev;out_kfree: kfree( in_dev ); in_dev = NULL; goto out;}static void myinet_rcu_free_ifa( struct rcu_head *head ){ struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head); if (ifa->ifa_dev) in_dev_put(ifa->ifa_dev); kfree(ifa);}static inline void myinet_free_ifa( struct in_ifaddr *ifa ){ call_rcu( &ifa->rcu_head, myinet_rcu_free_ifa );}static int myinet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 pid, u32 seq, int event, unsigned int flags){ struct ifaddrmsg *ifm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); ifm = NLMSG_DATA(nlh); ifm->ifa_family = MY_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 void myrtmsg_ifa( int event, struct in_ifaddr* ifa ){ int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128); struct sk_buff *skb = alloc_skb(size, GFP_KERNEL); if (!skb) netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS); else if( myinet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0 ){ kfree_skb(skb); netlink_set_err( rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL ); }else{ PR_DEBUG( "netlink_broadcast!!\n" ); netlink_broadcast( rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL ); }}static int myinet_insert_ifa(struct in_ifaddr *ifa){ struct in_device *in_dev = ifa->ifa_dev; struct in_ifaddr *ifa1, **ifap, **last_primary; ASSERT_RTNL(); if( !ifa->ifa_local ){ myinet_free_ifa( ifa ); return 0; } ifa->ifa_flags &= ~IFA_F_SECONDARY; last_primary = &in_dev->ifa_list; for( ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; ifap = &ifa1->ifa_next ){ if( !(ifa1->ifa_flags & IFA_F_SECONDARY) && ifa->ifa_scope <= ifa1->ifa_scope ) last_primary = &ifa1->ifa_next; if( ifa1->ifa_mask == ifa->ifa_mask && inet_ifa_match(ifa1->ifa_address, ifa) ){ if( ifa1->ifa_local == ifa->ifa_local ){ myinet_free_ifa(ifa); return -EEXIST; } if( ifa1->ifa_scope != ifa->ifa_scope ){ myinet_free_ifa(ifa); return -EINVAL; } ifa->ifa_flags |= IFA_F_SECONDARY; } } if( !(ifa->ifa_flags & IFA_F_SECONDARY) ){ net_srandom( ifa->ifa_local ); ifap = last_primary; } ifa->ifa_next = *ifap; *ifap = ifa; //myrtmsg_ifa( RTM_NEWADDR, ifa ); notifier_call_chain( &myinetaddr_chain, NETDEV_UP, ifa ); return 0;}static void myinetdev_destroy(struct in_device *in_dev);static void myinet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy){ struct in_ifaddr *promote = NULL; struct in_ifaddr *ifa, *ifa1 = *ifap; struct in_ifaddr *last_prim = in_dev->ifa_list; struct in_ifaddr *prev_prom = NULL; //int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); int do_promote = 0; ASSERT_RTNL(); if( !(ifa1->ifa_flags & IFA_F_SECONDARY) ){ struct in_ifaddr **ifap1 = &ifa1->ifa_next; while ((ifa = *ifap1) != NULL) { if( !(ifa->ifa_flags & IFA_F_SECONDARY) && ifa1->ifa_scope <= ifa->ifa_scope ) last_prim = ifa; if( !(ifa->ifa_flags & IFA_F_SECONDARY) || ifa1->ifa_mask != ifa->ifa_mask || !inet_ifa_match(ifa1->ifa_address, ifa)) { ifap1 = &ifa->ifa_next; prev_prom = ifa; continue; } if (!do_promote) { *ifap1 = ifa->ifa_next; myrtmsg_ifa(RTM_DELADDR, ifa); notifier_call_chain( &myinetaddr_chain, NETDEV_DOWN, ifa ); myinet_free_ifa(ifa); }else{ promote = ifa; break; } } } *ifap = ifa1->ifa_next; myrtmsg_ifa(RTM_DELADDR, ifa1); notifier_call_chain( &myinetaddr_chain, NETDEV_DOWN, ifa1 ); if( promote ){ if( prev_prom ){ prev_prom->ifa_next = promote->ifa_next; promote->ifa_next = last_prim->ifa_next; last_prim->ifa_next = promote; } promote->ifa_flags &= ~IFA_F_SECONDARY; myrtmsg_ifa(RTM_NEWADDR, promote); notifier_call_chain( &myinetaddr_chain, NETDEV_UP, promote ); for( ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next ){ if (ifa1->ifa_mask != ifa->ifa_mask || !inet_ifa_match(ifa1->ifa_address, ifa)) continue; //fib_add_ifaddr(ifa); } } if( destroy ){ myinet_free_ifa(ifa1); if( !in_dev->ifa_list ) myinetdev_destroy( in_dev ); }}void myarp_ifdown( struct net_device *dev ){ myneigh_ifdown( &myarp_tbl, dev );}void myin_dev_finish_destroy(struct in_device *idev){ struct net_device *dev = idev->dev; BUG_TRAP(!idev->ifa_list); BUG_TRAP(!idev->mc_list); PR_DEBUG( "in_dev_finish_destroy: %p=%s\n", idev, dev ? dev->name : "NIL"); dev_put(dev); if (!idev->dead) PR_DEBUG("Freeing alive in_device %p\n", idev); else kfree(idev);}static void myin_dev_rcu_put(struct rcu_head *head){ struct in_device *idev = container_of(head, struct in_device, rcu_head); myin_dev_put(idev);}static void myinetdev_destroy(struct in_device *in_dev){ struct in_ifaddr *ifa; struct net_device *dev; ASSERT_RTNL(); dev = in_dev->dev; if( dev == &loopback_dev ) return; in_dev->dead = 1; //ip_mc_destroy_dev(in_dev); while( (ifa = in_dev->ifa_list) != NULL ){ myinet_del_ifa(in_dev, &in_dev->ifa_list, 0); myinet_free_ifa(ifa); }/*#ifdef CONFIG_SYSCTL devinet_sysctl_unregister(&in_dev->cnf);#endif*/ dev->ip_ptr = NULL;/*#ifdef CONFIG_SYSCTL neigh_sysctl_unregister(in_dev->arp_parms);#endif*/ myneigh_parms_release( &myarp_tbl, in_dev->arp_parms ); myarp_ifdown( dev ); call_rcu( &in_dev->rcu_head, myin_dev_rcu_put ); }static void myinetdev_changename(struct net_device *dev, struct in_device *in_dev){ struct in_ifaddr *ifa; int named = 0; for( ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next ){ char old[IFNAMSIZ], *dot; memcpy(old, ifa->ifa_label, IFNAMSIZ); memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); if( named++ == 0 ) continue; dot = strchr(ifa->ifa_label, ':'); if (dot == NULL) { sprintf(old, ":%d", named); dot = old; } if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) { strcat(ifa->ifa_label, dot); } else { strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot); } } }static int myinetdev_event(struct notifier_block *this, unsigned long event, void *ptr){ struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); ASSERT_RTNL();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -