summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShirley Ma <mashirle@us.ibm.com>2004-01-14 09:01:45 -0800
committerDavid S. Miller <davem@nuts.ninka.net>2004-01-14 09:01:45 -0800
commit60872d54d963eefeb302ebeae15204e4be229c2b (patch)
tree808968ce25fc5a8954ad22085cdcf1ff2ccece31
parent3c1ea2a57f835a46d08b20d72b2c3c8bc4e9c2a0 (diff)
[IPV6]: Add notification for MIB:ipv6Prefix events.
-rw-r--r--include/linux/rtnetlink.h35
-rw-r--r--include/net/if_inet6.h4
-rw-r--r--net/ipv6/addrconf.c63
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, },