| 332 | } |
| 333 | |
| 334 | static struct mbuf * |
| 335 | firewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src) |
| 336 | { |
| 337 | union fw_encap *enc; |
| 338 | struct fw_reass *r; |
| 339 | struct mbuf *mf, *mprev; |
| 340 | int dsize; |
| 341 | int fstart, fend, start, end, islast; |
| 342 | uint32_t id; |
| 343 | |
| 344 | /* |
| 345 | * Find an existing reassembly buffer or create a new one. |
| 346 | */ |
| 347 | enc = mtod(m, union fw_encap *); |
| 348 | id = enc->firstfrag.dgl | (src << 16); |
| 349 | STAILQ_FOREACH(r, &fc->fc_frags, fr_link) |
| 350 | if (r->fr_id == id) |
| 351 | break; |
| 352 | if (!r) { |
| 353 | r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT); |
| 354 | if (!r) { |
| 355 | m_freem(m); |
| 356 | return 0; |
| 357 | } |
| 358 | r->fr_id = id; |
| 359 | r->fr_frags = 0; |
| 360 | STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link); |
| 361 | } |
| 362 | |
| 363 | /* |
| 364 | * If this fragment overlaps any other fragment, we must discard |
| 365 | * the partial reassembly and start again. |
| 366 | */ |
| 367 | if (enc->firstfrag.lf == FW_ENCAP_FIRST) |
| 368 | fstart = 0; |
| 369 | else |
| 370 | fstart = enc->nextfrag.fragment_offset; |
| 371 | fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t); |
| 372 | dsize = enc->nextfrag.datagram_size; |
| 373 | islast = (enc->nextfrag.lf == FW_ENCAP_LAST); |
| 374 | |
| 375 | for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) { |
| 376 | enc = mtod(mf, union fw_encap *); |
| 377 | if (enc->nextfrag.datagram_size != dsize) { |
| 378 | /* |
| 379 | * This fragment must be from a different |
| 380 | * packet. |
| 381 | */ |
| 382 | goto bad; |
| 383 | } |
| 384 | if (enc->firstfrag.lf == FW_ENCAP_FIRST) |
| 385 | start = 0; |
| 386 | else |
| 387 | start = enc->nextfrag.fragment_offset; |
| 388 | end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t); |
| 389 | if ((fstart < end && fend > start) || |
| 390 | (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) { |
| 391 | /* |