From c272dd4672c7b0d2b20f84acb965f1b61694a601 Mon Sep 17 00:00:00 2001 From: Shirley Ma Date: Wed, 14 Jan 2004 23:10:22 -0800 Subject: [PATCH] [IPV6]: Add MIB:ipv6RouterAdvert netlink notification. --- include/linux/rtnetlink.h | 36 +++++++++++++++++++++++++ include/net/ndisc.h | 4 +++ net/ipv6/addrconf.c | 56 +++++++++++++++++++++++++++++++++++++++ net/ipv6/ndisc.c | 1 + 4 files changed, 97 insertions(+) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 6cfd6f2f4a984..eb051105d72f1 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -44,6 +44,8 @@ #define RTM_DELTFILTER (RTM_BASE+29) #define RTM_GETTFILTER (RTM_BASE+30) +#define RTM_NEWRA (RTM_BASE+32) + #define RTM_NEWPREFIX (RTM_BASE+36) #define RTM_GETPREFIX (RTM_BASE+38) @@ -443,6 +445,38 @@ struct rtgenmsg unsigned char rtgen_family; }; +/***************************************************************** + * Route Advertisement specific messages. + * ******/ + +/* struct iframsg + * passes router advertisement specific information + */ + +struct iframsg +{ + unsigned char ifra_family; + unsigned ifra_flags; + int ifra_index; +}; + +enum +{ + IFRA_UNSPEC, + IFRA_LMTU, + IFRA_CACHEINFO +}; + +/* max_adver_interval, min_adver_interval should be gotten from user level */ +struct ifra_cacheinfo { + __u32 hop_limit; + __u32 lifetime; + __u32 reachable_time; + __u32 retrans_time; +}; + +#define IFRA_MAX IFRA_CACHEINFO + /***************************************************************** * Link layer specific messages. ****/ @@ -658,6 +692,8 @@ enum #define RTMGRP_IPV6_PREFIX 0x20000 +#define RTMGRP_IPV6_IFRA 0x10000 + /* End of information exported to user level */ #ifdef __KERNEL__ diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 95684d3363c1b..499eeb8d5337a 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -109,6 +109,10 @@ extern int ndisc_ifinfo_sysctl_change(ctl_table *ctl, extern void inet6_ifinfo_notify(int event, struct inet6_dev *idev); +extern void inet6_ifra_notify(int event, + struct inet6_dev *idev, + struct ra_msg *ra_msg); + static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, struct in6_addr *addr) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d20f6647bc70d..346dc88be972d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2924,6 +2924,62 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_PREFIX, GFP_ATOMIC); } +static int inet6_fill_ifra(struct sk_buff *skb, struct inet6_dev *idev, + struct ra_msg *ra_msg, u32 pid, u32 seq, int event) +{ + struct iframsg *ifra; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + __u32 mtu = idev->dev->mtu; + struct ifra_cacheinfo ci; + + nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifra)); + + if (pid) + nlh->nlmsg_flags |= NLM_F_MULTI; + + ifra = NLMSG_DATA(nlh); + ifra->ifra_family = AF_INET6; + ifra->ifra_index = idev->dev->ifindex; + ifra->ifra_flags = idev->if_flags; + + RTA_PUT(skb, IFRA_LMTU, sizeof(mtu), &mtu); + + ci.hop_limit = ra_msg->icmph.icmp6_hop_limit; + ci.lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); + ci.reachable_time = ntohl(ra_msg->reachable_time); + ci.retrans_time = ntohl(ra_msg->retrans_timer); + RTA_PUT(skb, IFRA_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; +} + +void inet6_ifra_notify(int event, struct inet6_dev *idev, + struct ra_msg *ra_msg) +{ + struct sk_buff *skb; + int size = NLMSG_SPACE(sizeof(struct iframsg)+128); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFRA, ENOBUFS); + return; + } + if (inet6_fill_ifra(skb, idev, ra_msg, 0, 0, event) < 0) { + kfree_skb(skb); + netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFRA, EINVAL); + return; + } + NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_IFRA; + netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFRA, 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, }, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f725744e6d485..08bd069732bfe 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1194,6 +1194,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) out: if (rt) dst_release(&rt->u.dst); + inet6_ifra_notify(RTM_NEWRA, in6_dev, ra_msg); in6_dev_put(in6_dev); } -- 2.53.0