Fri Dec 16 00:58:00 2011 UTC ()
Take softnet_lock and kernel lock in frag6_slowtimo and frag6_fasttimo,
similar to how it's done with other protocols.

If we don't do this sending ICMPv6 messages in this path can cause races
in network interface drivers.


(jakllsch)
diff -r1.50 -r1.51 src/sys/netinet6/frag6.c

cvs diff -r1.50 -r1.51 src/sys/netinet6/frag6.c (switch to unified diff)

--- src/sys/netinet6/frag6.c 2011/11/04 00:22:33 1.50
+++ src/sys/netinet6/frag6.c 2011/12/16 00:57:59 1.51
@@ -1,721 +1,733 @@ @@ -1,721 +1,733 @@
1/* $NetBSD: frag6.c,v 1.50 2011/11/04 00:22:33 zoltan Exp $ */ 1/* $NetBSD: frag6.c,v 1.51 2011/12/16 00:57:59 jakllsch Exp $ */
2/* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */ 2/* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors 16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software 17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission. 18 * without specific prior written permission.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.50 2011/11/04 00:22:33 zoltan Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.51 2011/12/16 00:57:59 jakllsch Exp $");
35 35
36#include <sys/param.h> 36#include <sys/param.h>
37#include <sys/systm.h> 37#include <sys/systm.h>
38#include <sys/malloc.h> 38#include <sys/malloc.h>
39#include <sys/mbuf.h> 39#include <sys/mbuf.h>
40#include <sys/domain.h> 40#include <sys/domain.h>
41#include <sys/protosw.h> 41#include <sys/protosw.h>
42#include <sys/socket.h> 42#include <sys/socket.h>
43#include <sys/socketvar.h> 43#include <sys/socketvar.h>
44#include <sys/errno.h> 44#include <sys/errno.h>
45#include <sys/time.h> 45#include <sys/time.h>
46#include <sys/kernel.h> 46#include <sys/kernel.h>
47#include <sys/syslog.h> 47#include <sys/syslog.h>
48 48
49#include <net/if.h> 49#include <net/if.h>
50#include <net/route.h> 50#include <net/route.h>
51 51
52#include <netinet/in.h> 52#include <netinet/in.h>
53#include <netinet/in_var.h> 53#include <netinet/in_var.h>
54#include <netinet/ip6.h> 54#include <netinet/ip6.h>
55#include <netinet6/ip6_var.h> 55#include <netinet6/ip6_var.h>
56#include <netinet6/ip6_private.h> 56#include <netinet6/ip6_private.h>
57#include <netinet/icmp6.h> 57#include <netinet/icmp6.h>
58 58
59#include <net/net_osdep.h> 59#include <net/net_osdep.h>
60 60
61static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *); 61static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *);
62static void frag6_deq(struct ip6asfrag *); 62static void frag6_deq(struct ip6asfrag *);
63static void frag6_insque(struct ip6q *, struct ip6q *); 63static void frag6_insque(struct ip6q *, struct ip6q *);
64static void frag6_remque(struct ip6q *); 64static void frag6_remque(struct ip6q *);
65static void frag6_freef(struct ip6q *); 65static void frag6_freef(struct ip6q *);
66 66
67static int frag6_drainwanted; 67static int frag6_drainwanted;
68 68
69u_int frag6_nfragpackets; 69u_int frag6_nfragpackets;
70u_int frag6_nfrags; 70u_int frag6_nfrags;
71struct ip6q ip6q; /* ip6 reassemble queue */ 71struct ip6q ip6q; /* ip6 reassemble queue */
72 72
73static kmutex_t frag6_lock; 73static kmutex_t frag6_lock;
74 74
75#ifndef offsetof /* XXX */ 75#ifndef offsetof /* XXX */
76#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 76#define offsetof(type, member) ((size_t)(&((type *)0)->member))
77#endif 77#endif
78 78
79/* 79/*
80 * Initialise reassembly queue and fragment identifier. 80 * Initialise reassembly queue and fragment identifier.
81 */ 81 */
82void 82void
83frag6_init(void) 83frag6_init(void)
84{ 84{
85 85
86 ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q; 86 ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
87 mutex_init(&frag6_lock, MUTEX_DEFAULT, IPL_NET); 87 mutex_init(&frag6_lock, MUTEX_DEFAULT, IPL_NET);
88} 88}
89 89
90/* 90/*
91 * In RFC2460, fragment and reassembly rule do not agree with each other, 91 * In RFC2460, fragment and reassembly rule do not agree with each other,
92 * in terms of next header field handling in fragment header. 92 * in terms of next header field handling in fragment header.
93 * While the sender will use the same value for all of the fragmented packets, 93 * While the sender will use the same value for all of the fragmented packets,
94 * receiver is suggested not to check the consistency. 94 * receiver is suggested not to check the consistency.
95 * 95 *
96 * fragment rule (p20): 96 * fragment rule (p20):
97 * (2) A Fragment header containing: 97 * (2) A Fragment header containing:
98 * The Next Header value that identifies the first header of 98 * The Next Header value that identifies the first header of
99 * the Fragmentable Part of the original packet. 99 * the Fragmentable Part of the original packet.
100 * -> next header field is same for all fragments 100 * -> next header field is same for all fragments
101 * 101 *
102 * reassembly rule (p21): 102 * reassembly rule (p21):
103 * The Next Header field of the last header of the Unfragmentable 103 * The Next Header field of the last header of the Unfragmentable
104 * Part is obtained from the Next Header field of the first 104 * Part is obtained from the Next Header field of the first
105 * fragment's Fragment header. 105 * fragment's Fragment header.
106 * -> should grab it from the first fragment only 106 * -> should grab it from the first fragment only
107 * 107 *
108 * The following note also contradicts with fragment rule - noone is going to 108 * The following note also contradicts with fragment rule - noone is going to
109 * send different fragment with different next header field. 109 * send different fragment with different next header field.
110 * 110 *
111 * additional note (p22): 111 * additional note (p22):
112 * The Next Header values in the Fragment headers of different 112 * The Next Header values in the Fragment headers of different
113 * fragments of the same original packet may differ. Only the value 113 * fragments of the same original packet may differ. Only the value
114 * from the Offset zero fragment packet is used for reassembly. 114 * from the Offset zero fragment packet is used for reassembly.
115 * -> should grab it from the first fragment only 115 * -> should grab it from the first fragment only
116 * 116 *
117 * There is no explicit reason given in the RFC. Historical reason maybe? 117 * There is no explicit reason given in the RFC. Historical reason maybe?
118 */ 118 */
119/* 119/*
120 * Fragment input 120 * Fragment input
121 */ 121 */
122static int 122static int
123frag6_in(struct mbuf **mp, int *offp) 123frag6_in(struct mbuf **mp, int *offp)
124{ 124{
125 struct rtentry *rt; 125 struct rtentry *rt;
126 struct mbuf *m = *mp, *t; 126 struct mbuf *m = *mp, *t;
127 struct ip6_hdr *ip6; 127 struct ip6_hdr *ip6;
128 struct ip6_frag *ip6f; 128 struct ip6_frag *ip6f;
129 struct ip6q *q6; 129 struct ip6q *q6;
130 struct ip6asfrag *af6, *ip6af, *af6dwn; 130 struct ip6asfrag *af6, *ip6af, *af6dwn;
131 int offset = *offp, nxt, i, next; 131 int offset = *offp, nxt, i, next;
132 int first_frag = 0; 132 int first_frag = 0;
133 int fragoff, frgpartlen; /* must be larger than u_int16_t */ 133 int fragoff, frgpartlen; /* must be larger than u_int16_t */
134 struct ifnet *dstifp; 134 struct ifnet *dstifp;
135 static struct route ro; 135 static struct route ro;
136 union { 136 union {
137 struct sockaddr dst; 137 struct sockaddr dst;
138 struct sockaddr_in6 dst6; 138 struct sockaddr_in6 dst6;
139 } u; 139 } u;
140 140
141 ip6 = mtod(m, struct ip6_hdr *); 141 ip6 = mtod(m, struct ip6_hdr *);
142 IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); 142 IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
143 if (ip6f == NULL) 143 if (ip6f == NULL)
144 return -1; 144 return -1;
145 145
146 dstifp = NULL; 146 dstifp = NULL;
147 /* find the destination interface of the packet. */ 147 /* find the destination interface of the packet. */
148 sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0); 148 sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0);
149 if ((rt = rtcache_lookup(&ro, &u.dst)) != NULL && rt->rt_ifa != NULL) 149 if ((rt = rtcache_lookup(&ro, &u.dst)) != NULL && rt->rt_ifa != NULL)
150 dstifp = ((struct in6_ifaddr *)rt->rt_ifa)->ia_ifp; 150 dstifp = ((struct in6_ifaddr *)rt->rt_ifa)->ia_ifp;
151 151
152 /* jumbo payload can't contain a fragment header */ 152 /* jumbo payload can't contain a fragment header */
153 if (ip6->ip6_plen == 0) { 153 if (ip6->ip6_plen == 0) {
154 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); 154 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
155 in6_ifstat_inc(dstifp, ifs6_reass_fail); 155 in6_ifstat_inc(dstifp, ifs6_reass_fail);
156 return -1; 156 return -1;
157 } 157 }
158 158
159 /* 159 /*
160 * check whether fragment packet's fragment length is 160 * check whether fragment packet's fragment length is
161 * multiple of 8 octets. 161 * multiple of 8 octets.
162 * sizeof(struct ip6_frag) == 8 162 * sizeof(struct ip6_frag) == 8
163 * sizeof(struct ip6_hdr) = 40 163 * sizeof(struct ip6_hdr) = 40
164 */ 164 */
165 if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) && 165 if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
166 (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) { 166 (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
167 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 167 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
168 offsetof(struct ip6_hdr, ip6_plen)); 168 offsetof(struct ip6_hdr, ip6_plen));
169 in6_ifstat_inc(dstifp, ifs6_reass_fail); 169 in6_ifstat_inc(dstifp, ifs6_reass_fail);
170 return -1; 170 return -1;
171 } 171 }
172 172
173 IP6_STATINC(IP6_STAT_FRAGMENTS); 173 IP6_STATINC(IP6_STAT_FRAGMENTS);
174 in6_ifstat_inc(dstifp, ifs6_reass_reqd); 174 in6_ifstat_inc(dstifp, ifs6_reass_reqd);
175 175
176 /* offset now points to data portion */ 176 /* offset now points to data portion */
177 offset += sizeof(struct ip6_frag); 177 offset += sizeof(struct ip6_frag);
178 178
179 mutex_enter(&frag6_lock); 179 mutex_enter(&frag6_lock);
180 180
181 /* 181 /*
182 * Enforce upper bound on number of fragments. 182 * Enforce upper bound on number of fragments.
183 * If maxfrag is 0, never accept fragments. 183 * If maxfrag is 0, never accept fragments.
184 * If maxfrag is -1, accept all fragments without limitation. 184 * If maxfrag is -1, accept all fragments without limitation.
185 */ 185 */
186 if (ip6_maxfrags < 0) 186 if (ip6_maxfrags < 0)
187 ; 187 ;
188 else if (frag6_nfrags >= (u_int)ip6_maxfrags) 188 else if (frag6_nfrags >= (u_int)ip6_maxfrags)
189 goto dropfrag; 189 goto dropfrag;
190 190
191 for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) 191 for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
192 if (ip6f->ip6f_ident == q6->ip6q_ident && 192 if (ip6f->ip6f_ident == q6->ip6q_ident &&
193 IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && 193 IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
194 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst)) 194 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
195 break; 195 break;
196 196
197 if (q6 == &ip6q) { 197 if (q6 == &ip6q) {
198 /* 198 /*
199 * the first fragment to arrive, create a reassembly queue. 199 * the first fragment to arrive, create a reassembly queue.
200 */ 200 */
201 first_frag = 1; 201 first_frag = 1;
202 202
203 /* 203 /*
204 * Enforce upper bound on number of fragmented packets 204 * Enforce upper bound on number of fragmented packets
205 * for which we attempt reassembly; 205 * for which we attempt reassembly;
206 * If maxfragpackets is 0, never accept fragments. 206 * If maxfragpackets is 0, never accept fragments.
207 * If maxfragpackets is -1, accept all fragments without 207 * If maxfragpackets is -1, accept all fragments without
208 * limitation. 208 * limitation.
209 */ 209 */
210 if (ip6_maxfragpackets < 0) 210 if (ip6_maxfragpackets < 0)
211 ; 211 ;
212 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) 212 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
213 goto dropfrag; 213 goto dropfrag;
214 frag6_nfragpackets++; 214 frag6_nfragpackets++;
215 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE, 215 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
216 M_DONTWAIT); 216 M_DONTWAIT);
217 if (q6 == NULL) 217 if (q6 == NULL)
218 goto dropfrag; 218 goto dropfrag;
219 memset(q6, 0, sizeof(*q6)); 219 memset(q6, 0, sizeof(*q6));
220 frag6_insque(q6, &ip6q); 220 frag6_insque(q6, &ip6q);
221 221
222 /* ip6q_nxt will be filled afterwards, from 1st fragment */ 222 /* ip6q_nxt will be filled afterwards, from 1st fragment */
223 q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6; 223 q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6;
224#ifdef notyet 224#ifdef notyet
225 q6->ip6q_nxtp = (u_char *)nxtp; 225 q6->ip6q_nxtp = (u_char *)nxtp;
226#endif 226#endif
227 q6->ip6q_ident = ip6f->ip6f_ident; 227 q6->ip6q_ident = ip6f->ip6f_ident;
228 q6->ip6q_arrive = 0; /* Is it used anywhere? */ 228 q6->ip6q_arrive = 0; /* Is it used anywhere? */
229 q6->ip6q_ttl = IPV6_FRAGTTL; 229 q6->ip6q_ttl = IPV6_FRAGTTL;
230 q6->ip6q_src = ip6->ip6_src; 230 q6->ip6q_src = ip6->ip6_src;
231 q6->ip6q_dst = ip6->ip6_dst; 231 q6->ip6q_dst = ip6->ip6_dst;
232 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ 232 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
233 233
234 q6->ip6q_nfrag = 0; 234 q6->ip6q_nfrag = 0;
235 } 235 }
236 236
237 /* 237 /*
238 * If it's the 1st fragment, record the length of the 238 * If it's the 1st fragment, record the length of the
239 * unfragmentable part and the next header of the fragment header. 239 * unfragmentable part and the next header of the fragment header.
240 */ 240 */
241 fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); 241 fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
242 if (fragoff == 0) { 242 if (fragoff == 0) {
243 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) - 243 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
244 sizeof(struct ip6_frag); 244 sizeof(struct ip6_frag);
245 q6->ip6q_nxt = ip6f->ip6f_nxt; 245 q6->ip6q_nxt = ip6f->ip6f_nxt;
246 } 246 }
247 247
248 /* 248 /*
249 * Check that the reassembled packet would not exceed 65535 bytes 249 * Check that the reassembled packet would not exceed 65535 bytes
250 * in size. 250 * in size.
251 * If it would exceed, discard the fragment and return an ICMP error. 251 * If it would exceed, discard the fragment and return an ICMP error.
252 */ 252 */
253 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset; 253 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
254 if (q6->ip6q_unfrglen >= 0) { 254 if (q6->ip6q_unfrglen >= 0) {
255 /* The 1st fragment has already arrived. */ 255 /* The 1st fragment has already arrived. */
256 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) { 256 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
257 mutex_exit(&frag6_lock); 257 mutex_exit(&frag6_lock);
258 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 258 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
259 offset - sizeof(struct ip6_frag) + 259 offset - sizeof(struct ip6_frag) +
260 offsetof(struct ip6_frag, ip6f_offlg)); 260 offsetof(struct ip6_frag, ip6f_offlg));
261 return -1; 261 return -1;
262 } 262 }
263 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { 263 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
264 mutex_exit(&frag6_lock); 264 mutex_exit(&frag6_lock);
265 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 265 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
266 offset - sizeof(struct ip6_frag) + 266 offset - sizeof(struct ip6_frag) +
267 offsetof(struct ip6_frag, ip6f_offlg)); 267 offsetof(struct ip6_frag, ip6f_offlg));
268 return -1; 268 return -1;
269 } 269 }
270 /* 270 /*
271 * If it's the first fragment, do the above check for each 271 * If it's the first fragment, do the above check for each
272 * fragment already stored in the reassembly queue. 272 * fragment already stored in the reassembly queue.
273 */ 273 */
274 if (fragoff == 0) { 274 if (fragoff == 0) {
275 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 275 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
276 af6 = af6dwn) { 276 af6 = af6dwn) {
277 af6dwn = af6->ip6af_down; 277 af6dwn = af6->ip6af_down;
278 278
279 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen > 279 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
280 IPV6_MAXPACKET) { 280 IPV6_MAXPACKET) {
281 struct mbuf *merr = IP6_REASS_MBUF(af6); 281 struct mbuf *merr = IP6_REASS_MBUF(af6);
282 struct ip6_hdr *ip6err; 282 struct ip6_hdr *ip6err;
283 int erroff = af6->ip6af_offset; 283 int erroff = af6->ip6af_offset;
284 284
285 /* dequeue the fragment. */ 285 /* dequeue the fragment. */
286 frag6_deq(af6); 286 frag6_deq(af6);
287 free(af6, M_FTABLE); 287 free(af6, M_FTABLE);
288 288
289 /* adjust pointer. */ 289 /* adjust pointer. */
290 ip6err = mtod(merr, struct ip6_hdr *); 290 ip6err = mtod(merr, struct ip6_hdr *);
291 291
292 /* 292 /*
293 * Restore source and destination addresses 293 * Restore source and destination addresses
294 * in the erroneous IPv6 header. 294 * in the erroneous IPv6 header.
295 */ 295 */
296 ip6err->ip6_src = q6->ip6q_src; 296 ip6err->ip6_src = q6->ip6q_src;
297 ip6err->ip6_dst = q6->ip6q_dst; 297 ip6err->ip6_dst = q6->ip6q_dst;
298 298
299 icmp6_error(merr, ICMP6_PARAM_PROB, 299 icmp6_error(merr, ICMP6_PARAM_PROB,
300 ICMP6_PARAMPROB_HEADER, 300 ICMP6_PARAMPROB_HEADER,
301 erroff - sizeof(struct ip6_frag) + 301 erroff - sizeof(struct ip6_frag) +
302 offsetof(struct ip6_frag, ip6f_offlg)); 302 offsetof(struct ip6_frag, ip6f_offlg));
303 } 303 }
304 } 304 }
305 } 305 }
306 306
307 ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE, 307 ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE,
308 M_DONTWAIT); 308 M_DONTWAIT);
309 if (ip6af == NULL) 309 if (ip6af == NULL)
310 goto dropfrag; 310 goto dropfrag;
311 memset(ip6af, 0, sizeof(*ip6af)); 311 memset(ip6af, 0, sizeof(*ip6af));
312 ip6af->ip6af_head = ip6->ip6_flow; 312 ip6af->ip6af_head = ip6->ip6_flow;
313 ip6af->ip6af_len = ip6->ip6_plen; 313 ip6af->ip6af_len = ip6->ip6_plen;
314 ip6af->ip6af_nxt = ip6->ip6_nxt; 314 ip6af->ip6af_nxt = ip6->ip6_nxt;
315 ip6af->ip6af_hlim = ip6->ip6_hlim; 315 ip6af->ip6af_hlim = ip6->ip6_hlim;
316 ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG; 316 ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
317 ip6af->ip6af_off = fragoff; 317 ip6af->ip6af_off = fragoff;
318 ip6af->ip6af_frglen = frgpartlen; 318 ip6af->ip6af_frglen = frgpartlen;
319 ip6af->ip6af_offset = offset; 319 ip6af->ip6af_offset = offset;
320 IP6_REASS_MBUF(ip6af) = m; 320 IP6_REASS_MBUF(ip6af) = m;
321 321
322 if (first_frag) { 322 if (first_frag) {
323 af6 = (struct ip6asfrag *)q6; 323 af6 = (struct ip6asfrag *)q6;
324 goto insert; 324 goto insert;
325 } 325 }
326 326
327 /* 327 /*
328 * Find a segment which begins after this one does. 328 * Find a segment which begins after this one does.
329 */ 329 */
330 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 330 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
331 af6 = af6->ip6af_down) 331 af6 = af6->ip6af_down)
332 if (af6->ip6af_off > ip6af->ip6af_off) 332 if (af6->ip6af_off > ip6af->ip6af_off)
333 break; 333 break;
334 334
335#if 0 335#if 0
336 /* 336 /*
337 * If there is a preceding segment, it may provide some of 337 * If there is a preceding segment, it may provide some of
338 * our data already. If so, drop the data from the incoming 338 * our data already. If so, drop the data from the incoming
339 * segment. If it provides all of our data, drop us. 339 * segment. If it provides all of our data, drop us.
340 */ 340 */
341 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 341 if (af6->ip6af_up != (struct ip6asfrag *)q6) {
342 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 342 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
343 - ip6af->ip6af_off; 343 - ip6af->ip6af_off;
344 if (i > 0) { 344 if (i > 0) {
345 if (i >= ip6af->ip6af_frglen) 345 if (i >= ip6af->ip6af_frglen)
346 goto dropfrag; 346 goto dropfrag;
347 m_adj(IP6_REASS_MBUF(ip6af), i); 347 m_adj(IP6_REASS_MBUF(ip6af), i);
348 ip6af->ip6af_off += i; 348 ip6af->ip6af_off += i;
349 ip6af->ip6af_frglen -= i; 349 ip6af->ip6af_frglen -= i;
350 } 350 }
351 } 351 }
352 352
353 /* 353 /*
354 * While we overlap succeeding segments trim them or, 354 * While we overlap succeeding segments trim them or,
355 * if they are completely covered, dequeue them. 355 * if they are completely covered, dequeue them.
356 */ 356 */
357 while (af6 != (struct ip6asfrag *)q6 && 357 while (af6 != (struct ip6asfrag *)q6 &&
358 ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) { 358 ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {
359 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 359 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
360 if (i < af6->ip6af_frglen) { 360 if (i < af6->ip6af_frglen) {
361 af6->ip6af_frglen -= i; 361 af6->ip6af_frglen -= i;
362 af6->ip6af_off += i; 362 af6->ip6af_off += i;
363 m_adj(IP6_REASS_MBUF(af6), i); 363 m_adj(IP6_REASS_MBUF(af6), i);
364 break; 364 break;
365 } 365 }
366 af6 = af6->ip6af_down; 366 af6 = af6->ip6af_down;
367 m_freem(IP6_REASS_MBUF(af6->ip6af_up)); 367 m_freem(IP6_REASS_MBUF(af6->ip6af_up));
368 frag6_deq(af6->ip6af_up); 368 frag6_deq(af6->ip6af_up);
369 } 369 }
370#else 370#else
371 /* 371 /*
372 * If the incoming framgent overlaps some existing fragments in 372 * If the incoming framgent overlaps some existing fragments in
373 * the reassembly queue, drop it, since it is dangerous to override 373 * the reassembly queue, drop it, since it is dangerous to override
374 * existing fragments from a security point of view. 374 * existing fragments from a security point of view.
375 * We don't know which fragment is the bad guy - here we trust 375 * We don't know which fragment is the bad guy - here we trust
376 * fragment that came in earlier, with no real reason. 376 * fragment that came in earlier, with no real reason.
377 */ 377 */
378 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 378 if (af6->ip6af_up != (struct ip6asfrag *)q6) {
379 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 379 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
380 - ip6af->ip6af_off; 380 - ip6af->ip6af_off;
381 if (i > 0) { 381 if (i > 0) {
382#if 0 /* suppress the noisy log */ 382#if 0 /* suppress the noisy log */
383 log(LOG_ERR, "%d bytes of a fragment from %s " 383 log(LOG_ERR, "%d bytes of a fragment from %s "
384 "overlaps the previous fragment\n", 384 "overlaps the previous fragment\n",
385 i, ip6_sprintf(&q6->ip6q_src)); 385 i, ip6_sprintf(&q6->ip6q_src));
386#endif 386#endif
387 free(ip6af, M_FTABLE); 387 free(ip6af, M_FTABLE);
388 goto dropfrag; 388 goto dropfrag;
389 } 389 }
390 } 390 }
391 if (af6 != (struct ip6asfrag *)q6) { 391 if (af6 != (struct ip6asfrag *)q6) {
392 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 392 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
393 if (i > 0) { 393 if (i > 0) {
394#if 0 /* suppress the noisy log */ 394#if 0 /* suppress the noisy log */
395 log(LOG_ERR, "%d bytes of a fragment from %s " 395 log(LOG_ERR, "%d bytes of a fragment from %s "
396 "overlaps the succeeding fragment", 396 "overlaps the succeeding fragment",
397 i, ip6_sprintf(&q6->ip6q_src)); 397 i, ip6_sprintf(&q6->ip6q_src));
398#endif 398#endif
399 free(ip6af, M_FTABLE); 399 free(ip6af, M_FTABLE);
400 goto dropfrag; 400 goto dropfrag;
401 } 401 }
402 } 402 }
403#endif 403#endif
404 404
405insert: 405insert:
406 406
407 /* 407 /*
408 * Stick new segment in its place; 408 * Stick new segment in its place;
409 * check for complete reassembly. 409 * check for complete reassembly.
410 * Move to front of packet queue, as we are 410 * Move to front of packet queue, as we are
411 * the most recently active fragmented packet. 411 * the most recently active fragmented packet.
412 */ 412 */
413 frag6_enq(ip6af, af6->ip6af_up); 413 frag6_enq(ip6af, af6->ip6af_up);
414 frag6_nfrags++; 414 frag6_nfrags++;
415 q6->ip6q_nfrag++; 415 q6->ip6q_nfrag++;
416#if 0 /* xxx */ 416#if 0 /* xxx */
417 if (q6 != ip6q.ip6q_next) { 417 if (q6 != ip6q.ip6q_next) {
418 frag6_remque(q6); 418 frag6_remque(q6);
419 frag6_insque(q6, &ip6q); 419 frag6_insque(q6, &ip6q);
420 } 420 }
421#endif 421#endif
422 next = 0; 422 next = 0;
423 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 423 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
424 af6 = af6->ip6af_down) { 424 af6 = af6->ip6af_down) {
425 if (af6->ip6af_off != next) { 425 if (af6->ip6af_off != next) {
426 mutex_exit(&frag6_lock); 426 mutex_exit(&frag6_lock);
427 return 0; 427 return 0;
428 } 428 }
429 next += af6->ip6af_frglen; 429 next += af6->ip6af_frglen;
430 } 430 }
431 if (af6->ip6af_up->ip6af_mff) { 431 if (af6->ip6af_up->ip6af_mff) {
432 mutex_exit(&frag6_lock); 432 mutex_exit(&frag6_lock);
433 return 0; 433 return 0;
434 } 434 }
435 435
436 /* 436 /*
437 * Reassembly is complete; concatenate fragments. 437 * Reassembly is complete; concatenate fragments.
438 */ 438 */
439 ip6af = q6->ip6q_down; 439 ip6af = q6->ip6q_down;
440 t = m = IP6_REASS_MBUF(ip6af); 440 t = m = IP6_REASS_MBUF(ip6af);
441 af6 = ip6af->ip6af_down; 441 af6 = ip6af->ip6af_down;
442 frag6_deq(ip6af); 442 frag6_deq(ip6af);
443 while (af6 != (struct ip6asfrag *)q6) { 443 while (af6 != (struct ip6asfrag *)q6) {
444 af6dwn = af6->ip6af_down; 444 af6dwn = af6->ip6af_down;
445 frag6_deq(af6); 445 frag6_deq(af6);
446 while (t->m_next) 446 while (t->m_next)
447 t = t->m_next; 447 t = t->m_next;
448 t->m_next = IP6_REASS_MBUF(af6); 448 t->m_next = IP6_REASS_MBUF(af6);
449 m_adj(t->m_next, af6->ip6af_offset); 449 m_adj(t->m_next, af6->ip6af_offset);
450 free(af6, M_FTABLE); 450 free(af6, M_FTABLE);
451 af6 = af6dwn; 451 af6 = af6dwn;
452 } 452 }
453 453
454 /* adjust offset to point where the original next header starts */ 454 /* adjust offset to point where the original next header starts */
455 offset = ip6af->ip6af_offset - sizeof(struct ip6_frag); 455 offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
456 free(ip6af, M_FTABLE); 456 free(ip6af, M_FTABLE);
457 ip6 = mtod(m, struct ip6_hdr *); 457 ip6 = mtod(m, struct ip6_hdr *);
458 ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr)); 458 ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr));
459 ip6->ip6_src = q6->ip6q_src; 459 ip6->ip6_src = q6->ip6q_src;
460 ip6->ip6_dst = q6->ip6q_dst; 460 ip6->ip6_dst = q6->ip6q_dst;
461 nxt = q6->ip6q_nxt; 461 nxt = q6->ip6q_nxt;
462#ifdef notyet 462#ifdef notyet
463 *q6->ip6q_nxtp = (u_char)(nxt & 0xff); 463 *q6->ip6q_nxtp = (u_char)(nxt & 0xff);
464#endif 464#endif
465 465
466 /* 466 /*
467 * Delete frag6 header with as a few cost as possible. 467 * Delete frag6 header with as a few cost as possible.
468 */ 468 */
469 if (m->m_len >= offset + sizeof(struct ip6_frag)) { 469 if (m->m_len >= offset + sizeof(struct ip6_frag)) {
470 memmove((char *)ip6 + sizeof(struct ip6_frag), ip6, offset); 470 memmove((char *)ip6 + sizeof(struct ip6_frag), ip6, offset);
471 m->m_data += sizeof(struct ip6_frag); 471 m->m_data += sizeof(struct ip6_frag);
472 m->m_len -= sizeof(struct ip6_frag); 472 m->m_len -= sizeof(struct ip6_frag);
473 } else { 473 } else {
474 /* this comes with no copy if the boundary is on cluster */ 474 /* this comes with no copy if the boundary is on cluster */
475 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) { 475 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
476 frag6_remque(q6); 476 frag6_remque(q6);
477 frag6_nfrags -= q6->ip6q_nfrag; 477 frag6_nfrags -= q6->ip6q_nfrag;
478 free(q6, M_FTABLE); 478 free(q6, M_FTABLE);
479 frag6_nfragpackets--; 479 frag6_nfragpackets--;
480 goto dropfrag; 480 goto dropfrag;
481 } 481 }
482 m_adj(t, sizeof(struct ip6_frag)); 482 m_adj(t, sizeof(struct ip6_frag));
483 m_cat(m, t); 483 m_cat(m, t);
484 } 484 }
485 485
486 /* 486 /*
487 * Store NXT to the original. 487 * Store NXT to the original.
488 */ 488 */
489 { 489 {
490 u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */ 490 u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
491 *prvnxtp = nxt; 491 *prvnxtp = nxt;
492 } 492 }
493 493
494 frag6_remque(q6); 494 frag6_remque(q6);
495 frag6_nfrags -= q6->ip6q_nfrag; 495 frag6_nfrags -= q6->ip6q_nfrag;
496 free(q6, M_FTABLE); 496 free(q6, M_FTABLE);
497 frag6_nfragpackets--; 497 frag6_nfragpackets--;
498 498
499 if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ 499 if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */
500 int plen = 0; 500 int plen = 0;
501 for (t = m; t; t = t->m_next) 501 for (t = m; t; t = t->m_next)
502 plen += t->m_len; 502 plen += t->m_len;
503 m->m_pkthdr.len = plen; 503 m->m_pkthdr.len = plen;
504 } 504 }
505 505
506 IP6_STATINC(IP6_STAT_REASSEMBLED); 506 IP6_STATINC(IP6_STAT_REASSEMBLED);
507 in6_ifstat_inc(dstifp, ifs6_reass_ok); 507 in6_ifstat_inc(dstifp, ifs6_reass_ok);
508 508
509 /* 509 /*
510 * Tell launch routine the next header 510 * Tell launch routine the next header
511 */ 511 */
512 512
513 *mp = m; 513 *mp = m;
514 *offp = offset; 514 *offp = offset;
515 515
516 mutex_exit(&frag6_lock); 516 mutex_exit(&frag6_lock);
517 return nxt; 517 return nxt;
518 518
519 dropfrag: 519 dropfrag:
520 mutex_exit(&frag6_lock); 520 mutex_exit(&frag6_lock);
521 in6_ifstat_inc(dstifp, ifs6_reass_fail); 521 in6_ifstat_inc(dstifp, ifs6_reass_fail);
522 IP6_STATINC(IP6_STAT_FRAGDROPPED); 522 IP6_STATINC(IP6_STAT_FRAGDROPPED);
523 m_freem(m); 523 m_freem(m);
524 return -1; 524 return -1;
525} 525}
526 526
527int 527int
528frag6_input(struct mbuf **mp, int *offp, int proto) 528frag6_input(struct mbuf **mp, int *offp, int proto)
529{ 529{
530 int ret = frag6_in(mp, offp); 530 int ret = frag6_in(mp, offp);
531 531
532 if (ret > 0) { 532 if (ret > 0) {
533 return ret; 533 return ret;
534 } 534 }
535 return IPPROTO_DONE; 535 return IPPROTO_DONE;
536} 536}
537 537
538int 538int
539ip6_reass_packet(struct mbuf **mp, int offset) 539ip6_reass_packet(struct mbuf **mp, int offset)
540{ 540{
541 int ret = frag6_in(mp, &offset); 541 int ret = frag6_in(mp, &offset);
542 542
543 if (ret <= 0) { 543 if (ret <= 0) {
544 *mp = NULL; 544 *mp = NULL;
545 } 545 }
546 return ret < 0 ? ret : 0; 546 return ret < 0 ? ret : 0;
547} 547}
548 548
549/* 549/*
550 * Free a fragment reassembly header and all 550 * Free a fragment reassembly header and all
551 * associated datagrams. 551 * associated datagrams.
552 */ 552 */
553void 553void
554frag6_freef(struct ip6q *q6) 554frag6_freef(struct ip6q *q6)
555{ 555{
556 struct ip6asfrag *af6, *down6; 556 struct ip6asfrag *af6, *down6;
557 557
558 KASSERT(mutex_owned(&frag6_lock)); 558 KASSERT(mutex_owned(&frag6_lock));
559 559
560 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 560 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
561 af6 = down6) { 561 af6 = down6) {
562 struct mbuf *m = IP6_REASS_MBUF(af6); 562 struct mbuf *m = IP6_REASS_MBUF(af6);
563 563
564 down6 = af6->ip6af_down; 564 down6 = af6->ip6af_down;
565 frag6_deq(af6); 565 frag6_deq(af6);
566 566
567 /* 567 /*
568 * Return ICMP time exceeded error for the 1st fragment. 568 * Return ICMP time exceeded error for the 1st fragment.
569 * Just free other fragments. 569 * Just free other fragments.
570 */ 570 */
571 if (af6->ip6af_off == 0) { 571 if (af6->ip6af_off == 0) {
572 struct ip6_hdr *ip6; 572 struct ip6_hdr *ip6;
573 573
574 /* adjust pointer */ 574 /* adjust pointer */
575 ip6 = mtod(m, struct ip6_hdr *); 575 ip6 = mtod(m, struct ip6_hdr *);
576 576
577 /* restoure source and destination addresses */ 577 /* restoure source and destination addresses */
578 ip6->ip6_src = q6->ip6q_src; 578 ip6->ip6_src = q6->ip6q_src;
579 ip6->ip6_dst = q6->ip6q_dst; 579 ip6->ip6_dst = q6->ip6q_dst;
580 580
581 icmp6_error(m, ICMP6_TIME_EXCEEDED, 581 icmp6_error(m, ICMP6_TIME_EXCEEDED,
582 ICMP6_TIME_EXCEED_REASSEMBLY, 0); 582 ICMP6_TIME_EXCEED_REASSEMBLY, 0);
583 } else 583 } else
584 m_freem(m); 584 m_freem(m);
585 free(af6, M_FTABLE); 585 free(af6, M_FTABLE);
586 } 586 }
587 frag6_remque(q6); 587 frag6_remque(q6);
588 frag6_nfrags -= q6->ip6q_nfrag; 588 frag6_nfrags -= q6->ip6q_nfrag;
589 free(q6, M_FTABLE); 589 free(q6, M_FTABLE);
590 frag6_nfragpackets--; 590 frag6_nfragpackets--;
591} 591}
592 592
593/* 593/*
594 * Put an ip fragment on a reassembly chain. 594 * Put an ip fragment on a reassembly chain.
595 * Like insque, but pointers in middle of structure. 595 * Like insque, but pointers in middle of structure.
596 */ 596 */
597void 597void
598frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6) 598frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6)
599{ 599{
600 600
601 KASSERT(mutex_owned(&frag6_lock)); 601 KASSERT(mutex_owned(&frag6_lock));
602 602
603 af6->ip6af_up = up6; 603 af6->ip6af_up = up6;
604 af6->ip6af_down = up6->ip6af_down; 604 af6->ip6af_down = up6->ip6af_down;
605 up6->ip6af_down->ip6af_up = af6; 605 up6->ip6af_down->ip6af_up = af6;
606 up6->ip6af_down = af6; 606 up6->ip6af_down = af6;
607} 607}
608 608
609/* 609/*
610 * To frag6_enq as remque is to insque. 610 * To frag6_enq as remque is to insque.
611 */ 611 */
612void 612void
613frag6_deq(struct ip6asfrag *af6) 613frag6_deq(struct ip6asfrag *af6)
614{ 614{
615 615
616 KASSERT(mutex_owned(&frag6_lock)); 616 KASSERT(mutex_owned(&frag6_lock));
617 617
618 af6->ip6af_up->ip6af_down = af6->ip6af_down; 618 af6->ip6af_up->ip6af_down = af6->ip6af_down;
619 af6->ip6af_down->ip6af_up = af6->ip6af_up; 619 af6->ip6af_down->ip6af_up = af6->ip6af_up;
620} 620}
621 621
622void 622void
623frag6_insque(struct ip6q *new, struct ip6q *old) 623frag6_insque(struct ip6q *new, struct ip6q *old)
624{ 624{
625 625
626 KASSERT(mutex_owned(&frag6_lock)); 626 KASSERT(mutex_owned(&frag6_lock));
627 627
628 new->ip6q_prev = old; 628 new->ip6q_prev = old;
629 new->ip6q_next = old->ip6q_next; 629 new->ip6q_next = old->ip6q_next;
630 old->ip6q_next->ip6q_prev= new; 630 old->ip6q_next->ip6q_prev= new;
631 old->ip6q_next = new; 631 old->ip6q_next = new;
632} 632}
633 633
634void 634void
635frag6_remque(struct ip6q *p6) 635frag6_remque(struct ip6q *p6)
636{ 636{
637 637
638 KASSERT(mutex_owned(&frag6_lock)); 638 KASSERT(mutex_owned(&frag6_lock));
639 639
640 p6->ip6q_prev->ip6q_next = p6->ip6q_next; 640 p6->ip6q_prev->ip6q_next = p6->ip6q_next;
641 p6->ip6q_next->ip6q_prev = p6->ip6q_prev; 641 p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
642} 642}
643 643
644void 644void
645frag6_fasttimo(void) 645frag6_fasttimo(void)
646{ 646{
 647 mutex_enter(softnet_lock);
 648 KERNEL_LOCK(1, NULL);
 649
647 if (frag6_drainwanted) { 650 if (frag6_drainwanted) {
648 frag6_drain(); 651 frag6_drain();
649 frag6_drainwanted = 0; 652 frag6_drainwanted = 0;
650 } 653 }
 654
 655 KERNEL_UNLOCK_ONE(NULL);
 656 mutex_exit(softnet_lock);
651} 657}
652 658
653/* 659/*
654 * IPv6 reassembling timer processing; 660 * IPv6 reassembling timer processing;
655 * if a timer expires on a reassembly 661 * if a timer expires on a reassembly
656 * queue, discard it. 662 * queue, discard it.
657 */ 663 */
658void 664void
659frag6_slowtimo(void) 665frag6_slowtimo(void)
660{ 666{
661 struct ip6q *q6; 667 struct ip6q *q6;
662 668
 669 mutex_enter(softnet_lock);
 670 KERNEL_LOCK(1, NULL);
 671
663 mutex_enter(&frag6_lock); 672 mutex_enter(&frag6_lock);
664 q6 = ip6q.ip6q_next; 673 q6 = ip6q.ip6q_next;
665 if (q6) 674 if (q6)
666 while (q6 != &ip6q) { 675 while (q6 != &ip6q) {
667 --q6->ip6q_ttl; 676 --q6->ip6q_ttl;
668 q6 = q6->ip6q_next; 677 q6 = q6->ip6q_next;
669 if (q6->ip6q_prev->ip6q_ttl == 0) { 678 if (q6->ip6q_prev->ip6q_ttl == 0) {
670 IP6_STATINC(IP6_STAT_FRAGTIMEOUT); 679 IP6_STATINC(IP6_STAT_FRAGTIMEOUT);
671 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 680 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
672 frag6_freef(q6->ip6q_prev); 681 frag6_freef(q6->ip6q_prev);
673 } 682 }
674 } 683 }
675 /* 684 /*
676 * If we are over the maximum number of fragments 685 * If we are over the maximum number of fragments
677 * (due to the limit being lowered), drain off 686 * (due to the limit being lowered), drain off
678 * enough to get down to the new limit. 687 * enough to get down to the new limit.
679 */ 688 */
680 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets && 689 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
681 ip6q.ip6q_prev) { 690 ip6q.ip6q_prev) {
682 IP6_STATINC(IP6_STAT_FRAGOVERFLOW); 691 IP6_STATINC(IP6_STAT_FRAGOVERFLOW);
683 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 692 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
684 frag6_freef(ip6q.ip6q_prev); 693 frag6_freef(ip6q.ip6q_prev);
685 } 694 }
686 mutex_exit(&frag6_lock); 695 mutex_exit(&frag6_lock);
687 696
 697 KERNEL_UNLOCK_ONE(NULL);
 698 mutex_exit(softnet_lock);
 699
