| 251 | } |
| 252 | |
| 253 | int |
| 254 | ip6_fragment(struct ifnet *ifp, struct mbuf *m0, int hlen, u_char nextproto, |
| 255 | int fraglen , uint32_t id) |
| 256 | { |
| 257 | struct mbuf *m, **mnext, *m_frgpart; |
| 258 | struct ip6_hdr *ip6, *mhip6; |
| 259 | struct ip6_frag *ip6f; |
| 260 | int off; |
| 261 | int error; |
| 262 | int tlen = m0->m_pkthdr.len; |
| 263 | |
| 264 | KASSERT((fraglen % 8 == 0), ("Fragment length must be a multiple of 8")); |
| 265 | |
| 266 | m = m0; |
| 267 | ip6 = mtod(m, struct ip6_hdr *); |
| 268 | mnext = &m->m_nextpkt; |
| 269 | |
| 270 | for (off = hlen; off < tlen; off += fraglen) { |
| 271 | m = m_gethdr(M_NOWAIT, MT_DATA); |
| 272 | if (!m) { |
| 273 | IP6STAT_INC(ip6s_odropped); |
| 274 | return (ENOBUFS); |
| 275 | } |
| 276 | |
| 277 | /* |
| 278 | * Make sure the complete packet header gets copied |
| 279 | * from the originating mbuf to the newly created |
| 280 | * mbuf. This also ensures that existing firewall |
| 281 | * classification(s), VLAN tags and so on get copied |
| 282 | * to the resulting fragmented packet(s): |
| 283 | */ |
| 284 | if (m_dup_pkthdr(m, m0, M_NOWAIT) == 0) { |
| 285 | m_free(m); |
| 286 | IP6STAT_INC(ip6s_odropped); |
| 287 | return (ENOBUFS); |
| 288 | } |
| 289 | |
| 290 | *mnext = m; |
| 291 | mnext = &m->m_nextpkt; |
| 292 | m->m_data += max_linkhdr; |
| 293 | mhip6 = mtod(m, struct ip6_hdr *); |
| 294 | *mhip6 = *ip6; |
| 295 | m->m_len = sizeof(*mhip6); |
| 296 | error = ip6_insertfraghdr(m0, m, hlen, &ip6f); |
| 297 | if (error) { |
| 298 | IP6STAT_INC(ip6s_odropped); |
| 299 | return (error); |
| 300 | } |
| 301 | ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7)); |
| 302 | if (off + fraglen >= tlen) |
| 303 | fraglen = tlen - off; |
| 304 | else |
| 305 | ip6f->ip6f_offlg |= IP6F_MORE_FRAG; |
| 306 | mhip6->ip6_plen = htons((u_short)(fraglen + hlen + |
| 307 | sizeof(*ip6f) - sizeof(struct ip6_hdr))); |
| 308 | if ((m_frgpart = m_copym(m0, off, fraglen, M_NOWAIT)) == NULL) { |
| 309 | IP6STAT_INC(ip6s_odropped); |
| 310 | return (ENOBUFS); |
no test coverage detected