]> git.hungrycats.org Git - linux/commitdiff
[IPV6]: Add notification for MIB:ipv6Prefix events.
authorShirley Ma <mashirle@us.ibm.com>
Wed, 14 Jan 2004 17:01:45 +0000 (09:01 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Wed, 14 Jan 2004 17:01:45 +0000 (09:01 -0800)
include/linux/rtnetlink.h
include/net/if_inet6.h
net/ipv6/addrconf.c

index db1966e24462ffb21de2401083d331460c155a69..6cfd6f2f4a984a10e778ce20e4b67b3318254d81 100644 (file)
 #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__
index 4ef8526494d25a5fc7fed2ee238b28a3bb489e81..48280b138cb9a590f385b0a200f89ee0bd2eb2ab 100644 (file)
 #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 
index 237a4c9336809b2f0a73863f17166e254a0d6846..6f1dc6fba0a48fd21afe587d5d0f6adf583cc7b5 100644 (file)
@@ -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, },