* Handle an outgoing control frame. */
| 1006 | * Handle an outgoing control frame. |
| 1007 | */ |
| 1008 | static int |
| 1009 | ng_l2tp_rcvdata_ctrl(hook_p hook, item_p item) |
| 1010 | { |
| 1011 | const node_p node = NG_HOOK_NODE(hook); |
| 1012 | const priv_p priv = NG_NODE_PRIVATE(node); |
| 1013 | struct l2tp_seq *const seq = &priv->seq; |
| 1014 | struct mbuf *m; |
| 1015 | int error; |
| 1016 | int i; |
| 1017 | u_int16_t ns; |
| 1018 | |
| 1019 | /* Sanity check */ |
| 1020 | L2TP_SEQ_CHECK(&priv->seq); |
| 1021 | |
| 1022 | /* If not configured, reject */ |
| 1023 | if (!priv->conf.enabled) { |
| 1024 | NG_FREE_ITEM(item); |
| 1025 | ERROUT(ENXIO); |
| 1026 | } |
| 1027 | |
| 1028 | /* Grab mbuf and discard other stuff XXX */ |
| 1029 | NGI_GET_M(item, m); |
| 1030 | NG_FREE_ITEM(item); |
| 1031 | |
| 1032 | /* Packet should have session ID prepended */ |
| 1033 | if (m->m_pkthdr.len < 2) { |
| 1034 | priv->stats.xmitInvalid++; |
| 1035 | m_freem(m); |
| 1036 | ERROUT(EINVAL); |
| 1037 | } |
| 1038 | |
| 1039 | /* Check max length */ |
| 1040 | if (m->m_pkthdr.len >= 0x10000 - 14) { |
| 1041 | priv->stats.xmitTooBig++; |
| 1042 | m_freem(m); |
| 1043 | ERROUT(EOVERFLOW); |
| 1044 | } |
| 1045 | |
| 1046 | mtx_lock(&seq->mtx); |
| 1047 | |
| 1048 | /* Find next empty slot in transmit queue */ |
| 1049 | for (i = 0; i < L2TP_MAX_XWIN && seq->xwin[i] != NULL; i++); |
| 1050 | if (i == L2TP_MAX_XWIN) { |
| 1051 | mtx_unlock(&seq->mtx); |
| 1052 | priv->stats.xmitDrops++; |
| 1053 | m_freem(m); |
| 1054 | ERROUT(ENOBUFS); |
| 1055 | } |
| 1056 | seq->xwin[i] = m; |
| 1057 | |
| 1058 | /* If peer's receive window is already full, nothing else to do */ |
| 1059 | if (i >= seq->cwnd) { |
| 1060 | mtx_unlock(&seq->mtx); |
| 1061 | ERROUT(0); |
| 1062 | } |
| 1063 | |
| 1064 | /* Start retransmit timer if not already running */ |
| 1065 | if (!callout_active(&seq->rack_timer)) |
nothing calls this directly
no test coverage detected