* Handle an incoming frame from below. */
| 739 | * Handle an incoming frame from below. |
| 740 | */ |
| 741 | static int |
| 742 | ng_l2tp_rcvdata_lower(hook_p h, item_p item) |
| 743 | { |
| 744 | static const u_int16_t req_bits[2][2] = { |
| 745 | { L2TP_DATA_0BITS, L2TP_DATA_1BITS }, |
| 746 | { L2TP_CTRL_0BITS, L2TP_CTRL_1BITS }, |
| 747 | }; |
| 748 | const node_p node = NG_HOOK_NODE(h); |
| 749 | const priv_p priv = NG_NODE_PRIVATE(node); |
| 750 | hookpriv_p hpriv = NULL; |
| 751 | hook_p hook = NULL; |
| 752 | struct mbuf *m; |
| 753 | u_int16_t tid, sid; |
| 754 | u_int16_t hdr; |
| 755 | u_int16_t ns, nr; |
| 756 | int is_ctrl; |
| 757 | int error; |
| 758 | int len, plen; |
| 759 | |
| 760 | /* Sanity check */ |
| 761 | L2TP_SEQ_CHECK(&priv->seq); |
| 762 | |
| 763 | /* If not configured, reject */ |
| 764 | if (!priv->conf.enabled) { |
| 765 | NG_FREE_ITEM(item); |
| 766 | ERROUT(ENXIO); |
| 767 | } |
| 768 | |
| 769 | /* Grab mbuf */ |
| 770 | NGI_GET_M(item, m); |
| 771 | |
| 772 | /* Remember full packet length; needed for per session accounting. */ |
| 773 | plen = m->m_pkthdr.len; |
| 774 | |
| 775 | /* Update stats */ |
| 776 | priv->stats.recvPackets++; |
| 777 | priv->stats.recvOctets += plen; |
| 778 | |
| 779 | /* Get initial header */ |
| 780 | if (m->m_pkthdr.len < 6) { |
| 781 | priv->stats.recvRunts++; |
| 782 | NG_FREE_ITEM(item); |
| 783 | NG_FREE_M(m); |
| 784 | ERROUT(EINVAL); |
| 785 | } |
| 786 | if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { |
| 787 | priv->stats.memoryFailures++; |
| 788 | NG_FREE_ITEM(item); |
| 789 | ERROUT(EINVAL); |
| 790 | } |
| 791 | hdr = (mtod(m, uint8_t *)[0] << 8) + mtod(m, uint8_t *)[1]; |
| 792 | m_adj(m, 2); |
| 793 | |
| 794 | /* Check required header bits and minimum length */ |
| 795 | is_ctrl = (hdr & L2TP_HDR_CTRL) != 0; |
| 796 | if ((hdr & req_bits[is_ctrl][0]) != 0 |
| 797 | || (~hdr & req_bits[is_ctrl][1]) != 0) { |
| 798 | priv->stats.recvInvalid++; |
nothing calls this directly
no test coverage detected