| 549 | } |
| 550 | |
| 551 | static int |
| 552 | ng_patch_rcvdata(hook_p hook, item_p item) |
| 553 | { |
| 554 | const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); |
| 555 | struct mbuf *m; |
| 556 | hook_p out; |
| 557 | int pullup_len = 0; |
| 558 | int error = 0; |
| 559 | |
| 560 | priv->stats.received++; |
| 561 | |
| 562 | NGI_GET_M(item, m); |
| 563 | |
| 564 | #define PULLUP_CHECK(mbuf, length) do { \ |
| 565 | pullup_len += length; \ |
| 566 | if (((mbuf)->m_pkthdr.len < pullup_len) || \ |
| 567 | (pullup_len > MHLEN)) { \ |
| 568 | error = EINVAL; \ |
| 569 | goto bypass; \ |
| 570 | } \ |
| 571 | if ((mbuf)->m_len < pullup_len && \ |
| 572 | (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) { \ |
| 573 | error = ENOBUFS; \ |
| 574 | goto drop; \ |
| 575 | } \ |
| 576 | } while (0) |
| 577 | |
| 578 | if (priv->conf && hook == priv->in && |
| 579 | m && (m->m_flags & M_PKTHDR)) { |
| 580 | m = m_unshare(m, M_NOWAIT); |
| 581 | |
| 582 | if (m == NULL) |
| 583 | ERROUT(ENOMEM); |
| 584 | |
| 585 | if (priv->conf->relative_offset) { |
| 586 | struct ether_header *eh; |
| 587 | struct ng_patch_vlan_header *vh; |
| 588 | uint16_t etype; |
| 589 | |
| 590 | switch (priv->dlt) |
| 591 | { |
| 592 | case DLT_EN10MB: |
| 593 | PULLUP_CHECK(m, sizeof(struct ether_header)); |
| 594 | eh = mtod(m, struct ether_header *); |
| 595 | etype = ntohs(eh->ether_type); |
| 596 | |
| 597 | for (;;) { /* QinQ support */ |
| 598 | switch (etype) |
| 599 | { |
| 600 | case 0x8100: |
| 601 | case 0x88A8: |
| 602 | case 0x9100: |
| 603 | PULLUP_CHECK(m, sizeof(struct ng_patch_vlan_header)); |
| 604 | vh = (struct ng_patch_vlan_header *) mtodo(m, |
| 605 | pullup_len - sizeof(struct ng_patch_vlan_header)); |
| 606 | etype = ntohs(vh->etype); |
| 607 | break; |
| 608 | |