diff options
| author | Shirley Ma <mashirle@us.ibm.com> | 2004-01-14 09:01:45 -0800 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2004-01-14 09:01:45 -0800 |
| commit | 60872d54d963eefeb302ebeae15204e4be229c2b (patch) | |
| tree | 808968ce25fc5a8954ad22085cdcf1ff2ccece31 | |
| parent | 3c1ea2a57f835a46d08b20d72b2c3c8bc4e9c2a0 (diff) | |
[IPV6]: Add notification for MIB:ipv6Prefix events.
| -rw-r--r-- | include/linux/rtnetlink.h | 35 | ||||
| -rw-r--r-- | include/net/if_inet6.h | 4 | ||||
| -rw-r--r-- | net/ipv6/addrconf.c | 63 |
3 files changed, 101 insertions, 1 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index db1966e24462..6cfd6f2f4a98 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -44,7 +44,10 @@ #define RTM_DELTFILTER (RTM_BASE+29) #define RTM_GETTFILTER (RTM_BASE+30) -#define RTM_MAX (RTM_BASE+31) +#define RTM_NEWPREFIX (RTM_BASE+36) +#define RTM_GETPREFIX (RTM_BASE+38) + +#define RTM_MAX (RTM_BASE+39) /* Generic structure for encapsulation of optional route information. @@ -459,6 +462,34 @@ struct ifinfomsg unsigned ifi_change; /* IFF_* change mask */ }; +/******************************************************************** + * prefix information + ****/ + +struct prefixmsg +{ + unsigned char prefix_family; + int prefix_ifindex; + unsigned char prefix_type; + unsigned char prefix_len; + unsigned char prefix_flags; +}; + +enum +{ + PREFIX_UNSPEC, + PREFIX_ADDRESS, + PREFIX_CACHEINFO, +}; + +#define PREFIX_MAX PREFIX_CACHEINFO + +struct prefix_cacheinfo +{ + __u32 preferred_time; + __u32 valid_time; +}; + /* The struct should be in sync with struct net_device_stats */ struct rtnl_link_stats { @@ -625,6 +656,8 @@ enum #define RTMGRP_DECnet_IFADDR 0x1000 #define RTMGRP_DECnet_ROUTE 0x4000 +#define RTMGRP_IPV6_PREFIX 0x20000 + /* End of information exported to user level */ #ifdef __KERNEL__ diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 4ef8526494d2..48280b138cb9 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -25,6 +25,10 @@ #define IF_RA_RCVD 0x20 #define IF_RS_SENT 0x10 +/* prefix flags */ +#define IF_PREFIX_ONLINK 0x01 +#define IF_PREFIX_AUTOCONF 0x02 + #ifdef __KERNEL__ struct inet6_ifaddr diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 237a4c933680..6f1dc6fba0a4 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -138,6 +138,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp); static void addrconf_rs_timer(unsigned long data); static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); +static void inet6_prefix_notify(int event, struct inet6_dev *idev, + struct prefix_info *pinfo); static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); static struct notifier_block *inet6addr_chain; @@ -1492,6 +1494,7 @@ ok: addrconf_verify(0); } } + inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo); in6_dev_put(in6_dev); } @@ -2854,6 +2857,66 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFINFO, GFP_ATOMIC); } +static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, + struct prefix_info *pinfo, u32 pid, u32 seq, int event) +{ + struct prefixmsg *pmsg; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + struct prefix_cacheinfo ci; + + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*pmsg)); + + if (pid) + nlh->nlmsg_flags |= NLM_F_MULTI; + + pmsg = NLMSG_DATA(nlh); + pmsg->prefix_family = AF_INET6; + pmsg->prefix_ifindex = idev->dev->ifindex; + pmsg->prefix_len = pinfo->prefix_len; + pmsg->prefix_type = pinfo->type; + + pmsg->prefix_flags = 0; + if (pinfo->onlink) + pmsg->prefix_flags |= IF_PREFIX_ONLINK; + if (pinfo->autoconf) + pmsg->prefix_flags |= IF_PREFIX_AUTOCONF; + + RTA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix); + + ci.preferred_time = ntohl(pinfo->prefered); + ci.valid_time = ntohl(pinfo->valid); + RTA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci); + + nlh->nlmsg_len = skb->tail - b; + return skb->len; + +nlmsg_failure: +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static void inet6_prefix_notify(int event, struct inet6_dev *idev, + struct prefix_info *pinfo) +{ + struct sk_buff *skb; + int size = NLMSG_SPACE(sizeof(struct prefixmsg)+128); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + netlink_set_err(rtnl, 0, RTMGRP_IPV6_PREFIX, ENOBUFS); + return; + } + if (inet6_fill_prefix(skb, idev, pinfo, 0, 0, event) < 0) { + kfree_skb(skb); + netlink_set_err(rtnl, 0, RTMGRP_IPV6_PREFIX, EINVAL); + return; + } + NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_PREFIX; + netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_PREFIX, GFP_ATOMIC); +} + static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = { [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, |
