Commit 75669bcc authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by David S. Miller

IPv6 neighbour discovery fixes:

- Answer to neighbour solicitations on SIT, otherwise
  freebsd does not want to talk to us.
- Fix wrong structure nd_msg and... use it :-)
parent d1818806
...@@ -42,11 +42,7 @@ extern struct neigh_table nd_tbl; ...@@ -42,11 +42,7 @@ extern struct neigh_table nd_tbl;
struct nd_msg { struct nd_msg {
struct icmp6hdr icmph; struct icmp6hdr icmph;
struct in6_addr target; struct in6_addr target;
struct { __u8 opt[0];
__u8 opt_type;
__u8 opt_len;
__u8 link_addr[MAX_ADDR_LEN];
} opt;
}; };
struct ra_msg { struct ra_msg {
......
...@@ -361,7 +361,7 @@ void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ...@@ -361,7 +361,7 @@ void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
ipv6_addr_copy(&msg->target, solicited_addr); ipv6_addr_copy(&msg->target, solicited_addr);
if (inc_opt) if (inc_opt)
ndisc_fill_option((void*)&msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len); ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
/* checksum */ /* checksum */
msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len, msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len,
...@@ -422,7 +422,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ...@@ -422,7 +422,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
ipv6_addr_copy(&msg->target, solicit); ipv6_addr_copy(&msg->target, solicit);
if (send_llinfo) if (send_llinfo)
ndisc_fill_option((void*)&msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len); ndisc_fill_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
/* checksum */ /* checksum */
msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
...@@ -572,6 +572,11 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -572,6 +572,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
printk(KERN_WARNING "ICMP RA: source address is not linklocal\n"); printk(KERN_WARNING "ICMP RA: source address is not linklocal\n");
return; return;
} }
if (optlen < 0) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP RA: packet too short\n");
return;
}
/* /*
* set the RA_RECV flag in the interface * set the RA_RECV flag in the interface
...@@ -928,7 +933,7 @@ ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb) ...@@ -928,7 +933,7 @@ ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
u8 *opt; u8 *opt;
opt = skb->h.raw; opt = skb->h.raw;
opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr); opt += sizeof(struct nd_msg);
opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR); opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev); return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
...@@ -936,12 +941,11 @@ ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb) ...@@ -936,12 +941,11 @@ ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb) static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
{ {
struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
u8 *opt; u8 *opt;
struct nd_msg *msg = (struct nd_msg*) skb->h.raw;
opt = skb->h.raw; opt = ndisc_find_option(msg->opt, skb->dev->addr_len+2,
opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr); skb->tail - msg->opt, ND_OPT_TARGET_LL_ADDR);
opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_TARGET_LL_ADDR);
return neigh_update(neigh, opt, return neigh_update(neigh, opt,
msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
...@@ -962,7 +966,6 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -962,7 +966,6 @@ int ndisc_rcv(struct sk_buff *skb)
struct nd_msg *msg = (struct nd_msg *) skb->h.raw; struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
struct neighbour *neigh; struct neighbour *neigh;
struct inet6_ifaddr *ifp; struct inet6_ifaddr *ifp;
unsigned int payload_len;
__skb_push(skb, skb->data-skb->h.raw); __skb_push(skb, skb->data-skb->h.raw);
...@@ -985,11 +988,9 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -985,11 +988,9 @@ int ndisc_rcv(struct sk_buff *skb)
* (Some checking in ndisc_find_option) * (Some checking in ndisc_find_option)
*/ */
payload_len = ntohs(skb->nh.ipv6h->payload_len);
switch (msg->icmph.icmp6_type) { switch (msg->icmph.icmp6_type) {
case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_SOLICITATION:
/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */ if (skb->len < sizeof(struct nd_msg)) {
if (payload_len < 8+16) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: packet too short\n"); printk(KERN_WARNING "ICMP NS: packet too short\n");
return 0; return 0;
...@@ -1069,11 +1070,12 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1069,11 +1070,12 @@ int ndisc_rcv(struct sk_buff *skb)
neigh = ndisc_recv_ns(saddr, skb); neigh = ndisc_recv_ns(saddr, skb);
if (neigh) { if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &ifp->addr, ndisc_send_na(dev, neigh, saddr, &ifp->addr,
ifp->idev->cnf.forwarding, 1, ifp->idev->cnf.forwarding, 1,
ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
1); 1);
if (neigh)
neigh_release(neigh); neigh_release(neigh);
} }
} }
...@@ -1118,8 +1120,7 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1118,8 +1120,7 @@ int ndisc_rcv(struct sk_buff *skb)
return 0; return 0;
case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_NEIGHBOUR_ADVERTISEMENT:
/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */ if (skb->len < sizeof(struct nd_msg)) {
if (payload_len < 16+8 ) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "ICMP NA: packet too short\n"); printk(KERN_WARNING "ICMP NA: packet too short\n");
return 0; return 0;
...@@ -1180,35 +1181,12 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1180,35 +1181,12 @@ int ndisc_rcv(struct sk_buff *skb)
break; break;
case NDISC_ROUTER_ADVERTISEMENT: case NDISC_ROUTER_ADVERTISEMENT:
/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
if (payload_len < 8+4+4) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP RA: packet too short\n");
return 0;
}
ndisc_router_discovery(skb); ndisc_router_discovery(skb);
break; break;
case NDISC_REDIRECT: case NDISC_REDIRECT:
/* XXX: import nd_redirect from glibc netinet/icmp6.h */
if (payload_len < 8+16+16) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP redirect: packet too short\n");
return 0;
}
ndisc_redirect_rcv(skb); ndisc_redirect_rcv(skb);
break; break;
case NDISC_ROUTER_SOLICITATION:
/* No RS support in the kernel, but we do some required checks */
/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
if (payload_len < 8) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP RS: packet too short\n");
return 0;
}
break;
}; };
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment