Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 67069
b: refs/heads/master
c: 3191057
h: refs/heads/master
i:
  67067: 550d282
v: v3
  • Loading branch information
Pierre Ynard authored and David S. Miller committed Oct 11, 2007
1 parent 1e69562 commit 5353d49
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 092e9d93b3728d484a4e73df9852dc4002cf9923
refs/heads/master: 31910575a9de61e78065e93846e8e7a4894a18bf
29 changes: 29 additions & 0 deletions trunk/include/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ enum {
RTM_SETNEIGHTBL,
#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL

RTM_NEWNDUSEROPT = 68,
#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT

__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
Expand Down Expand Up @@ -479,6 +482,30 @@ enum
#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))

/********************************************************************
* Neighbor Discovery userland options
****/

struct nduseroptmsg
{
unsigned char nduseropt_family;
unsigned char nduseropt_pad1;
unsigned short nduseropt_opts_len; /* Total length of options */
__u8 nduseropt_icmp_type;
__u8 nduseropt_icmp_code;
unsigned short nduseropt_pad2;
/* Followed by one or more ND options */
};

enum
{
NDUSEROPT_UNSPEC,
NDUSEROPT_SRCADDR,
__NDUSEROPT_MAX
};

#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1)

#ifndef __KERNEL__
/* RTnetlink multicast groups - backwards compatibility for userspace */
#define RTMGRP_LINK 1
Expand Down Expand Up @@ -542,6 +569,8 @@ enum rtnetlink_groups {
#define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX
RTNLGRP_IPV6_RULE,
#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE
RTNLGRP_ND_USEROPT,
#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
Expand Down
1 change: 1 addition & 0 deletions trunk/include/net/ndisc.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum {
ND_OPT_MTU = 5, /* RFC2461 */
__ND_OPT_ARRAY_MAX,
ND_OPT_ROUTE_INFO = 24, /* RFC4191 */
ND_OPT_RDNSS = 25, /* RFC5006 */
__ND_OPT_MAX
};

Expand Down
103 changes: 94 additions & 9 deletions trunk/net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
/*
* Changes:
*
* Pierre Ynard : export userland ND options
* through netlink (RDNSS support)
* Lars Fenneberg : fixed MTU setting on receipt
* of an RA.
*
* Janos Farkas : kmalloc failure checks
* Alexey Kuznetsov : state machine reworked
* and moved to net/core.
Expand Down Expand Up @@ -78,6 +79,9 @@
#include <net/addrconf.h>
#include <net/icmp.h>

#include <net/netlink.h>
#include <linux/rtnetlink.h>

#include <net/flow.h>
#include <net/ip6_checksum.h>
#include <linux/proc_fs.h>
Expand Down Expand Up @@ -161,6 +165,8 @@ struct ndisc_options {
struct nd_opt_hdr *nd_opts_ri;
struct nd_opt_hdr *nd_opts_ri_end;
#endif
struct nd_opt_hdr *nd_useropts;
struct nd_opt_hdr *nd_useropts_end;
};

#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
Expand Down Expand Up @@ -225,6 +231,22 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
}

static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
{
return (opt->nd_opt_type == ND_OPT_RDNSS);
}

static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
struct nd_opt_hdr *end)
{
if (!cur || !end || cur >= end)
return NULL;
do {
cur = ((void *)cur) + (cur->nd_opt_len << 3);
} while(cur < end && !ndisc_is_useropt(cur));
return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL);
}

static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
struct ndisc_options *ndopts)
{
Expand Down Expand Up @@ -267,14 +289,21 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
break;
#endif
default:
/*
* Unknown options must be silently ignored,
* to accommodate future extension to the protocol.
*/
ND_PRINTK2(KERN_NOTICE
"%s(): ignored unsupported option; type=%d, len=%d\n",
__FUNCTION__,
nd_opt->nd_opt_type, nd_opt->nd_opt_len);
if (ndisc_is_useropt(nd_opt)) {
ndopts->nd_useropts_end = nd_opt;
if (!ndopts->nd_useropts)
ndopts->nd_useropts = nd_opt;
} else {
/*
* Unknown options must be silently ignored,
* to accommodate future extension to the
* protocol.
*/
ND_PRINTK2(KERN_NOTICE
"%s(): ignored unsupported option; type=%d, len=%d\n",
__FUNCTION__,
nd_opt->nd_opt_type, nd_opt->nd_opt_len);
}
}
opt_len -= l;
nd_opt = ((void *)nd_opt) + l;
Expand Down Expand Up @@ -984,6 +1013,53 @@ static void ndisc_recv_rs(struct sk_buff *skb)
in6_dev_put(idev);
}

static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
{
struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct nduseroptmsg *ndmsg;
int err;
int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
+ (opt->nd_opt_len << 3));
size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr));

skb = nlmsg_new(msg_size, GFP_ATOMIC);
if (skb == NULL) {
err = -ENOBUFS;
goto errout;
}

nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0);
if (nlh == NULL) {
goto nla_put_failure;
}

ndmsg = nlmsg_data(nlh);
ndmsg->nduseropt_family = AF_INET6;
ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type;
ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code;
ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3;

memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3);

NLA_PUT(skb, NDUSEROPT_SRCADDR, sizeof(struct in6_addr),
&ipv6_hdr(ra)->saddr);
nlmsg_end(skb, nlh);

err = rtnl_notify(skb, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
if (err < 0)
goto errout;

return;

nla_put_failure:
nlmsg_free(skb);
err = -EMSGSIZE;
errout:
rtnl_set_sk_err(RTNLGRP_ND_USEROPT, err);
}

static void ndisc_router_discovery(struct sk_buff *skb)
{
struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
Expand Down Expand Up @@ -1216,6 +1292,15 @@ static void ndisc_router_discovery(struct sk_buff *skb)
}
}

if (ndopts.nd_useropts) {
struct nd_opt_hdr *opt;
for (opt = ndopts.nd_useropts;
opt;
opt = ndisc_next_useropt(opt, ndopts.nd_useropts_end)) {
ndisc_ra_useropt(skb, opt);
}
}

if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
ND_PRINTK2(KERN_WARNING
"ICMPv6 RA: invalid RA options");
Expand Down

0 comments on commit 5353d49

Please sign in to comment.