688#if 0 700#if 0
689 /* 701 /*
690 * Routing changes might produce a better route than we last used; 702 * Routing changes might produce a better route than we last used;
691 * make sure we notice eventually, even if forwarding only for one 703 * make sure we notice eventually, even if forwarding only for one
692 * destination and the cache is never replaced. 704 * destination and the cache is never replaced.
693 */ 705 */
694 rtcache_free(&ip6_forward_rt); 706 rtcache_free(&ip6_forward_rt);
695 rtcache_free(&ipsrcchk_rt); 707 rtcache_free(&ipsrcchk_rt);
696#endif 708#endif
697 709
698} 710}
699 711
700void 712void
701frag6_drainstub(void) 713frag6_drainstub(void)
702{ 714{
703 frag6_drainwanted = 1; 715 frag6_drainwanted = 1;
704} 716}
705 717
706/* 718/*
707 * Drain off all datagram fragments. 719 * Drain off all datagram fragments.
708 */ 720 */
709void 721void
710frag6_drain(void) 722frag6_drain(void)
711{ 723{
712 724
713 if (mutex_tryenter(&frag6_lock)) { 725 if (mutex_tryenter(&frag6_lock)) {
714 while (ip6q.ip6q_next != &ip6q) { 726 while (ip6q.ip6q_next != &ip6q) {
715 IP6_STATINC(IP6_STAT_FRAGDROPPED); 727 IP6_STATINC(IP6_STAT_FRAGDROPPED);
716 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 728 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
717 frag6_freef(ip6q.ip6q_next); 729 frag6_freef(ip6q.ip6q_next);
718 } 730 }
719 mutex_exit(&frag6_lock); 731 mutex_exit(&frag6_lock);
720 } 732 }
721} 733}