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