Subject: Re: bridged IPv6 packets rewritten with embedded scope IDs
To: None <tech-net@NetBSD.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 03/22/2006 23:26:37
--1LKvkjL3sHcu1TtY
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Wed, Mar 22, 2006 at 10:30:39PM -0600, David Young wrote:
> In NetBSD, the 802.11 hostap bridge has started inserting scope IDs into
> link-local IPv6 addresses before retransmission. The ICMP6 checksum on
> the repeated packet is wrong. A bridge shouldn't be rewriting packets,
> anyway.
>
> I suspect this is fallout from recent changes to scope-ID embedding.
> ip6_input does not take sufficient care to avoid writing to unwriteable
> mbufs such as the shallow mbuf copy produced by the AP bridging code.
> In particular, it does not call m_makewritable before embedding scope
> IDs in the source and destination addresses with in6_setscope.
>
> This packet trace illustrates the problem:
>
> Packet received by AP:
>
> 13:05:19.170044 00:02:6f:20:f6:2e > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 70: fe80::202:6fff:fe20:f62e > ff02::1: [icmp6 sum ok] icmp6: echo request seq 1539 (len 16, hlim 64)
>
> Repeated packet---notice the destination turned from ff02::1 to ff02:5::1:
>
> 13:05:19.170429 00:02:6f:20:f6:2e > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 70: fe80:5::202:6fff:fe20:f62e > ff02:5::1: [bad icmp6 cksum f5ff!] icmp6: echo request seq 1539 (len 16, hlim 64)
>
> AP's reply:
>
> 13:05:19.170562 xx:yy:zz:20:44:12 > 00:02:6f:20:f6:2e, ethertype IPv6 (0x86dd), length 70: fe80::250:43ff:fe20:4412 > fe80::202:6fff:fe20:f62e: [icmp6 sum ok] icmp6: echo reply seq 1539 (len 16, hlim 64)
Here is an (untested) patch that may fix the problem.
Dave
--
David Young OJC Technologies
dyoung@ojctech.com Urbana, IL * (217) 278-3933
--1LKvkjL3sHcu1TtY
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=embed-scope
Index: in6.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6.h,v
retrieving revision 1.52
diff -u -p -u -p -r1.52 in6.h
--- in6.h 16 Feb 2006 20:17:20 -0000 1.52
+++ in6.h 23 Mar 2006 05:14:02 -0000
@@ -359,6 +359,9 @@ extern const struct in6_addr in6addr_lin
((IN6_IS_ADDR_LINKLOCAL(a)) || \
(IN6_IS_ADDR_MC_LINKLOCAL(a)))
+#define IN6_IS_SCOPE_EMBEDDABLE(__a) \
+ (IN6_IS_SCOPE_LINKLOCAL(__a) || IN6_IS_ADDR_MC_INTFACELOCAL(__a))
+
#define IFA6_IS_DEPRECATED(a) \
((a)->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME && \
(u_int32_t)((time.tv_sec - (a)->ia6_updatetime)) > \
Index: ip6_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.83
diff -u -p -u -p -r1.83 ip6_input.c
--- ip6_input.c 5 Mar 2006 23:47:08 -0000 1.83
+++ ip6_input.c 23 Mar 2006 05:14:02 -0000
@@ -234,7 +234,7 @@ void
ip6_input(m)
struct mbuf *m;
{
- struct ip6_hdr *ip6;
+ struct ip6_hdr *ip6, *tmp;
int off = sizeof(struct ip6_hdr), nest;
u_int32_t plen;
u_int32_t rtalert = ~0;
@@ -305,7 +305,24 @@ ip6_input(m)
}
}
- ip6 = mtod(m, struct ip6_hdr *);
+ /* If we will embed a scope identifier in either the source or
+ * destination address or both, then make them both writable.
+ * We have to do this because m may be a shallow copy of a packet
+ * that a link-layer bridge will repeat.
+ */
+ tmp = mtod(m, struct ip6_hdr *);
+ if (!(IN6_IS_SCOPE_EMBEDDABLE(&tmp->ip6_src) ||
+ IN6_IS_SCOPE_EMBEDDABLE(&tmp->ip6_dst)))
+ ip6 = tmp;
+ else if (m_makewritable(&m, offsetof(struct ip6_hdr, ip6_src),
+ sizeof(struct ip6_hdr) - offsetof(struct ip6_hdr, ip6_src),
+ M_DONTWAIT) != 0) {
+ struct ifnet *inifp = m->m_pkthdr.rcvif;
+ ip6stat.ip6s_toosmall++; /* XXXDCY new stat */
+ in6_ifstat_inc(inifp, ifs6_in_hdrerr); /* XXX DCY new stat */
+ goto bad;
+ } else
+ ip6 = mtod(m, struct ip6_hdr *);
if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
ip6stat.ip6s_badvers++;
Index: scope6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/scope6.c,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 scope6.c
--- scope6.c 5 Mar 2006 01:28:51 -0000 1.2
+++ scope6.c 23 Mar 2006 05:14:02 -0000
@@ -427,7 +427,7 @@ in6_setscope(struct in6_addr *in6, struc
if (ret_id != NULL)
*ret_id = zoneid;
- if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6))
+ if (IN6_IS_SCOPE_EMBEDDABLE(in6))
in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
return (0);
--1LKvkjL3sHcu1TtY--