1 2/* 3 * Copyright (c) 2001-2002 Packet Design, LLC. 4 * All rights reserved. 5 * 6 * Subject to the following obligations and disclaimer of warranty, 7 * use and redistribution of this software, in source or object code 8 * forms, with or without modifications are expressly permitted by 9 * Packet Design; provided, however, that: 10 * 11 * (i) Any and all reproductions of the source or object code 12 * must include the copyright notice above and the following 13 * disclaimer of warranties; and 14 * (ii) No rights are granted, in any manner or form, to use 15 * Packet Design trademarks, including the mark "PACKET DESIGN" 16 * on advertising, endorsements, or otherwise except as such 17 * appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING 22 * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED 23 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 24 * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, 25 * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS 26 * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, 27 * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE 28 * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE 29 * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, 30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL 31 * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF 32 * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF 33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 35 * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF 36 * THE POSSIBILITY OF SUCH DAMAGE. 37 * 38 * Author: Archie Cobbs <archie@freebsd.org> 39 *
| 1 2/* 3 * Copyright (c) 2001-2002 Packet Design, LLC. 4 * All rights reserved. 5 * 6 * Subject to the following obligations and disclaimer of warranty, 7 * use and redistribution of this software, in source or object code 8 * forms, with or without modifications are expressly permitted by 9 * Packet Design; provided, however, that: 10 * 11 * (i) Any and all reproductions of the source or object code 12 * must include the copyright notice above and the following 13 * disclaimer of warranties; and 14 * (ii) No rights are granted, in any manner or form, to use 15 * Packet Design trademarks, including the mark "PACKET DESIGN" 16 * on advertising, endorsements, or otherwise except as such 17 * appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING 22 * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED 23 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 24 * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, 25 * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS 26 * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, 27 * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE 28 * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE 29 * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, 30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL 31 * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF 32 * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF 33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 35 * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF 36 * THE POSSIBILITY OF SUCH DAMAGE. 37 * 38 * Author: Archie Cobbs <archie@freebsd.org> 39 *
|
40 * $FreeBSD: head/sys/netgraph/ng_l2tp.c 102244 2002-08-22 00:30:03Z archie $
| 40 * $FreeBSD: head/sys/netgraph/ng_l2tp.c 108107 2002-12-19 22:58:27Z bmilekic $
|
41 */ 42 43/* 44 * L2TP netgraph node type. 45 * 46 * This node type implements the lower layer of the 47 * L2TP protocol as specified in RFC 2661. 48 */ 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/kernel.h> 53#include <sys/time.h> 54#include <sys/conf.h> 55#include <sys/mbuf.h> 56#include <sys/malloc.h> 57#include <sys/errno.h>
| 41 */ 42 43/* 44 * L2TP netgraph node type. 45 * 46 * This node type implements the lower layer of the 47 * L2TP protocol as specified in RFC 2661. 48 */ 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/kernel.h> 53#include <sys/time.h> 54#include <sys/conf.h> 55#include <sys/mbuf.h> 56#include <sys/malloc.h> 57#include <sys/errno.h>
|
| 58#include <sys/libkern.h>
|
58 59#include <netgraph/ng_message.h> 60#include <netgraph/netgraph.h> 61#include <netgraph/ng_parse.h> 62#include <netgraph/ng_l2tp.h> 63 64#ifdef NG_SEPARATE_MALLOC 65MALLOC_DEFINE(M_NETGRAPH_L2TP, "netgraph_l2tp", "netgraph l2tp node"); 66#else 67#define M_NETGRAPH_L2TP M_NETGRAPH 68#endif 69 70/* L2TP header format (first 2 bytes only) */ 71#define L2TP_HDR_CTRL 0x8000 /* control packet */ 72#define L2TP_HDR_LEN 0x4000 /* has length field */ 73#define L2TP_HDR_SEQ 0x0800 /* has ns, nr fields */ 74#define L2TP_HDR_OFF 0x0200 /* has offset field */ 75#define L2TP_HDR_PRIO 0x0100 /* give priority */ 76#define L2TP_HDR_VERS_MASK 0x000f /* version field mask */ 77#define L2TP_HDR_VERSION 0x0002 /* version field */ 78 79/* Bits that must be zero or one in first two bytes of header */ 80#define L2TP_CTRL_0BITS 0x030d /* ctrl: must be 0 */ 81#define L2TP_CTRL_1BITS 0xc802 /* ctrl: must be 1 */ 82#define L2TP_DATA_0BITS 0x800d /* data: must be 0 */ 83#define L2TP_DATA_1BITS 0x0002 /* data: must be 1 */ 84 85/* Standard xmit ctrl and data header bits */ 86#define L2TP_CTRL_HDR (L2TP_HDR_CTRL | L2TP_HDR_LEN \ 87 | L2TP_HDR_SEQ | L2TP_HDR_VERSION) 88#define L2TP_DATA_HDR (L2TP_HDR_VERSION) /* optional: len, seq */ 89 90/* Some hard coded values */ 91#define L2TP_MAX_XWIN 16 /* my max xmit window */ 92#define L2TP_MAX_REXMIT 5 /* default max rexmit */ 93#define L2TP_MAX_REXMIT_TO 30 /* default rexmit to */ 94#define L2TP_DELAYED_ACK ((hz + 19) / 20) /* delayed ack: 50 ms */ 95 96/* Default data sequence number configuration for new sessions */ 97#define L2TP_CONTROL_DSEQ 1 /* we are the lns */ 98#define L2TP_ENABLE_DSEQ 1 /* enable data seq # */ 99 100/* Compare sequence numbers using circular math */ 101#define L2TP_SEQ_DIFF(x, y) ((int)((int16_t)(x) - (int16_t)(y))) 102 103/* 104 * Sequence number state 105 * 106 * Invariants: 107 * - If cwnd < ssth, we're doing slow start, otherwise congestion avoidance 108 * - The number of unacknowledged xmit packets is (ns - rack) <= seq->wmax 109 * - The first (ns - rack) mbuf's in xwin[] array are copies of these 110 * unacknowledged packets; the remainder of xwin[] consists first of 111 * zero or more further untransmitted packets in the transmit queue 112 * - We try to keep the peer's receive window as full as possible. 113 * Therefore, (i < cwnd && xwin[i] != NULL) implies (ns - rack) > i. 114 * - rack_timer is running iff (ns - rack) > 0 (unack'd xmit'd pkts) 115 * - If xack != nr, there are unacknowledged recv packet(s) (delayed ack) 116 * - xack_timer is running iff xack != nr (unack'd rec'd pkts) 117 */ 118struct l2tp_seq { 119 u_int16_t ns; /* next xmit seq we send */ 120 u_int16_t nr; /* next recv seq we expect */ 121 u_int16_t rack; /* last 'nr' we rec'd */ 122 u_int16_t xack; /* last 'nr' we sent */ 123 u_int16_t wmax; /* peer's max recv window */ 124 u_int16_t cwnd; /* current congestion window */ 125 u_int16_t ssth; /* slow start threshold */ 126 u_int16_t acks; /* # consecutive acks rec'd */ 127 u_int16_t rexmits; /* # retransmits sent */ 128 u_int16_t max_rexmits; /* max # retransmits sent */ 129 u_int16_t max_rexmit_to; /* max retransmit timeout */ 130 struct callout rack_timer; /* retransmit timer */ 131 struct callout xack_timer; /* delayed ack timer */ 132 u_char rack_timer_running; /* xmit timer running */ 133 u_char xack_timer_running; /* ack timer running */ 134 struct mbuf *xwin[L2TP_MAX_XWIN]; /* transmit window */ 135}; 136 137/* Node private data */ 138struct ng_l2tp_private { 139 node_p node; /* back pointer to node */ 140 hook_p ctrl; /* hook to upper layers */ 141 hook_p lower; /* hook to lower layers */ 142 struct ng_l2tp_config conf; /* node configuration */ 143 struct ng_l2tp_stats stats; /* node statistics */ 144 struct l2tp_seq seq; /* ctrl sequence number state */ 145 ng_ID_t ftarget; /* failure message target */ 146}; 147typedef struct ng_l2tp_private *priv_p; 148 149/* Hook private data (data session hooks only) */ 150struct ng_l2tp_hook_private { 151 struct ng_l2tp_sess_config conf; /* hook/session config */ 152 u_int16_t ns; /* data ns sequence number */ 153 u_int16_t nr; /* data nr sequence number */ 154}; 155typedef struct ng_l2tp_hook_private *hookpriv_p; 156 157/* Netgraph node methods */ 158static ng_constructor_t ng_l2tp_constructor; 159static ng_rcvmsg_t ng_l2tp_rcvmsg; 160static ng_shutdown_t ng_l2tp_shutdown; 161static ng_newhook_t ng_l2tp_newhook; 162static ng_rcvdata_t ng_l2tp_rcvdata; 163static ng_disconnect_t ng_l2tp_disconnect; 164 165/* Internal functions */ 166static int ng_l2tp_recv_lower(node_p node, item_p item); 167static int ng_l2tp_recv_ctrl(node_p node, item_p item); 168static int ng_l2tp_recv_data(node_p node, item_p item, hookpriv_p hpriv); 169 170static int ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns); 171 172static void ng_l2tp_seq_init(priv_p priv); 173static int ng_l2tp_seq_adjust(priv_p priv, 174 const struct ng_l2tp_config *conf); 175static void ng_l2tp_seq_reset(priv_p priv); 176static void ng_l2tp_seq_failure(priv_p priv); 177static void ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr); 178static int ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns); 179static void ng_l2tp_seq_xack_timeout(void *arg); 180static void ng_l2tp_seq_rack_timeout(void *arg); 181 182static ng_fn_eachhook ng_l2tp_find_session; 183static ng_fn_eachhook ng_l2tp_reset_session; 184 185#ifdef INVARIANTS 186static void ng_l2tp_seq_check(struct l2tp_seq *seq); 187#endif 188 189/* Parse type for struct ng_l2tp_config */ 190static const struct ng_parse_struct_field 191 ng_l2tp_config_type_fields[] = NG_L2TP_CONFIG_TYPE_INFO; 192static const struct ng_parse_type ng_l2tp_config_type = { 193 &ng_parse_struct_type, 194 &ng_l2tp_config_type_fields, 195}; 196 197/* Parse type for struct ng_l2tp_sess_config */ 198static const struct ng_parse_struct_field 199 ng_l2tp_sess_config_type_fields[] = NG_L2TP_SESS_CONFIG_TYPE_INFO; 200static const struct ng_parse_type ng_l2tp_sess_config_type = { 201 &ng_parse_struct_type, 202 &ng_l2tp_sess_config_type_fields, 203}; 204 205/* Parse type for struct ng_l2tp_stats */ 206static const struct ng_parse_struct_field 207 ng_l2tp_stats_type_fields[] = NG_L2TP_STATS_TYPE_INFO; 208static const struct ng_parse_type ng_pptp_stats_type = { 209 &ng_parse_struct_type, 210 &ng_l2tp_stats_type_fields 211}; 212 213/* List of commands and how to convert arguments to/from ASCII */ 214static const struct ng_cmdlist ng_l2tp_cmdlist[] = { 215 { 216 NGM_L2TP_COOKIE, 217 NGM_L2TP_SET_CONFIG, 218 "setconfig", 219 &ng_l2tp_config_type, 220 NULL 221 }, 222 { 223 NGM_L2TP_COOKIE, 224 NGM_L2TP_GET_CONFIG, 225 "getconfig", 226 NULL, 227 &ng_l2tp_config_type 228 }, 229 { 230 NGM_L2TP_COOKIE, 231 NGM_L2TP_SET_SESS_CONFIG, 232 "setsessconfig", 233 &ng_l2tp_sess_config_type, 234 NULL 235 }, 236 { 237 NGM_L2TP_COOKIE, 238 NGM_L2TP_GET_SESS_CONFIG, 239 "getsessconfig", 240 &ng_parse_hint16_type, 241 &ng_l2tp_sess_config_type 242 }, 243 { 244 NGM_L2TP_COOKIE, 245 NGM_L2TP_GET_STATS, 246 "getstats", 247 NULL, 248 &ng_pptp_stats_type 249 }, 250 { 251 NGM_L2TP_COOKIE, 252 NGM_L2TP_CLR_STATS, 253 "clrstats", 254 NULL, 255 NULL 256 }, 257 { 258 NGM_L2TP_COOKIE, 259 NGM_L2TP_GETCLR_STATS, 260 "getclrstats", 261 NULL, 262 &ng_pptp_stats_type 263 }, 264 { 265 NGM_L2TP_COOKIE, 266 NGM_L2TP_ACK_FAILURE, 267 "ackfailure", 268 NULL, 269 NULL 270 }, 271 { 0 } 272}; 273 274/* Node type descriptor */ 275static struct ng_type ng_l2tp_typestruct = { 276 NG_ABI_VERSION, 277 NG_L2TP_NODE_TYPE, 278 NULL, 279 ng_l2tp_constructor, 280 ng_l2tp_rcvmsg, 281 ng_l2tp_shutdown, 282 ng_l2tp_newhook, 283 NULL, 284 NULL, 285 ng_l2tp_rcvdata, 286 ng_l2tp_disconnect, 287 ng_l2tp_cmdlist 288}; 289NETGRAPH_INIT(l2tp, &ng_l2tp_typestruct); 290 291/* Sequence number state sanity checking */ 292#ifdef INVARIANTS 293#define L2TP_SEQ_CHECK(seq) ng_l2tp_seq_check(seq) 294#else 295#define L2TP_SEQ_CHECK(x) do { } while (0) 296#endif 297
| 59 60#include <netgraph/ng_message.h> 61#include <netgraph/netgraph.h> 62#include <netgraph/ng_parse.h> 63#include <netgraph/ng_l2tp.h> 64 65#ifdef NG_SEPARATE_MALLOC 66MALLOC_DEFINE(M_NETGRAPH_L2TP, "netgraph_l2tp", "netgraph l2tp node"); 67#else 68#define M_NETGRAPH_L2TP M_NETGRAPH 69#endif 70 71/* L2TP header format (first 2 bytes only) */ 72#define L2TP_HDR_CTRL 0x8000 /* control packet */ 73#define L2TP_HDR_LEN 0x4000 /* has length field */ 74#define L2TP_HDR_SEQ 0x0800 /* has ns, nr fields */ 75#define L2TP_HDR_OFF 0x0200 /* has offset field */ 76#define L2TP_HDR_PRIO 0x0100 /* give priority */ 77#define L2TP_HDR_VERS_MASK 0x000f /* version field mask */ 78#define L2TP_HDR_VERSION 0x0002 /* version field */ 79 80/* Bits that must be zero or one in first two bytes of header */ 81#define L2TP_CTRL_0BITS 0x030d /* ctrl: must be 0 */ 82#define L2TP_CTRL_1BITS 0xc802 /* ctrl: must be 1 */ 83#define L2TP_DATA_0BITS 0x800d /* data: must be 0 */ 84#define L2TP_DATA_1BITS 0x0002 /* data: must be 1 */ 85 86/* Standard xmit ctrl and data header bits */ 87#define L2TP_CTRL_HDR (L2TP_HDR_CTRL | L2TP_HDR_LEN \ 88 | L2TP_HDR_SEQ | L2TP_HDR_VERSION) 89#define L2TP_DATA_HDR (L2TP_HDR_VERSION) /* optional: len, seq */ 90 91/* Some hard coded values */ 92#define L2TP_MAX_XWIN 16 /* my max xmit window */ 93#define L2TP_MAX_REXMIT 5 /* default max rexmit */ 94#define L2TP_MAX_REXMIT_TO 30 /* default rexmit to */ 95#define L2TP_DELAYED_ACK ((hz + 19) / 20) /* delayed ack: 50 ms */ 96 97/* Default data sequence number configuration for new sessions */ 98#define L2TP_CONTROL_DSEQ 1 /* we are the lns */ 99#define L2TP_ENABLE_DSEQ 1 /* enable data seq # */ 100 101/* Compare sequence numbers using circular math */ 102#define L2TP_SEQ_DIFF(x, y) ((int)((int16_t)(x) - (int16_t)(y))) 103 104/* 105 * Sequence number state 106 * 107 * Invariants: 108 * - If cwnd < ssth, we're doing slow start, otherwise congestion avoidance 109 * - The number of unacknowledged xmit packets is (ns - rack) <= seq->wmax 110 * - The first (ns - rack) mbuf's in xwin[] array are copies of these 111 * unacknowledged packets; the remainder of xwin[] consists first of 112 * zero or more further untransmitted packets in the transmit queue 113 * - We try to keep the peer's receive window as full as possible. 114 * Therefore, (i < cwnd && xwin[i] != NULL) implies (ns - rack) > i. 115 * - rack_timer is running iff (ns - rack) > 0 (unack'd xmit'd pkts) 116 * - If xack != nr, there are unacknowledged recv packet(s) (delayed ack) 117 * - xack_timer is running iff xack != nr (unack'd rec'd pkts) 118 */ 119struct l2tp_seq { 120 u_int16_t ns; /* next xmit seq we send */ 121 u_int16_t nr; /* next recv seq we expect */ 122 u_int16_t rack; /* last 'nr' we rec'd */ 123 u_int16_t xack; /* last 'nr' we sent */ 124 u_int16_t wmax; /* peer's max recv window */ 125 u_int16_t cwnd; /* current congestion window */ 126 u_int16_t ssth; /* slow start threshold */ 127 u_int16_t acks; /* # consecutive acks rec'd */ 128 u_int16_t rexmits; /* # retransmits sent */ 129 u_int16_t max_rexmits; /* max # retransmits sent */ 130 u_int16_t max_rexmit_to; /* max retransmit timeout */ 131 struct callout rack_timer; /* retransmit timer */ 132 struct callout xack_timer; /* delayed ack timer */ 133 u_char rack_timer_running; /* xmit timer running */ 134 u_char xack_timer_running; /* ack timer running */ 135 struct mbuf *xwin[L2TP_MAX_XWIN]; /* transmit window */ 136}; 137 138/* Node private data */ 139struct ng_l2tp_private { 140 node_p node; /* back pointer to node */ 141 hook_p ctrl; /* hook to upper layers */ 142 hook_p lower; /* hook to lower layers */ 143 struct ng_l2tp_config conf; /* node configuration */ 144 struct ng_l2tp_stats stats; /* node statistics */ 145 struct l2tp_seq seq; /* ctrl sequence number state */ 146 ng_ID_t ftarget; /* failure message target */ 147}; 148typedef struct ng_l2tp_private *priv_p; 149 150/* Hook private data (data session hooks only) */ 151struct ng_l2tp_hook_private { 152 struct ng_l2tp_sess_config conf; /* hook/session config */ 153 u_int16_t ns; /* data ns sequence number */ 154 u_int16_t nr; /* data nr sequence number */ 155}; 156typedef struct ng_l2tp_hook_private *hookpriv_p; 157 158/* Netgraph node methods */ 159static ng_constructor_t ng_l2tp_constructor; 160static ng_rcvmsg_t ng_l2tp_rcvmsg; 161static ng_shutdown_t ng_l2tp_shutdown; 162static ng_newhook_t ng_l2tp_newhook; 163static ng_rcvdata_t ng_l2tp_rcvdata; 164static ng_disconnect_t ng_l2tp_disconnect; 165 166/* Internal functions */ 167static int ng_l2tp_recv_lower(node_p node, item_p item); 168static int ng_l2tp_recv_ctrl(node_p node, item_p item); 169static int ng_l2tp_recv_data(node_p node, item_p item, hookpriv_p hpriv); 170 171static int ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns); 172 173static void ng_l2tp_seq_init(priv_p priv); 174static int ng_l2tp_seq_adjust(priv_p priv, 175 const struct ng_l2tp_config *conf); 176static void ng_l2tp_seq_reset(priv_p priv); 177static void ng_l2tp_seq_failure(priv_p priv); 178static void ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr); 179static int ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns); 180static void ng_l2tp_seq_xack_timeout(void *arg); 181static void ng_l2tp_seq_rack_timeout(void *arg); 182 183static ng_fn_eachhook ng_l2tp_find_session; 184static ng_fn_eachhook ng_l2tp_reset_session; 185 186#ifdef INVARIANTS 187static void ng_l2tp_seq_check(struct l2tp_seq *seq); 188#endif 189 190/* Parse type for struct ng_l2tp_config */ 191static const struct ng_parse_struct_field 192 ng_l2tp_config_type_fields[] = NG_L2TP_CONFIG_TYPE_INFO; 193static const struct ng_parse_type ng_l2tp_config_type = { 194 &ng_parse_struct_type, 195 &ng_l2tp_config_type_fields, 196}; 197 198/* Parse type for struct ng_l2tp_sess_config */ 199static const struct ng_parse_struct_field 200 ng_l2tp_sess_config_type_fields[] = NG_L2TP_SESS_CONFIG_TYPE_INFO; 201static const struct ng_parse_type ng_l2tp_sess_config_type = { 202 &ng_parse_struct_type, 203 &ng_l2tp_sess_config_type_fields, 204}; 205 206/* Parse type for struct ng_l2tp_stats */ 207static const struct ng_parse_struct_field 208 ng_l2tp_stats_type_fields[] = NG_L2TP_STATS_TYPE_INFO; 209static const struct ng_parse_type ng_pptp_stats_type = { 210 &ng_parse_struct_type, 211 &ng_l2tp_stats_type_fields 212}; 213 214/* List of commands and how to convert arguments to/from ASCII */ 215static const struct ng_cmdlist ng_l2tp_cmdlist[] = { 216 { 217 NGM_L2TP_COOKIE, 218 NGM_L2TP_SET_CONFIG, 219 "setconfig", 220 &ng_l2tp_config_type, 221 NULL 222 }, 223 { 224 NGM_L2TP_COOKIE, 225 NGM_L2TP_GET_CONFIG, 226 "getconfig", 227 NULL, 228 &ng_l2tp_config_type 229 }, 230 { 231 NGM_L2TP_COOKIE, 232 NGM_L2TP_SET_SESS_CONFIG, 233 "setsessconfig", 234 &ng_l2tp_sess_config_type, 235 NULL 236 }, 237 { 238 NGM_L2TP_COOKIE, 239 NGM_L2TP_GET_SESS_CONFIG, 240 "getsessconfig", 241 &ng_parse_hint16_type, 242 &ng_l2tp_sess_config_type 243 }, 244 { 245 NGM_L2TP_COOKIE, 246 NGM_L2TP_GET_STATS, 247 "getstats", 248 NULL, 249 &ng_pptp_stats_type 250 }, 251 { 252 NGM_L2TP_COOKIE, 253 NGM_L2TP_CLR_STATS, 254 "clrstats", 255 NULL, 256 NULL 257 }, 258 { 259 NGM_L2TP_COOKIE, 260 NGM_L2TP_GETCLR_STATS, 261 "getclrstats", 262 NULL, 263 &ng_pptp_stats_type 264 }, 265 { 266 NGM_L2TP_COOKIE, 267 NGM_L2TP_ACK_FAILURE, 268 "ackfailure", 269 NULL, 270 NULL 271 }, 272 { 0 } 273}; 274 275/* Node type descriptor */ 276static struct ng_type ng_l2tp_typestruct = { 277 NG_ABI_VERSION, 278 NG_L2TP_NODE_TYPE, 279 NULL, 280 ng_l2tp_constructor, 281 ng_l2tp_rcvmsg, 282 ng_l2tp_shutdown, 283 ng_l2tp_newhook, 284 NULL, 285 NULL, 286 ng_l2tp_rcvdata, 287 ng_l2tp_disconnect, 288 ng_l2tp_cmdlist 289}; 290NETGRAPH_INIT(l2tp, &ng_l2tp_typestruct); 291 292/* Sequence number state sanity checking */ 293#ifdef INVARIANTS 294#define L2TP_SEQ_CHECK(seq) ng_l2tp_seq_check(seq) 295#else 296#define L2TP_SEQ_CHECK(x) do { } while (0) 297#endif 298
|
298/* mem*() macros */
| 299/* memmove macro */
|
299#define memmove(d, s, l) ovbcopy(s, d, l)
| 300#define memmove(d, s, l) ovbcopy(s, d, l)
|
300#define memset(d, z, l) bzero(d, l) /* XXX */
| |
301 302/* Whether to use m_copypacket() or m_dup() */ 303#define L2TP_COPY_MBUF m_copypacket 304 305/************************************************************************ 306 NETGRAPH NODE STUFF 307************************************************************************/ 308 309/* 310 * Node type constructor 311 */ 312static int 313ng_l2tp_constructor(node_p node) 314{ 315 priv_p priv; 316 317 /* Allocate private structure */ 318 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_L2TP, M_NOWAIT | M_ZERO); 319 if (priv == NULL) 320 return (ENOMEM); 321 NG_NODE_SET_PRIVATE(node, priv); 322 priv->node = node; 323 324 /* Apply a semi-reasonable default configuration */ 325 priv->conf.peer_win = 1; 326 priv->conf.rexmit_max = L2TP_MAX_REXMIT; 327 priv->conf.rexmit_max_to = L2TP_MAX_REXMIT_TO; 328 329 /* Initialize sequence number state */ 330 ng_l2tp_seq_init(priv); 331 332 /* Done */ 333 return (0); 334} 335 336/* 337 * Give our OK for a hook to be added. 338 */ 339static int 340ng_l2tp_newhook(node_p node, hook_p hook, const char *name) 341{ 342 const priv_p priv = NG_NODE_PRIVATE(node); 343 344 /* Check hook name */ 345 if (strcmp(name, NG_L2TP_HOOK_CTRL) == 0) { 346 if (priv->ctrl != NULL) 347 return (EISCONN); 348 priv->ctrl = hook; 349 } else if (strcmp(name, NG_L2TP_HOOK_LOWER) == 0) { 350 if (priv->lower != NULL) 351 return (EISCONN); 352 priv->lower = hook; 353 } else { 354 static const char hexdig[16] = "0123456789abcdef"; 355 u_int16_t session_id; 356 hookpriv_p hpriv; 357 const char *hex; 358 int i; 359 int j; 360 361 /* Parse hook name to get session ID */ 362 if (strncmp(name, NG_L2TP_HOOK_SESSION_P, 363 sizeof(NG_L2TP_HOOK_SESSION_P) - 1) != 0) 364 return (EINVAL); 365 hex = name + sizeof(NG_L2TP_HOOK_SESSION_P) - 1; 366 for (session_id = i = 0; i < 4; i++) { 367 for (j = 0; j < 16 && hex[i] != hexdig[j]; j++); 368 if (j == 16) 369 return (EINVAL); 370 session_id = (session_id << 4) | j; 371 } 372 if (hex[i] != '\0') 373 return (EINVAL); 374 375 /* Create hook private structure */ 376 MALLOC(hpriv, hookpriv_p, 377 sizeof(*hpriv), M_NETGRAPH_L2TP, M_NOWAIT | M_ZERO); 378 if (hpriv == NULL) 379 return (ENOMEM); 380 hpriv->conf.session_id = htons(session_id); 381 hpriv->conf.control_dseq = L2TP_CONTROL_DSEQ; 382 hpriv->conf.enable_dseq = L2TP_ENABLE_DSEQ; 383 NG_HOOK_SET_PRIVATE(hook, hpriv); 384 } 385 386 /* Done */ 387 return (0); 388} 389 390/* 391 * Receive a control message. 392 */ 393static int 394ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook) 395{ 396 const priv_p priv = NG_NODE_PRIVATE(node); 397 struct ng_mesg *resp = NULL; 398 struct ng_mesg *msg; 399 int error = 0; 400 401 NGI_GET_MSG(item, msg); 402 switch (msg->header.typecookie) { 403 case NGM_L2TP_COOKIE: 404 switch (msg->header.cmd) { 405 case NGM_L2TP_SET_CONFIG: 406 { 407 struct ng_l2tp_config *const conf = 408 (struct ng_l2tp_config *)msg->data; 409 410 /* Check for invalid or illegal config */ 411 if (msg->header.arglen != sizeof(*conf)) { 412 error = EINVAL; 413 break; 414 } 415 conf->enabled = !!conf->enabled; 416 conf->match_id = !!conf->match_id; 417 conf->tunnel_id = htons(conf->tunnel_id); 418 conf->peer_id = htons(conf->peer_id); 419 if (priv->conf.enabled 420 && ((priv->conf.tunnel_id != 0 421 && conf->tunnel_id != priv->conf.tunnel_id) 422 || ((priv->conf.peer_id != 0 423 && conf->peer_id != priv->conf.peer_id)))) { 424 error = EBUSY; 425 break; 426 } 427 428 /* Save calling node as failure target */ 429 priv->ftarget = NGI_RETADDR(item); 430 431 /* Adjust sequence number state */ 432 if ((error = ng_l2tp_seq_adjust(priv, conf)) != 0) 433 break; 434 435 /* Update node's config */ 436 priv->conf = *conf; 437 break; 438 } 439 case NGM_L2TP_GET_CONFIG: 440 { 441 struct ng_l2tp_config *conf; 442 443 NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 444 if (resp == NULL) { 445 error = ENOMEM; 446 break; 447 } 448 conf = (struct ng_l2tp_config *)resp->data; 449 *conf = priv->conf; 450 451 /* Put ID's in host order */ 452 conf->tunnel_id = ntohs(conf->tunnel_id); 453 conf->peer_id = ntohs(conf->peer_id); 454 break; 455 } 456 case NGM_L2TP_SET_SESS_CONFIG: 457 { 458 struct ng_l2tp_sess_config *const conf = 459 (struct ng_l2tp_sess_config *)msg->data; 460 hookpriv_p hpriv; 461 hook_p hook; 462 463 /* Check for invalid or illegal config */ 464 if (msg->header.arglen != sizeof(*conf)) { 465 error = EINVAL; 466 break; 467 } 468 469 /* Put ID's in network order */ 470 conf->session_id = htons(conf->session_id); 471 conf->peer_id = htons(conf->peer_id); 472 473 /* Find matching hook */ 474 NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session, 475 (void *)(uintptr_t)conf->session_id, hook); 476 if (hook == NULL) { 477 error = ENOENT; 478 break; 479 } 480 hpriv = NG_HOOK_PRIVATE(hook); 481 482 /* Update hook's config */ 483 hpriv->conf = *conf; 484 break; 485 } 486 case NGM_L2TP_GET_SESS_CONFIG: 487 { 488 struct ng_l2tp_sess_config *conf; 489 u_int16_t session_id; 490 hookpriv_p hpriv; 491 hook_p hook; 492 493 /* Get session ID */ 494 if (msg->header.arglen != sizeof(session_id)) { 495 error = EINVAL; 496 break; 497 } 498 memcpy(&session_id, msg->data, 2); 499 session_id = htons(session_id); 500 501 /* Find matching hook */ 502 NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session, 503 (void *)(uintptr_t)session_id, hook); 504 if (hook == NULL) { 505 error = ENOENT; 506 break; 507 } 508 hpriv = NG_HOOK_PRIVATE(hook); 509 510 /* Send response */ 511 NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT); 512 if (resp == NULL) { 513 error = ENOMEM; 514 break; 515 } 516 conf = (struct ng_l2tp_sess_config *)resp->data; 517 *conf = hpriv->conf; 518 519 /* Put ID's in host order */ 520 conf->session_id = ntohs(conf->session_id); 521 conf->peer_id = ntohs(conf->peer_id); 522 break; 523 } 524 case NGM_L2TP_GET_STATS: 525 case NGM_L2TP_CLR_STATS: 526 case NGM_L2TP_GETCLR_STATS: 527 { 528 if (msg->header.cmd != NGM_L2TP_CLR_STATS) { 529 NG_MKRESPONSE(resp, msg, 530 sizeof(priv->stats), M_NOWAIT); 531 if (resp == NULL) { 532 error = ENOMEM; 533 break; 534 } 535 memcpy(resp->data, 536 &priv->stats, sizeof(priv->stats)); 537 } 538 if (msg->header.cmd != NGM_L2TP_GET_STATS) 539 memset(&priv->stats, 0, sizeof(priv->stats)); 540 break; 541 } 542 default: 543 error = EINVAL; 544 break; 545 } 546 break; 547 default: 548 error = EINVAL; 549 break; 550 } 551 552 /* Done */ 553 NG_RESPOND_MSG(error, node, item, resp); 554 NG_FREE_MSG(msg); 555 return (error); 556} 557 558/* 559 * Receive incoming data on a hook. 560 */ 561static int 562ng_l2tp_rcvdata(hook_p hook, item_p item) 563{ 564 const node_p node = NG_HOOK_NODE(hook); 565 const priv_p priv = NG_NODE_PRIVATE(node); 566 int error; 567 568 /* Sanity check */ 569 L2TP_SEQ_CHECK(&priv->seq); 570 571 /* If not configured, reject */ 572 if (!priv->conf.enabled) { 573 NG_FREE_ITEM(item); 574 return (ENXIO); 575 } 576 577 /* Handle incoming frame from below */ 578 if (hook == priv->lower) { 579 error = ng_l2tp_recv_lower(node, item); 580 goto done; 581 } 582 583 /* Handle outgoing control frame */ 584 if (hook == priv->ctrl) { 585 error = ng_l2tp_recv_ctrl(node, item); 586 goto done; 587 } 588 589 /* Handle outgoing data frame */ 590 error = ng_l2tp_recv_data(node, item, NG_HOOK_PRIVATE(hook)); 591 592done: 593 /* Done */ 594 L2TP_SEQ_CHECK(&priv->seq); 595 return (error); 596} 597 598/* 599 * Destroy node 600 */ 601static int 602ng_l2tp_shutdown(node_p node) 603{ 604 const priv_p priv = NG_NODE_PRIVATE(node); 605 struct l2tp_seq *const seq = &priv->seq; 606 607 /* Sanity check */ 608 L2TP_SEQ_CHECK(seq); 609 610 /* Reset sequence number state */ 611 ng_l2tp_seq_reset(priv); 612 613 /* Free private data if neither timer is running */ 614 if (!seq->rack_timer_running && !seq->xack_timer_running) { 615 FREE(priv, M_NETGRAPH_L2TP); 616 NG_NODE_SET_PRIVATE(node, NULL); 617 } 618 619 /* Unref node */ 620 NG_NODE_UNREF(node); 621 return (0); 622} 623 624/* 625 * Hook disconnection 626 */ 627static int 628ng_l2tp_disconnect(hook_p hook) 629{ 630 const node_p node = NG_HOOK_NODE(hook); 631 const priv_p priv = NG_NODE_PRIVATE(node); 632 633 /* Zero out hook pointer */ 634 if (hook == priv->ctrl) 635 priv->ctrl = NULL; 636 else if (hook == priv->lower) 637 priv->lower = NULL; 638 else { 639 FREE(NG_HOOK_PRIVATE(hook), M_NETGRAPH_L2TP); 640 NG_HOOK_SET_PRIVATE(hook, NULL); 641 } 642 643 /* Go away if no longer connected to anything */ 644 if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) 645 ng_rmnode_self(node); 646 return (0); 647} 648 649/************************************************************************* 650 INTERNAL FUNCTIONS 651*************************************************************************/ 652 653/* 654 * Find the hook with a given session ID. 655 */ 656static int 657ng_l2tp_find_session(hook_p hook, void *arg) 658{ 659 const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook); 660 const u_int16_t sid = (u_int16_t)(uintptr_t)arg; 661 662 if (hpriv == NULL || hpriv->conf.session_id != sid) 663 return (-1); 664 return (0); 665} 666 667/* 668 * Reset a hook's session state. 669 */ 670static int 671ng_l2tp_reset_session(hook_p hook, void *arg) 672{ 673 const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook); 674 675 if (hpriv != NULL) { 676 hpriv->conf.control_dseq = 0; 677 hpriv->conf.enable_dseq = 0; 678 hpriv->nr = 0; 679 hpriv->ns = 0; 680 } 681 return (-1); 682} 683 684/* 685 * Handle an incoming frame from below. 686 */ 687static int 688ng_l2tp_recv_lower(node_p node, item_p item) 689{ 690 static const u_int16_t req_bits[2][2] = { 691 { L2TP_DATA_0BITS, L2TP_DATA_1BITS }, 692 { L2TP_CTRL_0BITS, L2TP_CTRL_1BITS }, 693 }; 694 const priv_p priv = NG_NODE_PRIVATE(node); 695 hookpriv_p hpriv = NULL; 696 hook_p hook = NULL; 697 u_int16_t ids[2]; 698 struct mbuf *m; 699 u_int16_t hdr; 700 u_int16_t ns; 701 u_int16_t nr; 702 int is_ctrl; 703 int error; 704 int len; 705 706 /* Grab mbuf */ 707 NGI_GET_M(item, m); 708 709 /* Update stats */ 710 priv->stats.recvPackets++; 711 priv->stats.recvOctets += m->m_pkthdr.len; 712 713 /* Get initial header */ 714 if (m->m_pkthdr.len < 6) { 715 priv->stats.recvRunts++; 716 NG_FREE_ITEM(item); 717 NG_FREE_M(m); 718 return (EINVAL); 719 } 720 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 721 priv->stats.memoryFailures++; 722 NG_FREE_ITEM(item); 723 return (EINVAL); 724 } 725 hdr = ntohs(*mtod(m, u_int16_t *)); 726 m_adj(m, 2); 727 728 /* Check required header bits and minimum length */ 729 is_ctrl = (hdr & L2TP_HDR_CTRL) != 0; 730 if ((hdr & req_bits[is_ctrl][0]) != 0 731 || (~hdr & req_bits[is_ctrl][1]) != 0) { 732 priv->stats.recvInvalid++; 733 NG_FREE_ITEM(item); 734 NG_FREE_M(m); 735 return (EINVAL); 736 } 737 if (m->m_pkthdr.len < 4 /* tunnel, session id */ 738 + (2 * ((hdr & L2TP_HDR_LEN) != 0)) /* length field */ 739 + (4 * ((hdr & L2TP_HDR_SEQ) != 0)) /* seq # fields */ 740 + (2 * ((hdr & L2TP_HDR_OFF) != 0))) { /* offset field */ 741 priv->stats.recvRunts++; 742 NG_FREE_ITEM(item); 743 NG_FREE_M(m); 744 return (EINVAL); 745 } 746 747 /* Get and validate length field if present */ 748 if ((hdr & L2TP_HDR_LEN) != 0) { 749 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 750 priv->stats.memoryFailures++; 751 NG_FREE_ITEM(item); 752 return (EINVAL); 753 } 754 len = (u_int16_t)ntohs(*mtod(m, u_int16_t *)) - 4; 755 m_adj(m, 2); 756 if (len < 0 || len > m->m_pkthdr.len) { 757 priv->stats.recvInvalid++; 758 NG_FREE_ITEM(item); 759 NG_FREE_M(m); 760 return (EINVAL); 761 } 762 if (len < m->m_pkthdr.len) /* trim extra bytes */ 763 m_adj(m, -(m->m_pkthdr.len - len)); 764 } 765 766 /* Get tunnel ID and session ID */ 767 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { 768 priv->stats.memoryFailures++; 769 NG_FREE_ITEM(item); 770 return (EINVAL); 771 } 772 memcpy(ids, mtod(m, u_int16_t *), 4); 773 m_adj(m, 4); 774 775 /* Check tunnel ID */ 776 if (ids[0] != priv->conf.tunnel_id 777 && (priv->conf.match_id || ids[0] != 0)) { 778 priv->stats.recvWrongTunnel++; 779 NG_FREE_ITEM(item); 780 NG_FREE_M(m); 781 return (EADDRNOTAVAIL); 782 } 783 784 /* Check session ID (for data packets only) */ 785 if ((hdr & L2TP_HDR_CTRL) == 0) { 786 NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session, 787 (void *)(uintptr_t)ids[1], hook); 788 if (hook == NULL) { 789 priv->stats.recvUnknownSID++; 790 NG_FREE_ITEM(item); 791 NG_FREE_M(m); 792 return (ENOTCONN); 793 } 794 hpriv = NG_HOOK_PRIVATE(hook); 795 } 796 797 /* Get Ns, Nr fields if present */ 798 if ((hdr & L2TP_HDR_SEQ) != 0) { 799 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { 800 priv->stats.memoryFailures++; 801 NG_FREE_ITEM(item); 802 return (EINVAL); 803 } 804 memcpy(&ns, &mtod(m, u_int16_t *)[0], 2); 805 ns = ntohs(ns); 806 memcpy(&nr, &mtod(m, u_int16_t *)[1], 2); 807 nr = ntohs(nr); 808 m_adj(m, 4); 809 } 810 811 /* Strip offset padding if present */ 812 if ((hdr & L2TP_HDR_OFF) != 0) { 813 u_int16_t offset; 814 815 /* Get length of offset padding */ 816 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 817 priv->stats.memoryFailures++; 818 NG_FREE_ITEM(item); 819 return (EINVAL); 820 } 821 memcpy(&offset, mtod(m, u_int16_t *), 2); 822 offset = ntohs(offset); 823 824 /* Trim offset padding */ 825 if (offset <= 2 || offset > m->m_pkthdr.len) { 826 priv->stats.recvInvalid++; 827 NG_FREE_ITEM(item); 828 NG_FREE_M(m); 829 return (EINVAL); 830 } 831 m_adj(m, offset); 832 } 833 834 /* Handle control packets */ 835 if ((hdr & L2TP_HDR_CTRL) != 0) { 836 837 /* Handle receive ack sequence number Nr */ 838 ng_l2tp_seq_recv_nr(priv, nr); 839 840 /* Discard ZLB packets */ 841 if (m->m_pkthdr.len == 0) { 842 priv->stats.recvZLBs++; 843 NG_FREE_ITEM(item); 844 NG_FREE_M(m); 845 return (0); 846 } 847 848 /* 849 * Prepend session ID to packet here: we don't want to accept 850 * the send sequence number Ns if we have to drop the packet 851 * later because of a memory error, because then the upper 852 * layer would never get the packet. 853 */ 854 M_PREPEND(m, 2, M_DONTWAIT); 855 if (m == NULL) { 856 priv->stats.memoryFailures++; 857 NG_FREE_ITEM(item); 858 return (ENOBUFS); 859 } 860 memcpy(mtod(m, u_int16_t *), &ids[1], 2); 861 862 /* Now handle send sequence number */ 863 if (ng_l2tp_seq_recv_ns(priv, ns) == -1) { 864 NG_FREE_ITEM(item); 865 NG_FREE_M(m); 866 return (0); 867 } 868 869 /* Deliver packet to upper layers */ 870 NG_FWD_NEW_DATA(error, item, priv->ctrl, m); 871 return (error); 872 } 873 874 /* Follow peer's lead in data sequencing, if configured to do so */ 875 if (!hpriv->conf.control_dseq) 876 hpriv->conf.enable_dseq = ((hdr & L2TP_HDR_SEQ) != 0); 877 878 /* Handle data sequence numbers if present and enabled */ 879 if ((hdr & L2TP_HDR_SEQ) != 0) { 880 if (hpriv->conf.enable_dseq 881 && L2TP_SEQ_DIFF(ns, hpriv->nr) < 0) { 882 NG_FREE_ITEM(item); /* duplicate or out of order */ 883 NG_FREE_M(m); 884 priv->stats.recvDataDrops++; 885 return (0); 886 } 887 hpriv->nr = ns + 1; 888 } 889 890 /* Drop empty data packets */ 891 if (m->m_pkthdr.len == 0) { 892 NG_FREE_ITEM(item); 893 NG_FREE_M(m); 894 return (0); 895 } 896 897 /* Deliver data */ 898 NG_FWD_NEW_DATA(error, item, hook, m); 899 return (error); 900} 901 902/* 903 * Handle an outgoing control frame. 904 */ 905static int 906ng_l2tp_recv_ctrl(node_p node, item_p item) 907{ 908 const priv_p priv = NG_NODE_PRIVATE(node); 909 struct l2tp_seq *const seq = &priv->seq; 910 struct mbuf *m; 911 int i; 912 913 /* Grab mbuf and discard other stuff XXX */ 914 NGI_GET_M(item, m); 915 NG_FREE_ITEM(item); 916 917 /* Packet should have session ID prepended */ 918 if (m->m_pkthdr.len < 2) { 919 priv->stats.xmitInvalid++; 920 m_freem(m); 921 return (EINVAL); 922 } 923 924 /* Check max length */ 925 if (m->m_pkthdr.len >= 0x10000 - 14) { 926 priv->stats.xmitTooBig++; 927 m_freem(m); 928 return (EOVERFLOW); 929 } 930 931 /* Find next empty slot in transmit queue */ 932 for (i = 0; i < L2TP_MAX_XWIN && seq->xwin[i] != NULL; i++); 933 if (i == L2TP_MAX_XWIN) { 934 priv->stats.xmitDrops++; 935 m_freem(m); 936 return (ENOBUFS); 937 } 938 seq->xwin[i] = m; 939 940 /* Sanity check receive ack timer state */ 941 KASSERT((i == 0) ^ seq->rack_timer_running, 942 ("%s: xwin %d full but rack timer %srunning", 943 __FUNCTION__, i, seq->rack_timer_running ? "" : "not ")); 944 945 /* If peer's receive window is already full, nothing else to do */ 946 if (i >= seq->cwnd) 947 return (0); 948 949 /* Start retransmit timer if not already running */ 950 if (!seq->rack_timer_running) { 951 callout_reset(&seq->rack_timer, 952 hz, ng_l2tp_seq_rack_timeout, node); 953 seq->rack_timer_running = 1; 954 NG_NODE_REF(node); 955 } 956 957 /* Copy packet */
| 301 302/* Whether to use m_copypacket() or m_dup() */ 303#define L2TP_COPY_MBUF m_copypacket 304 305/************************************************************************ 306 NETGRAPH NODE STUFF 307************************************************************************/ 308 309/* 310 * Node type constructor 311 */ 312static int 313ng_l2tp_constructor(node_p node) 314{ 315 priv_p priv; 316 317 /* Allocate private structure */ 318 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_L2TP, M_NOWAIT | M_ZERO); 319 if (priv == NULL) 320 return (ENOMEM); 321 NG_NODE_SET_PRIVATE(node, priv); 322 priv->node = node; 323 324 /* Apply a semi-reasonable default configuration */ 325 priv->conf.peer_win = 1; 326 priv->conf.rexmit_max = L2TP_MAX_REXMIT; 327 priv->conf.rexmit_max_to = L2TP_MAX_REXMIT_TO; 328 329 /* Initialize sequence number state */ 330 ng_l2tp_seq_init(priv); 331 332 /* Done */ 333 return (0); 334} 335 336/* 337 * Give our OK for a hook to be added. 338 */ 339static int 340ng_l2tp_newhook(node_p node, hook_p hook, const char *name) 341{ 342 const priv_p priv = NG_NODE_PRIVATE(node); 343 344 /* Check hook name */ 345 if (strcmp(name, NG_L2TP_HOOK_CTRL) == 0) { 346 if (priv->ctrl != NULL) 347 return (EISCONN); 348 priv->ctrl = hook; 349 } else if (strcmp(name, NG_L2TP_HOOK_LOWER) == 0) { 350 if (priv->lower != NULL) 351 return (EISCONN); 352 priv->lower = hook; 353 } else { 354 static const char hexdig[16] = "0123456789abcdef"; 355 u_int16_t session_id; 356 hookpriv_p hpriv; 357 const char *hex; 358 int i; 359 int j; 360 361 /* Parse hook name to get session ID */ 362 if (strncmp(name, NG_L2TP_HOOK_SESSION_P, 363 sizeof(NG_L2TP_HOOK_SESSION_P) - 1) != 0) 364 return (EINVAL); 365 hex = name + sizeof(NG_L2TP_HOOK_SESSION_P) - 1; 366 for (session_id = i = 0; i < 4; i++) { 367 for (j = 0; j < 16 && hex[i] != hexdig[j]; j++); 368 if (j == 16) 369 return (EINVAL); 370 session_id = (session_id << 4) | j; 371 } 372 if (hex[i] != '\0') 373 return (EINVAL); 374 375 /* Create hook private structure */ 376 MALLOC(hpriv, hookpriv_p, 377 sizeof(*hpriv), M_NETGRAPH_L2TP, M_NOWAIT | M_ZERO); 378 if (hpriv == NULL) 379 return (ENOMEM); 380 hpriv->conf.session_id = htons(session_id); 381 hpriv->conf.control_dseq = L2TP_CONTROL_DSEQ; 382 hpriv->conf.enable_dseq = L2TP_ENABLE_DSEQ; 383 NG_HOOK_SET_PRIVATE(hook, hpriv); 384 } 385 386 /* Done */ 387 return (0); 388} 389 390/* 391 * Receive a control message. 392 */ 393static int 394ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook) 395{ 396 const priv_p priv = NG_NODE_PRIVATE(node); 397 struct ng_mesg *resp = NULL; 398 struct ng_mesg *msg; 399 int error = 0; 400 401 NGI_GET_MSG(item, msg); 402 switch (msg->header.typecookie) { 403 case NGM_L2TP_COOKIE: 404 switch (msg->header.cmd) { 405 case NGM_L2TP_SET_CONFIG: 406 { 407 struct ng_l2tp_config *const conf = 408 (struct ng_l2tp_config *)msg->data; 409 410 /* Check for invalid or illegal config */ 411 if (msg->header.arglen != sizeof(*conf)) { 412 error = EINVAL; 413 break; 414 } 415 conf->enabled = !!conf->enabled; 416 conf->match_id = !!conf->match_id; 417 conf->tunnel_id = htons(conf->tunnel_id); 418 conf->peer_id = htons(conf->peer_id); 419 if (priv->conf.enabled 420 && ((priv->conf.tunnel_id != 0 421 && conf->tunnel_id != priv->conf.tunnel_id) 422 || ((priv->conf.peer_id != 0 423 && conf->peer_id != priv->conf.peer_id)))) { 424 error = EBUSY; 425 break; 426 } 427 428 /* Save calling node as failure target */ 429 priv->ftarget = NGI_RETADDR(item); 430 431 /* Adjust sequence number state */ 432 if ((error = ng_l2tp_seq_adjust(priv, conf)) != 0) 433 break; 434 435 /* Update node's config */ 436 priv->conf = *conf; 437 break; 438 } 439 case NGM_L2TP_GET_CONFIG: 440 { 441 struct ng_l2tp_config *conf; 442 443 NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 444 if (resp == NULL) { 445 error = ENOMEM; 446 break; 447 } 448 conf = (struct ng_l2tp_config *)resp->data; 449 *conf = priv->conf; 450 451 /* Put ID's in host order */ 452 conf->tunnel_id = ntohs(conf->tunnel_id); 453 conf->peer_id = ntohs(conf->peer_id); 454 break; 455 } 456 case NGM_L2TP_SET_SESS_CONFIG: 457 { 458 struct ng_l2tp_sess_config *const conf = 459 (struct ng_l2tp_sess_config *)msg->data; 460 hookpriv_p hpriv; 461 hook_p hook; 462 463 /* Check for invalid or illegal config */ 464 if (msg->header.arglen != sizeof(*conf)) { 465 error = EINVAL; 466 break; 467 } 468 469 /* Put ID's in network order */ 470 conf->session_id = htons(conf->session_id); 471 conf->peer_id = htons(conf->peer_id); 472 473 /* Find matching hook */ 474 NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session, 475 (void *)(uintptr_t)conf->session_id, hook); 476 if (hook == NULL) { 477 error = ENOENT; 478 break; 479 } 480 hpriv = NG_HOOK_PRIVATE(hook); 481 482 /* Update hook's config */ 483 hpriv->conf = *conf; 484 break; 485 } 486 case NGM_L2TP_GET_SESS_CONFIG: 487 { 488 struct ng_l2tp_sess_config *conf; 489 u_int16_t session_id; 490 hookpriv_p hpriv; 491 hook_p hook; 492 493 /* Get session ID */ 494 if (msg->header.arglen != sizeof(session_id)) { 495 error = EINVAL; 496 break; 497 } 498 memcpy(&session_id, msg->data, 2); 499 session_id = htons(session_id); 500 501 /* Find matching hook */ 502 NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session, 503 (void *)(uintptr_t)session_id, hook); 504 if (hook == NULL) { 505 error = ENOENT; 506 break; 507 } 508 hpriv = NG_HOOK_PRIVATE(hook); 509 510 /* Send response */ 511 NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT); 512 if (resp == NULL) { 513 error = ENOMEM; 514 break; 515 } 516 conf = (struct ng_l2tp_sess_config *)resp->data; 517 *conf = hpriv->conf; 518 519 /* Put ID's in host order */ 520 conf->session_id = ntohs(conf->session_id); 521 conf->peer_id = ntohs(conf->peer_id); 522 break; 523 } 524 case NGM_L2TP_GET_STATS: 525 case NGM_L2TP_CLR_STATS: 526 case NGM_L2TP_GETCLR_STATS: 527 { 528 if (msg->header.cmd != NGM_L2TP_CLR_STATS) { 529 NG_MKRESPONSE(resp, msg, 530 sizeof(priv->stats), M_NOWAIT); 531 if (resp == NULL) { 532 error = ENOMEM; 533 break; 534 } 535 memcpy(resp->data, 536 &priv->stats, sizeof(priv->stats)); 537 } 538 if (msg->header.cmd != NGM_L2TP_GET_STATS) 539 memset(&priv->stats, 0, sizeof(priv->stats)); 540 break; 541 } 542 default: 543 error = EINVAL; 544 break; 545 } 546 break; 547 default: 548 error = EINVAL; 549 break; 550 } 551 552 /* Done */ 553 NG_RESPOND_MSG(error, node, item, resp); 554 NG_FREE_MSG(msg); 555 return (error); 556} 557 558/* 559 * Receive incoming data on a hook. 560 */ 561static int 562ng_l2tp_rcvdata(hook_p hook, item_p item) 563{ 564 const node_p node = NG_HOOK_NODE(hook); 565 const priv_p priv = NG_NODE_PRIVATE(node); 566 int error; 567 568 /* Sanity check */ 569 L2TP_SEQ_CHECK(&priv->seq); 570 571 /* If not configured, reject */ 572 if (!priv->conf.enabled) { 573 NG_FREE_ITEM(item); 574 return (ENXIO); 575 } 576 577 /* Handle incoming frame from below */ 578 if (hook == priv->lower) { 579 error = ng_l2tp_recv_lower(node, item); 580 goto done; 581 } 582 583 /* Handle outgoing control frame */ 584 if (hook == priv->ctrl) { 585 error = ng_l2tp_recv_ctrl(node, item); 586 goto done; 587 } 588 589 /* Handle outgoing data frame */ 590 error = ng_l2tp_recv_data(node, item, NG_HOOK_PRIVATE(hook)); 591 592done: 593 /* Done */ 594 L2TP_SEQ_CHECK(&priv->seq); 595 return (error); 596} 597 598/* 599 * Destroy node 600 */ 601static int 602ng_l2tp_shutdown(node_p node) 603{ 604 const priv_p priv = NG_NODE_PRIVATE(node); 605 struct l2tp_seq *const seq = &priv->seq; 606 607 /* Sanity check */ 608 L2TP_SEQ_CHECK(seq); 609 610 /* Reset sequence number state */ 611 ng_l2tp_seq_reset(priv); 612 613 /* Free private data if neither timer is running */ 614 if (!seq->rack_timer_running && !seq->xack_timer_running) { 615 FREE(priv, M_NETGRAPH_L2TP); 616 NG_NODE_SET_PRIVATE(node, NULL); 617 } 618 619 /* Unref node */ 620 NG_NODE_UNREF(node); 621 return (0); 622} 623 624/* 625 * Hook disconnection 626 */ 627static int 628ng_l2tp_disconnect(hook_p hook) 629{ 630 const node_p node = NG_HOOK_NODE(hook); 631 const priv_p priv = NG_NODE_PRIVATE(node); 632 633 /* Zero out hook pointer */ 634 if (hook == priv->ctrl) 635 priv->ctrl = NULL; 636 else if (hook == priv->lower) 637 priv->lower = NULL; 638 else { 639 FREE(NG_HOOK_PRIVATE(hook), M_NETGRAPH_L2TP); 640 NG_HOOK_SET_PRIVATE(hook, NULL); 641 } 642 643 /* Go away if no longer connected to anything */ 644 if (NG_NODE_NUMHOOKS(node) == 0 && NG_NODE_IS_VALID(node)) 645 ng_rmnode_self(node); 646 return (0); 647} 648 649/************************************************************************* 650 INTERNAL FUNCTIONS 651*************************************************************************/ 652 653/* 654 * Find the hook with a given session ID. 655 */ 656static int 657ng_l2tp_find_session(hook_p hook, void *arg) 658{ 659 const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook); 660 const u_int16_t sid = (u_int16_t)(uintptr_t)arg; 661 662 if (hpriv == NULL || hpriv->conf.session_id != sid) 663 return (-1); 664 return (0); 665} 666 667/* 668 * Reset a hook's session state. 669 */ 670static int 671ng_l2tp_reset_session(hook_p hook, void *arg) 672{ 673 const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook); 674 675 if (hpriv != NULL) { 676 hpriv->conf.control_dseq = 0; 677 hpriv->conf.enable_dseq = 0; 678 hpriv->nr = 0; 679 hpriv->ns = 0; 680 } 681 return (-1); 682} 683 684/* 685 * Handle an incoming frame from below. 686 */ 687static int 688ng_l2tp_recv_lower(node_p node, item_p item) 689{ 690 static const u_int16_t req_bits[2][2] = { 691 { L2TP_DATA_0BITS, L2TP_DATA_1BITS }, 692 { L2TP_CTRL_0BITS, L2TP_CTRL_1BITS }, 693 }; 694 const priv_p priv = NG_NODE_PRIVATE(node); 695 hookpriv_p hpriv = NULL; 696 hook_p hook = NULL; 697 u_int16_t ids[2]; 698 struct mbuf *m; 699 u_int16_t hdr; 700 u_int16_t ns; 701 u_int16_t nr; 702 int is_ctrl; 703 int error; 704 int len; 705 706 /* Grab mbuf */ 707 NGI_GET_M(item, m); 708 709 /* Update stats */ 710 priv->stats.recvPackets++; 711 priv->stats.recvOctets += m->m_pkthdr.len; 712 713 /* Get initial header */ 714 if (m->m_pkthdr.len < 6) { 715 priv->stats.recvRunts++; 716 NG_FREE_ITEM(item); 717 NG_FREE_M(m); 718 return (EINVAL); 719 } 720 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 721 priv->stats.memoryFailures++; 722 NG_FREE_ITEM(item); 723 return (EINVAL); 724 } 725 hdr = ntohs(*mtod(m, u_int16_t *)); 726 m_adj(m, 2); 727 728 /* Check required header bits and minimum length */ 729 is_ctrl = (hdr & L2TP_HDR_CTRL) != 0; 730 if ((hdr & req_bits[is_ctrl][0]) != 0 731 || (~hdr & req_bits[is_ctrl][1]) != 0) { 732 priv->stats.recvInvalid++; 733 NG_FREE_ITEM(item); 734 NG_FREE_M(m); 735 return (EINVAL); 736 } 737 if (m->m_pkthdr.len < 4 /* tunnel, session id */ 738 + (2 * ((hdr & L2TP_HDR_LEN) != 0)) /* length field */ 739 + (4 * ((hdr & L2TP_HDR_SEQ) != 0)) /* seq # fields */ 740 + (2 * ((hdr & L2TP_HDR_OFF) != 0))) { /* offset field */ 741 priv->stats.recvRunts++; 742 NG_FREE_ITEM(item); 743 NG_FREE_M(m); 744 return (EINVAL); 745 } 746 747 /* Get and validate length field if present */ 748 if ((hdr & L2TP_HDR_LEN) != 0) { 749 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 750 priv->stats.memoryFailures++; 751 NG_FREE_ITEM(item); 752 return (EINVAL); 753 } 754 len = (u_int16_t)ntohs(*mtod(m, u_int16_t *)) - 4; 755 m_adj(m, 2); 756 if (len < 0 || len > m->m_pkthdr.len) { 757 priv->stats.recvInvalid++; 758 NG_FREE_ITEM(item); 759 NG_FREE_M(m); 760 return (EINVAL); 761 } 762 if (len < m->m_pkthdr.len) /* trim extra bytes */ 763 m_adj(m, -(m->m_pkthdr.len - len)); 764 } 765 766 /* Get tunnel ID and session ID */ 767 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { 768 priv->stats.memoryFailures++; 769 NG_FREE_ITEM(item); 770 return (EINVAL); 771 } 772 memcpy(ids, mtod(m, u_int16_t *), 4); 773 m_adj(m, 4); 774 775 /* Check tunnel ID */ 776 if (ids[0] != priv->conf.tunnel_id 777 && (priv->conf.match_id || ids[0] != 0)) { 778 priv->stats.recvWrongTunnel++; 779 NG_FREE_ITEM(item); 780 NG_FREE_M(m); 781 return (EADDRNOTAVAIL); 782 } 783 784 /* Check session ID (for data packets only) */ 785 if ((hdr & L2TP_HDR_CTRL) == 0) { 786 NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session, 787 (void *)(uintptr_t)ids[1], hook); 788 if (hook == NULL) { 789 priv->stats.recvUnknownSID++; 790 NG_FREE_ITEM(item); 791 NG_FREE_M(m); 792 return (ENOTCONN); 793 } 794 hpriv = NG_HOOK_PRIVATE(hook); 795 } 796 797 /* Get Ns, Nr fields if present */ 798 if ((hdr & L2TP_HDR_SEQ) != 0) { 799 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { 800 priv->stats.memoryFailures++; 801 NG_FREE_ITEM(item); 802 return (EINVAL); 803 } 804 memcpy(&ns, &mtod(m, u_int16_t *)[0], 2); 805 ns = ntohs(ns); 806 memcpy(&nr, &mtod(m, u_int16_t *)[1], 2); 807 nr = ntohs(nr); 808 m_adj(m, 4); 809 } 810 811 /* Strip offset padding if present */ 812 if ((hdr & L2TP_HDR_OFF) != 0) { 813 u_int16_t offset; 814 815 /* Get length of offset padding */ 816 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 817 priv->stats.memoryFailures++; 818 NG_FREE_ITEM(item); 819 return (EINVAL); 820 } 821 memcpy(&offset, mtod(m, u_int16_t *), 2); 822 offset = ntohs(offset); 823 824 /* Trim offset padding */ 825 if (offset <= 2 || offset > m->m_pkthdr.len) { 826 priv->stats.recvInvalid++; 827 NG_FREE_ITEM(item); 828 NG_FREE_M(m); 829 return (EINVAL); 830 } 831 m_adj(m, offset); 832 } 833 834 /* Handle control packets */ 835 if ((hdr & L2TP_HDR_CTRL) != 0) { 836 837 /* Handle receive ack sequence number Nr */ 838 ng_l2tp_seq_recv_nr(priv, nr); 839 840 /* Discard ZLB packets */ 841 if (m->m_pkthdr.len == 0) { 842 priv->stats.recvZLBs++; 843 NG_FREE_ITEM(item); 844 NG_FREE_M(m); 845 return (0); 846 } 847 848 /* 849 * Prepend session ID to packet here: we don't want to accept 850 * the send sequence number Ns if we have to drop the packet 851 * later because of a memory error, because then the upper 852 * layer would never get the packet. 853 */ 854 M_PREPEND(m, 2, M_DONTWAIT); 855 if (m == NULL) { 856 priv->stats.memoryFailures++; 857 NG_FREE_ITEM(item); 858 return (ENOBUFS); 859 } 860 memcpy(mtod(m, u_int16_t *), &ids[1], 2); 861 862 /* Now handle send sequence number */ 863 if (ng_l2tp_seq_recv_ns(priv, ns) == -1) { 864 NG_FREE_ITEM(item); 865 NG_FREE_M(m); 866 return (0); 867 } 868 869 /* Deliver packet to upper layers */ 870 NG_FWD_NEW_DATA(error, item, priv->ctrl, m); 871 return (error); 872 } 873 874 /* Follow peer's lead in data sequencing, if configured to do so */ 875 if (!hpriv->conf.control_dseq) 876 hpriv->conf.enable_dseq = ((hdr & L2TP_HDR_SEQ) != 0); 877 878 /* Handle data sequence numbers if present and enabled */ 879 if ((hdr & L2TP_HDR_SEQ) != 0) { 880 if (hpriv->conf.enable_dseq 881 && L2TP_SEQ_DIFF(ns, hpriv->nr) < 0) { 882 NG_FREE_ITEM(item); /* duplicate or out of order */ 883 NG_FREE_M(m); 884 priv->stats.recvDataDrops++; 885 return (0); 886 } 887 hpriv->nr = ns + 1; 888 } 889 890 /* Drop empty data packets */ 891 if (m->m_pkthdr.len == 0) { 892 NG_FREE_ITEM(item); 893 NG_FREE_M(m); 894 return (0); 895 } 896 897 /* Deliver data */ 898 NG_FWD_NEW_DATA(error, item, hook, m); 899 return (error); 900} 901 902/* 903 * Handle an outgoing control frame. 904 */ 905static int 906ng_l2tp_recv_ctrl(node_p node, item_p item) 907{ 908 const priv_p priv = NG_NODE_PRIVATE(node); 909 struct l2tp_seq *const seq = &priv->seq; 910 struct mbuf *m; 911 int i; 912 913 /* Grab mbuf and discard other stuff XXX */ 914 NGI_GET_M(item, m); 915 NG_FREE_ITEM(item); 916 917 /* Packet should have session ID prepended */ 918 if (m->m_pkthdr.len < 2) { 919 priv->stats.xmitInvalid++; 920 m_freem(m); 921 return (EINVAL); 922 } 923 924 /* Check max length */ 925 if (m->m_pkthdr.len >= 0x10000 - 14) { 926 priv->stats.xmitTooBig++; 927 m_freem(m); 928 return (EOVERFLOW); 929 } 930 931 /* Find next empty slot in transmit queue */ 932 for (i = 0; i < L2TP_MAX_XWIN && seq->xwin[i] != NULL; i++); 933 if (i == L2TP_MAX_XWIN) { 934 priv->stats.xmitDrops++; 935 m_freem(m); 936 return (ENOBUFS); 937 } 938 seq->xwin[i] = m; 939 940 /* Sanity check receive ack timer state */ 941 KASSERT((i == 0) ^ seq->rack_timer_running, 942 ("%s: xwin %d full but rack timer %srunning", 943 __FUNCTION__, i, seq->rack_timer_running ? "" : "not ")); 944 945 /* If peer's receive window is already full, nothing else to do */ 946 if (i >= seq->cwnd) 947 return (0); 948 949 /* Start retransmit timer if not already running */ 950 if (!seq->rack_timer_running) { 951 callout_reset(&seq->rack_timer, 952 hz, ng_l2tp_seq_rack_timeout, node); 953 seq->rack_timer_running = 1; 954 NG_NODE_REF(node); 955 } 956 957 /* Copy packet */
|
958 if ((m = L2TP_COPY_MBUF(seq->xwin[i], M_NOWAIT)) == NULL) {
| 958 if ((m = L2TP_COPY_MBUF(seq->xwin[i], M_DONTWAIT)) == NULL) {
|
959 priv->stats.memoryFailures++; 960 return (ENOBUFS); 961 } 962 963 /* Send packet and increment xmit sequence number */ 964 return (ng_l2tp_xmit_ctrl(priv, m, seq->ns++)); 965} 966 967/* 968 * Handle an outgoing data frame. 969 */ 970static int 971ng_l2tp_recv_data(node_p node, item_p item, hookpriv_p hpriv) 972{ 973 const priv_p priv = NG_NODE_PRIVATE(node); 974 struct mbuf *m; 975 u_int16_t hdr; 976 int error; 977 int i = 1; 978 979 /* Get mbuf */ 980 NGI_GET_M(item, m); 981 982 /* Check max length */ 983 if (m->m_pkthdr.len >= 0x10000 - 12) { 984 priv->stats.xmitDataTooBig++; 985 NG_FREE_ITEM(item); 986 NG_FREE_M(m); 987 return (EOVERFLOW); 988 } 989 990 /* Prepend L2TP header */ 991 M_PREPEND(m, 6 992 + (2 * (hpriv->conf.include_length != 0)) 993 + (4 * (hpriv->conf.enable_dseq != 0)), 994 M_DONTWAIT); 995 if (m == NULL) { 996 priv->stats.memoryFailures++; 997 NG_FREE_ITEM(item); 998 return (ENOBUFS); 999 } 1000 hdr = L2TP_DATA_HDR; 1001 if (hpriv->conf.include_length) { 1002 hdr |= L2TP_HDR_LEN; 1003 mtod(m, u_int16_t *)[i++] = htons(m->m_pkthdr.len); 1004 } 1005 mtod(m, u_int16_t *)[i++] = priv->conf.peer_id; 1006 mtod(m, u_int16_t *)[i++] = hpriv->conf.peer_id; 1007 if (hpriv->conf.enable_dseq) { 1008 hdr |= L2TP_HDR_SEQ; 1009 mtod(m, u_int16_t *)[i++] = htons(hpriv->ns); 1010 mtod(m, u_int16_t *)[i++] = htons(hpriv->nr); 1011 hpriv->ns++; 1012 } 1013 mtod(m, u_int16_t *)[0] = htons(hdr); 1014 1015 /* Send packet */ 1016 NG_FWD_NEW_DATA(error, item, priv->lower, m); 1017 return (error); 1018} 1019 1020/* 1021 * Send a message to our controlling node that we've failed. 1022 */ 1023static void 1024ng_l2tp_seq_failure(priv_p priv) 1025{ 1026 struct ng_mesg *msg; 1027 int error; 1028 1029 NG_MKMESSAGE(msg, NGM_L2TP_COOKIE, NGM_L2TP_ACK_FAILURE, 0, M_NOWAIT); 1030 if (msg == NULL) 1031 return; 1032 NG_SEND_MSG_ID(error, priv->node, msg, priv->ftarget, 0); 1033} 1034 1035/************************************************************************ 1036 SEQUENCE NUMBER HANDLING 1037************************************************************************/ 1038 1039/* 1040 * Initialize sequence number state. 1041 */ 1042static void 1043ng_l2tp_seq_init(priv_p priv) 1044{ 1045 struct l2tp_seq *const seq = &priv->seq; 1046 1047 KASSERT(priv->conf.peer_win >= 1, 1048 ("%s: peer_win is zero", __FUNCTION__)); 1049 memset(seq, 0, sizeof(*seq)); 1050 seq->cwnd = 1; 1051 seq->wmax = priv->conf.peer_win; 1052 if (seq->wmax > L2TP_MAX_XWIN) 1053 seq->wmax = L2TP_MAX_XWIN; 1054 seq->ssth = seq->wmax; 1055 seq->max_rexmits = priv->conf.rexmit_max; 1056 seq->max_rexmit_to = priv->conf.rexmit_max_to; 1057 callout_init(&seq->rack_timer, 0); 1058 callout_init(&seq->xack_timer, 0); 1059 L2TP_SEQ_CHECK(seq); 1060} 1061 1062/* 1063 * Adjust sequence number state accordingly after reconfiguration. 1064 */ 1065static int 1066ng_l2tp_seq_adjust(priv_p priv, const struct ng_l2tp_config *conf) 1067{ 1068 struct l2tp_seq *const seq = &priv->seq; 1069 u_int16_t new_wmax; 1070 1071 /* If disabling node, reset state sequence number */ 1072 if (!conf->enabled) { 1073 ng_l2tp_seq_reset(priv); 1074 return (0); 1075 } 1076 1077 /* Adjust peer's max recv window; it can only increase */ 1078 new_wmax = conf->peer_win; 1079 if (new_wmax > L2TP_MAX_XWIN) 1080 new_wmax = L2TP_MAX_XWIN; 1081 if (new_wmax == 0) 1082 return (EINVAL); 1083 if (new_wmax < seq->wmax) 1084 return (EBUSY); 1085 seq->wmax = new_wmax; 1086 1087 /* Update retransmit parameters */ 1088 seq->max_rexmits = conf->rexmit_max; 1089 seq->max_rexmit_to = conf->rexmit_max_to; 1090 1091 /* Done */ 1092 return (0); 1093} 1094 1095/* 1096 * Reset sequence number state. 1097 */ 1098static void 1099ng_l2tp_seq_reset(priv_p priv) 1100{ 1101 struct l2tp_seq *const seq = &priv->seq; 1102 hook_p hook; 1103 int i; 1104 1105 /* Sanity check */ 1106 L2TP_SEQ_CHECK(seq); 1107 1108 /* Stop timers */ 1109 if (seq->rack_timer_running && callout_stop(&seq->rack_timer) == 1) { 1110 seq->rack_timer_running = 0; 1111 NG_NODE_UNREF(priv->node); 1112 } 1113 if (seq->xack_timer_running && callout_stop(&seq->xack_timer) == 1) { 1114 seq->xack_timer_running = 0; 1115 NG_NODE_UNREF(priv->node); 1116 } 1117 1118 /* Free retransmit queue */ 1119 for (i = 0; i < L2TP_MAX_XWIN; i++) { 1120 if (seq->xwin[i] == NULL) 1121 break; 1122 m_freem(seq->xwin[i]); 1123 } 1124 1125 /* Reset session hooks' sequence number states */ 1126 NG_NODE_FOREACH_HOOK(priv->node, ng_l2tp_reset_session, NULL, hook); 1127 1128 /* Reset node's sequence number state */ 1129 memset(seq, 0, sizeof(*seq)); 1130 seq->cwnd = 1; 1131 seq->wmax = L2TP_MAX_XWIN; 1132 seq->ssth = seq->wmax; 1133 1134 /* Done */ 1135 L2TP_SEQ_CHECK(seq); 1136} 1137 1138/* 1139 * Handle receipt of an acknowledgement value (Nr) from peer. 1140 */ 1141static void 1142ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr) 1143{ 1144 struct l2tp_seq *const seq = &priv->seq; 1145 struct mbuf *m; 1146 int nack; 1147 int i; 1148 1149 /* Verify peer's ACK is in range */ 1150 if ((nack = L2TP_SEQ_DIFF(nr, seq->rack)) <= 0) 1151 return; /* duplicate ack */ 1152 if (L2TP_SEQ_DIFF(nr, seq->ns) > 0) { 1153 priv->stats.recvBadAcks++; /* ack for packet not sent */ 1154 return; 1155 } 1156 KASSERT(nack <= L2TP_MAX_XWIN, 1157 ("%s: nack=%d > %d", __FUNCTION__, nack, L2TP_MAX_XWIN)); 1158 1159 /* Update receive ack stats */ 1160 seq->rack = nr; 1161 seq->rexmits = 0; 1162 1163 /* Free acknowledged packets and shift up packets in the xmit queue */ 1164 for (i = 0; i < nack; i++) 1165 m_freem(seq->xwin[i]); 1166 memmove(seq->xwin, seq->xwin + nack, 1167 (L2TP_MAX_XWIN - nack) * sizeof(*seq->xwin)); 1168 memset(seq->xwin + (L2TP_MAX_XWIN - nack), 0, 1169 nack * sizeof(*seq->xwin)); 1170 1171 /* 1172 * Do slow-start/congestion avoidance windowing algorithm described 1173 * in RFC 2661, Appendix A. Here we handle a multiple ACK as if each 1174 * ACK had arrived separately. 1175 */ 1176 if (seq->cwnd < seq->wmax) { 1177 1178 /* Handle slow start phase */ 1179 if (seq->cwnd < seq->ssth) { 1180 seq->cwnd += nack; 1181 nack = 0; 1182 if (seq->cwnd > seq->ssth) { /* into cg.av. phase */ 1183 nack = seq->cwnd - seq->ssth; 1184 seq->cwnd = seq->ssth; 1185 } 1186 } 1187 1188 /* Handle congestion avoidance phase */ 1189 if (seq->cwnd >= seq->ssth) { 1190 seq->acks += nack; 1191 while (seq->acks >= seq->cwnd) { 1192 seq->acks -= seq->cwnd; 1193 if (seq->cwnd < seq->wmax) 1194 seq->cwnd++; 1195 } 1196 } 1197 } 1198 1199 /* Stop xmit timer */ 1200 if (seq->rack_timer_running && callout_stop(&seq->rack_timer) == 1) { 1201 seq->rack_timer_running = 0; 1202 NG_NODE_UNREF(priv->node); 1203 } 1204 1205 /* If transmit queue is empty, we're done for now */ 1206 if (seq->xwin[0] == NULL) 1207 return; 1208 1209 /* Start restransmit timer again */ 1210 callout_reset(&seq->rack_timer, 1211 hz, ng_l2tp_seq_rack_timeout, priv->node); 1212 seq->rack_timer_running = 1; 1213 NG_NODE_REF(priv->node); 1214 1215 /* 1216 * Send more packets, trying to keep peer's receive window full. 1217 * If there is a memory error, pretend packet was sent, as it 1218 * will get retransmitted later anyway. 1219 */ 1220 while ((i = L2TP_SEQ_DIFF(seq->ns, seq->rack)) < seq->cwnd 1221 && seq->xwin[i] != NULL) {
| 959 priv->stats.memoryFailures++; 960 return (ENOBUFS); 961 } 962 963 /* Send packet and increment xmit sequence number */ 964 return (ng_l2tp_xmit_ctrl(priv, m, seq->ns++)); 965} 966 967/* 968 * Handle an outgoing data frame. 969 */ 970static int 971ng_l2tp_recv_data(node_p node, item_p item, hookpriv_p hpriv) 972{ 973 const priv_p priv = NG_NODE_PRIVATE(node); 974 struct mbuf *m; 975 u_int16_t hdr; 976 int error; 977 int i = 1; 978 979 /* Get mbuf */ 980 NGI_GET_M(item, m); 981 982 /* Check max length */ 983 if (m->m_pkthdr.len >= 0x10000 - 12) { 984 priv->stats.xmitDataTooBig++; 985 NG_FREE_ITEM(item); 986 NG_FREE_M(m); 987 return (EOVERFLOW); 988 } 989 990 /* Prepend L2TP header */ 991 M_PREPEND(m, 6 992 + (2 * (hpriv->conf.include_length != 0)) 993 + (4 * (hpriv->conf.enable_dseq != 0)), 994 M_DONTWAIT); 995 if (m == NULL) { 996 priv->stats.memoryFailures++; 997 NG_FREE_ITEM(item); 998 return (ENOBUFS); 999 } 1000 hdr = L2TP_DATA_HDR; 1001 if (hpriv->conf.include_length) { 1002 hdr |= L2TP_HDR_LEN; 1003 mtod(m, u_int16_t *)[i++] = htons(m->m_pkthdr.len); 1004 } 1005 mtod(m, u_int16_t *)[i++] = priv->conf.peer_id; 1006 mtod(m, u_int16_t *)[i++] = hpriv->conf.peer_id; 1007 if (hpriv->conf.enable_dseq) { 1008 hdr |= L2TP_HDR_SEQ; 1009 mtod(m, u_int16_t *)[i++] = htons(hpriv->ns); 1010 mtod(m, u_int16_t *)[i++] = htons(hpriv->nr); 1011 hpriv->ns++; 1012 } 1013 mtod(m, u_int16_t *)[0] = htons(hdr); 1014 1015 /* Send packet */ 1016 NG_FWD_NEW_DATA(error, item, priv->lower, m); 1017 return (error); 1018} 1019 1020/* 1021 * Send a message to our controlling node that we've failed. 1022 */ 1023static void 1024ng_l2tp_seq_failure(priv_p priv) 1025{ 1026 struct ng_mesg *msg; 1027 int error; 1028 1029 NG_MKMESSAGE(msg, NGM_L2TP_COOKIE, NGM_L2TP_ACK_FAILURE, 0, M_NOWAIT); 1030 if (msg == NULL) 1031 return; 1032 NG_SEND_MSG_ID(error, priv->node, msg, priv->ftarget, 0); 1033} 1034 1035/************************************************************************ 1036 SEQUENCE NUMBER HANDLING 1037************************************************************************/ 1038 1039/* 1040 * Initialize sequence number state. 1041 */ 1042static void 1043ng_l2tp_seq_init(priv_p priv) 1044{ 1045 struct l2tp_seq *const seq = &priv->seq; 1046 1047 KASSERT(priv->conf.peer_win >= 1, 1048 ("%s: peer_win is zero", __FUNCTION__)); 1049 memset(seq, 0, sizeof(*seq)); 1050 seq->cwnd = 1; 1051 seq->wmax = priv->conf.peer_win; 1052 if (seq->wmax > L2TP_MAX_XWIN) 1053 seq->wmax = L2TP_MAX_XWIN; 1054 seq->ssth = seq->wmax; 1055 seq->max_rexmits = priv->conf.rexmit_max; 1056 seq->max_rexmit_to = priv->conf.rexmit_max_to; 1057 callout_init(&seq->rack_timer, 0); 1058 callout_init(&seq->xack_timer, 0); 1059 L2TP_SEQ_CHECK(seq); 1060} 1061 1062/* 1063 * Adjust sequence number state accordingly after reconfiguration. 1064 */ 1065static int 1066ng_l2tp_seq_adjust(priv_p priv, const struct ng_l2tp_config *conf) 1067{ 1068 struct l2tp_seq *const seq = &priv->seq; 1069 u_int16_t new_wmax; 1070 1071 /* If disabling node, reset state sequence number */ 1072 if (!conf->enabled) { 1073 ng_l2tp_seq_reset(priv); 1074 return (0); 1075 } 1076 1077 /* Adjust peer's max recv window; it can only increase */ 1078 new_wmax = conf->peer_win; 1079 if (new_wmax > L2TP_MAX_XWIN) 1080 new_wmax = L2TP_MAX_XWIN; 1081 if (new_wmax == 0) 1082 return (EINVAL); 1083 if (new_wmax < seq->wmax) 1084 return (EBUSY); 1085 seq->wmax = new_wmax; 1086 1087 /* Update retransmit parameters */ 1088 seq->max_rexmits = conf->rexmit_max; 1089 seq->max_rexmit_to = conf->rexmit_max_to; 1090 1091 /* Done */ 1092 return (0); 1093} 1094 1095/* 1096 * Reset sequence number state. 1097 */ 1098static void 1099ng_l2tp_seq_reset(priv_p priv) 1100{ 1101 struct l2tp_seq *const seq = &priv->seq; 1102 hook_p hook; 1103 int i; 1104 1105 /* Sanity check */ 1106 L2TP_SEQ_CHECK(seq); 1107 1108 /* Stop timers */ 1109 if (seq->rack_timer_running && callout_stop(&seq->rack_timer) == 1) { 1110 seq->rack_timer_running = 0; 1111 NG_NODE_UNREF(priv->node); 1112 } 1113 if (seq->xack_timer_running && callout_stop(&seq->xack_timer) == 1) { 1114 seq->xack_timer_running = 0; 1115 NG_NODE_UNREF(priv->node); 1116 } 1117 1118 /* Free retransmit queue */ 1119 for (i = 0; i < L2TP_MAX_XWIN; i++) { 1120 if (seq->xwin[i] == NULL) 1121 break; 1122 m_freem(seq->xwin[i]); 1123 } 1124 1125 /* Reset session hooks' sequence number states */ 1126 NG_NODE_FOREACH_HOOK(priv->node, ng_l2tp_reset_session, NULL, hook); 1127 1128 /* Reset node's sequence number state */ 1129 memset(seq, 0, sizeof(*seq)); 1130 seq->cwnd = 1; 1131 seq->wmax = L2TP_MAX_XWIN; 1132 seq->ssth = seq->wmax; 1133 1134 /* Done */ 1135 L2TP_SEQ_CHECK(seq); 1136} 1137 1138/* 1139 * Handle receipt of an acknowledgement value (Nr) from peer. 1140 */ 1141static void 1142ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr) 1143{ 1144 struct l2tp_seq *const seq = &priv->seq; 1145 struct mbuf *m; 1146 int nack; 1147 int i; 1148 1149 /* Verify peer's ACK is in range */ 1150 if ((nack = L2TP_SEQ_DIFF(nr, seq->rack)) <= 0) 1151 return; /* duplicate ack */ 1152 if (L2TP_SEQ_DIFF(nr, seq->ns) > 0) { 1153 priv->stats.recvBadAcks++; /* ack for packet not sent */ 1154 return; 1155 } 1156 KASSERT(nack <= L2TP_MAX_XWIN, 1157 ("%s: nack=%d > %d", __FUNCTION__, nack, L2TP_MAX_XWIN)); 1158 1159 /* Update receive ack stats */ 1160 seq->rack = nr; 1161 seq->rexmits = 0; 1162 1163 /* Free acknowledged packets and shift up packets in the xmit queue */ 1164 for (i = 0; i < nack; i++) 1165 m_freem(seq->xwin[i]); 1166 memmove(seq->xwin, seq->xwin + nack, 1167 (L2TP_MAX_XWIN - nack) * sizeof(*seq->xwin)); 1168 memset(seq->xwin + (L2TP_MAX_XWIN - nack), 0, 1169 nack * sizeof(*seq->xwin)); 1170 1171 /* 1172 * Do slow-start/congestion avoidance windowing algorithm described 1173 * in RFC 2661, Appendix A. Here we handle a multiple ACK as if each 1174 * ACK had arrived separately. 1175 */ 1176 if (seq->cwnd < seq->wmax) { 1177 1178 /* Handle slow start phase */ 1179 if (seq->cwnd < seq->ssth) { 1180 seq->cwnd += nack; 1181 nack = 0; 1182 if (seq->cwnd > seq->ssth) { /* into cg.av. phase */ 1183 nack = seq->cwnd - seq->ssth; 1184 seq->cwnd = seq->ssth; 1185 } 1186 } 1187 1188 /* Handle congestion avoidance phase */ 1189 if (seq->cwnd >= seq->ssth) { 1190 seq->acks += nack; 1191 while (seq->acks >= seq->cwnd) { 1192 seq->acks -= seq->cwnd; 1193 if (seq->cwnd < seq->wmax) 1194 seq->cwnd++; 1195 } 1196 } 1197 } 1198 1199 /* Stop xmit timer */ 1200 if (seq->rack_timer_running && callout_stop(&seq->rack_timer) == 1) { 1201 seq->rack_timer_running = 0; 1202 NG_NODE_UNREF(priv->node); 1203 } 1204 1205 /* If transmit queue is empty, we're done for now */ 1206 if (seq->xwin[0] == NULL) 1207 return; 1208 1209 /* Start restransmit timer again */ 1210 callout_reset(&seq->rack_timer, 1211 hz, ng_l2tp_seq_rack_timeout, priv->node); 1212 seq->rack_timer_running = 1; 1213 NG_NODE_REF(priv->node); 1214 1215 /* 1216 * Send more packets, trying to keep peer's receive window full. 1217 * If there is a memory error, pretend packet was sent, as it 1218 * will get retransmitted later anyway. 1219 */ 1220 while ((i = L2TP_SEQ_DIFF(seq->ns, seq->rack)) < seq->cwnd 1221 && seq->xwin[i] != NULL) {
|
1222 if ((m = L2TP_COPY_MBUF(seq->xwin[i], M_NOWAIT)) == NULL)
| 1222 if ((m = L2TP_COPY_MBUF(seq->xwin[i], M_DONTWAIT)) == NULL)
|
1223 priv->stats.memoryFailures++; 1224 else 1225 ng_l2tp_xmit_ctrl(priv, m, seq->ns); 1226 seq->ns++; 1227 } 1228} 1229 1230/* 1231 * Handle receipt of a sequence number value (Ns) from peer. 1232 * We make no attempt to re-order out of order packets. 1233 * 1234 * This function should only be called for non-ZLB packets. 1235 * 1236 * Returns: 1237 * 0 Accept packet 1238 * -1 Drop packet 1239 */ 1240static int 1241ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns) 1242{ 1243 struct l2tp_seq *const seq = &priv->seq; 1244 1245 /* If not what we expect, drop packet and send an immediate ZLB ack */ 1246 if (ns != seq->nr) { 1247 if (L2TP_SEQ_DIFF(ns, seq->nr) < 0) 1248 priv->stats.recvDuplicates++; 1249 else 1250 priv->stats.recvOutOfOrder++; 1251 ng_l2tp_xmit_ctrl(priv, NULL, seq->ns); 1252 return (-1); 1253 } 1254 1255 /* Update recv sequence number */ 1256 seq->nr++; 1257 1258 /* Start receive ack timer, if not already running */ 1259 if (!seq->xack_timer_running) { 1260 callout_reset(&seq->xack_timer, 1261 L2TP_DELAYED_ACK, ng_l2tp_seq_xack_timeout, priv->node); 1262 seq->xack_timer_running = 1; 1263 NG_NODE_REF(priv->node); 1264 } 1265 1266 /* Accept packet */ 1267 return (0); 1268} 1269 1270/* 1271 * Handle an ack timeout. We have an outstanding ack that we 1272 * were hoping to piggy-back, but haven't, so send a ZLB. 1273 */ 1274static void 1275ng_l2tp_seq_xack_timeout(void *arg) 1276{ 1277 const node_p node = arg; 1278 const priv_p priv = NG_NODE_PRIVATE(node); 1279 struct l2tp_seq *const seq = &priv->seq; 1280 int s; 1281 1282 /* Check if node is going away */ 1283 s = splnet(); 1284 if (NG_NODE_NOT_VALID(node)) { 1285 seq->xack_timer_running = 0; 1286 if (!seq->rack_timer_running) { 1287 FREE(priv, M_NETGRAPH_L2TP); 1288 NG_NODE_SET_PRIVATE(node, NULL); 1289 } 1290 NG_NODE_UNREF(node); 1291 splx(s); 1292 return; 1293 } 1294 1295 /* Sanity check */ 1296 L2TP_SEQ_CHECK(seq); 1297 1298 /* If ack is still outstanding, send a ZLB */ 1299 if (seq->xack != seq->nr) 1300 ng_l2tp_xmit_ctrl(priv, NULL, seq->ns); 1301 1302 /* Done */ 1303 seq->xack_timer_running = 0; 1304 NG_NODE_UNREF(node); 1305 L2TP_SEQ_CHECK(seq); 1306 splx(s); 1307} 1308 1309/* 1310 * Handle a transmit timeout. The peer has failed to respond 1311 * with an ack for our packet, so retransmit it. 1312 */ 1313static void 1314ng_l2tp_seq_rack_timeout(void *arg) 1315{ 1316 const node_p node = arg; 1317 const priv_p priv = NG_NODE_PRIVATE(node); 1318 struct l2tp_seq *const seq = &priv->seq; 1319 struct mbuf *m; 1320 u_int delay; 1321 int s; 1322 1323 /* Check if node is going away */ 1324 s = splnet(); 1325 if (NG_NODE_NOT_VALID(node)) { 1326 seq->rack_timer_running = 0; 1327 if (!seq->xack_timer_running) { 1328 FREE(priv, M_NETGRAPH_L2TP); 1329 NG_NODE_SET_PRIVATE(node, NULL); 1330 } 1331 NG_NODE_UNREF(node); 1332 splx(s); 1333 return; 1334 } 1335 1336 /* Sanity check */ 1337 L2TP_SEQ_CHECK(seq); 1338 1339 /* Make sure peer's ack is still outstanding before doing anything */ 1340 if (seq->rack == seq->ns) { 1341 seq->rack_timer_running = 0; 1342 NG_NODE_UNREF(node); 1343 goto done; 1344 } 1345 priv->stats.xmitRetransmits++; 1346 1347 /* Have we reached the retransmit limit? If so, notify owner. */ 1348 if (seq->rexmits++ >= seq->max_rexmits) 1349 ng_l2tp_seq_failure(priv); 1350 1351 /* Restart timer, this time with an increased delay */ 1352 delay = (seq->rexmits > 12) ? (1 << 12) : (1 << seq->rexmits); 1353 if (delay > seq->max_rexmit_to) 1354 delay = seq->max_rexmit_to; 1355 callout_reset(&seq->rack_timer, 1356 hz * delay, ng_l2tp_seq_rack_timeout, node); 1357 1358 /* Do slow-start/congestion algorithm windowing algorithm */ 1359 seq->ssth = (seq->cwnd + 1) / 2; 1360 seq->cwnd = 1; 1361 seq->acks = 0; 1362 1363 /* Retransmit oldest unack'd packet */
| 1223 priv->stats.memoryFailures++; 1224 else 1225 ng_l2tp_xmit_ctrl(priv, m, seq->ns); 1226 seq->ns++; 1227 } 1228} 1229 1230/* 1231 * Handle receipt of a sequence number value (Ns) from peer. 1232 * We make no attempt to re-order out of order packets. 1233 * 1234 * This function should only be called for non-ZLB packets. 1235 * 1236 * Returns: 1237 * 0 Accept packet 1238 * -1 Drop packet 1239 */ 1240static int 1241ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns) 1242{ 1243 struct l2tp_seq *const seq = &priv->seq; 1244 1245 /* If not what we expect, drop packet and send an immediate ZLB ack */ 1246 if (ns != seq->nr) { 1247 if (L2TP_SEQ_DIFF(ns, seq->nr) < 0) 1248 priv->stats.recvDuplicates++; 1249 else 1250 priv->stats.recvOutOfOrder++; 1251 ng_l2tp_xmit_ctrl(priv, NULL, seq->ns); 1252 return (-1); 1253 } 1254 1255 /* Update recv sequence number */ 1256 seq->nr++; 1257 1258 /* Start receive ack timer, if not already running */ 1259 if (!seq->xack_timer_running) { 1260 callout_reset(&seq->xack_timer, 1261 L2TP_DELAYED_ACK, ng_l2tp_seq_xack_timeout, priv->node); 1262 seq->xack_timer_running = 1; 1263 NG_NODE_REF(priv->node); 1264 } 1265 1266 /* Accept packet */ 1267 return (0); 1268} 1269 1270/* 1271 * Handle an ack timeout. We have an outstanding ack that we 1272 * were hoping to piggy-back, but haven't, so send a ZLB. 1273 */ 1274static void 1275ng_l2tp_seq_xack_timeout(void *arg) 1276{ 1277 const node_p node = arg; 1278 const priv_p priv = NG_NODE_PRIVATE(node); 1279 struct l2tp_seq *const seq = &priv->seq; 1280 int s; 1281 1282 /* Check if node is going away */ 1283 s = splnet(); 1284 if (NG_NODE_NOT_VALID(node)) { 1285 seq->xack_timer_running = 0; 1286 if (!seq->rack_timer_running) { 1287 FREE(priv, M_NETGRAPH_L2TP); 1288 NG_NODE_SET_PRIVATE(node, NULL); 1289 } 1290 NG_NODE_UNREF(node); 1291 splx(s); 1292 return; 1293 } 1294 1295 /* Sanity check */ 1296 L2TP_SEQ_CHECK(seq); 1297 1298 /* If ack is still outstanding, send a ZLB */ 1299 if (seq->xack != seq->nr) 1300 ng_l2tp_xmit_ctrl(priv, NULL, seq->ns); 1301 1302 /* Done */ 1303 seq->xack_timer_running = 0; 1304 NG_NODE_UNREF(node); 1305 L2TP_SEQ_CHECK(seq); 1306 splx(s); 1307} 1308 1309/* 1310 * Handle a transmit timeout. The peer has failed to respond 1311 * with an ack for our packet, so retransmit it. 1312 */ 1313static void 1314ng_l2tp_seq_rack_timeout(void *arg) 1315{ 1316 const node_p node = arg; 1317 const priv_p priv = NG_NODE_PRIVATE(node); 1318 struct l2tp_seq *const seq = &priv->seq; 1319 struct mbuf *m; 1320 u_int delay; 1321 int s; 1322 1323 /* Check if node is going away */ 1324 s = splnet(); 1325 if (NG_NODE_NOT_VALID(node)) { 1326 seq->rack_timer_running = 0; 1327 if (!seq->xack_timer_running) { 1328 FREE(priv, M_NETGRAPH_L2TP); 1329 NG_NODE_SET_PRIVATE(node, NULL); 1330 } 1331 NG_NODE_UNREF(node); 1332 splx(s); 1333 return; 1334 } 1335 1336 /* Sanity check */ 1337 L2TP_SEQ_CHECK(seq); 1338 1339 /* Make sure peer's ack is still outstanding before doing anything */ 1340 if (seq->rack == seq->ns) { 1341 seq->rack_timer_running = 0; 1342 NG_NODE_UNREF(node); 1343 goto done; 1344 } 1345 priv->stats.xmitRetransmits++; 1346 1347 /* Have we reached the retransmit limit? If so, notify owner. */ 1348 if (seq->rexmits++ >= seq->max_rexmits) 1349 ng_l2tp_seq_failure(priv); 1350 1351 /* Restart timer, this time with an increased delay */ 1352 delay = (seq->rexmits > 12) ? (1 << 12) : (1 << seq->rexmits); 1353 if (delay > seq->max_rexmit_to) 1354 delay = seq->max_rexmit_to; 1355 callout_reset(&seq->rack_timer, 1356 hz * delay, ng_l2tp_seq_rack_timeout, node); 1357 1358 /* Do slow-start/congestion algorithm windowing algorithm */ 1359 seq->ssth = (seq->cwnd + 1) / 2; 1360 seq->cwnd = 1; 1361 seq->acks = 0; 1362 1363 /* Retransmit oldest unack'd packet */
|
1364 if ((m = L2TP_COPY_MBUF(seq->xwin[0], M_NOWAIT)) == NULL)
| 1364 if ((m = L2TP_COPY_MBUF(seq->xwin[0], M_DONTWAIT)) == NULL)
|
1365 priv->stats.memoryFailures++; 1366 else 1367 ng_l2tp_xmit_ctrl(priv, m, seq->rack); 1368 1369done: 1370 /* Done */ 1371 L2TP_SEQ_CHECK(seq); 1372 splx(s); 1373} 1374 1375/* 1376 * Transmit a control stream packet, payload optional. 1377 * The transmit sequence number is not incremented. 1378 */ 1379static int 1380ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns) 1381{ 1382 struct l2tp_seq *const seq = &priv->seq; 1383 u_int16_t session_id = 0; 1384 meta_p meta = NULL; 1385 int error; 1386 1387 /* If no mbuf passed, send an empty packet (ZLB) */ 1388 if (m == NULL) { 1389 1390 /* Create a new mbuf for ZLB packet */ 1391 MGETHDR(m, M_DONTWAIT, MT_DATA); 1392 if (m == NULL) { 1393 priv->stats.memoryFailures++; 1394 return (ENOBUFS); 1395 } 1396 m->m_len = m->m_pkthdr.len = 12; 1397 m->m_pkthdr.rcvif = NULL; 1398 priv->stats.xmitZLBs++; 1399 } else { 1400 1401 /* Strip off session ID */ 1402 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 1403 priv->stats.memoryFailures++; 1404 return (ENOBUFS); 1405 } 1406 memcpy(&session_id, mtod(m, u_int16_t *), 2); 1407 m_adj(m, 2); 1408 1409 /* Make room for L2TP header */ 1410 M_PREPEND(m, 12, M_DONTWAIT); 1411 if (m == NULL) { 1412 priv->stats.memoryFailures++; 1413 return (ENOBUFS); 1414 } 1415 } 1416 1417 /* Fill in L2TP header */ 1418 mtod(m, u_int16_t *)[0] = htons(L2TP_CTRL_HDR); 1419 mtod(m, u_int16_t *)[1] = htons(m->m_pkthdr.len); 1420 mtod(m, u_int16_t *)[2] = priv->conf.peer_id; 1421 mtod(m, u_int16_t *)[3] = session_id; 1422 mtod(m, u_int16_t *)[4] = htons(ns); 1423 mtod(m, u_int16_t *)[5] = htons(seq->nr); 1424 1425 /* Update sequence number info and stats */ 1426 priv->stats.xmitPackets++; 1427 priv->stats.xmitOctets += m->m_pkthdr.len; 1428 1429 /* Stop ack timer: we're sending an ack with this packet */ 1430 if (seq->xack_timer_running && callout_stop(&seq->xack_timer) == 1) { 1431 seq->xack_timer_running = 0; 1432 NG_NODE_UNREF(priv->node); 1433 } 1434 seq->xack = seq->nr; 1435 1436 /* Send packet */ 1437 NG_SEND_DATA(error, priv->lower, m, meta); 1438 return (error); 1439} 1440 1441#ifdef INVARIANTS 1442/* 1443 * Sanity check sequence number state. 1444 */ 1445static void 1446ng_l2tp_seq_check(struct l2tp_seq *seq) 1447{ 1448 const int self_unack = L2TP_SEQ_DIFF(seq->nr, seq->xack); 1449 const int peer_unack = L2TP_SEQ_DIFF(seq->ns, seq->rack); 1450 int i; 1451 1452#define CHECK(p) KASSERT((p), ("%s: not: %s", __FUNCTION__, #p)) 1453 1454 CHECK(seq->wmax <= L2TP_MAX_XWIN); 1455 CHECK(seq->cwnd >= 1); 1456 CHECK(seq->cwnd <= seq->wmax); 1457 CHECK(seq->ssth >= 1); 1458 CHECK(seq->ssth <= seq->wmax); 1459 if (seq->cwnd < seq->ssth) 1460 CHECK(seq->acks == 0); 1461 else 1462 CHECK(seq->acks <= seq->cwnd); 1463 CHECK(self_unack >= 0); 1464 CHECK(peer_unack >= 0); 1465 CHECK(peer_unack <= seq->wmax); 1466 CHECK((self_unack == 0) ^ seq->xack_timer_running); 1467 CHECK((peer_unack == 0) ^ seq->rack_timer_running); 1468 CHECK(seq->rack_timer_running || !callout_pending(&seq->rack_timer)); 1469 CHECK(seq->xack_timer_running || !callout_pending(&seq->xack_timer)); 1470 for (i = 0; i < peer_unack; i++) 1471 CHECK(seq->xwin[i] != NULL); 1472 for ( ; i < seq->cwnd; i++) /* verify peer's recv window full */ 1473 CHECK(seq->xwin[i] == NULL); 1474 1475#undef CHECK 1476} 1477#endif /* INVARIANTS */ 1478 1479
| 1365 priv->stats.memoryFailures++; 1366 else 1367 ng_l2tp_xmit_ctrl(priv, m, seq->rack); 1368 1369done: 1370 /* Done */ 1371 L2TP_SEQ_CHECK(seq); 1372 splx(s); 1373} 1374 1375/* 1376 * Transmit a control stream packet, payload optional. 1377 * The transmit sequence number is not incremented. 1378 */ 1379static int 1380ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns) 1381{ 1382 struct l2tp_seq *const seq = &priv->seq; 1383 u_int16_t session_id = 0; 1384 meta_p meta = NULL; 1385 int error; 1386 1387 /* If no mbuf passed, send an empty packet (ZLB) */ 1388 if (m == NULL) { 1389 1390 /* Create a new mbuf for ZLB packet */ 1391 MGETHDR(m, M_DONTWAIT, MT_DATA); 1392 if (m == NULL) { 1393 priv->stats.memoryFailures++; 1394 return (ENOBUFS); 1395 } 1396 m->m_len = m->m_pkthdr.len = 12; 1397 m->m_pkthdr.rcvif = NULL; 1398 priv->stats.xmitZLBs++; 1399 } else { 1400 1401 /* Strip off session ID */ 1402 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL) { 1403 priv->stats.memoryFailures++; 1404 return (ENOBUFS); 1405 } 1406 memcpy(&session_id, mtod(m, u_int16_t *), 2); 1407 m_adj(m, 2); 1408 1409 /* Make room for L2TP header */ 1410 M_PREPEND(m, 12, M_DONTWAIT); 1411 if (m == NULL) { 1412 priv->stats.memoryFailures++; 1413 return (ENOBUFS); 1414 } 1415 } 1416 1417 /* Fill in L2TP header */ 1418 mtod(m, u_int16_t *)[0] = htons(L2TP_CTRL_HDR); 1419 mtod(m, u_int16_t *)[1] = htons(m->m_pkthdr.len); 1420 mtod(m, u_int16_t *)[2] = priv->conf.peer_id; 1421 mtod(m, u_int16_t *)[3] = session_id; 1422 mtod(m, u_int16_t *)[4] = htons(ns); 1423 mtod(m, u_int16_t *)[5] = htons(seq->nr); 1424 1425 /* Update sequence number info and stats */ 1426 priv->stats.xmitPackets++; 1427 priv->stats.xmitOctets += m->m_pkthdr.len; 1428 1429 /* Stop ack timer: we're sending an ack with this packet */ 1430 if (seq->xack_timer_running && callout_stop(&seq->xack_timer) == 1) { 1431 seq->xack_timer_running = 0; 1432 NG_NODE_UNREF(priv->node); 1433 } 1434 seq->xack = seq->nr; 1435 1436 /* Send packet */ 1437 NG_SEND_DATA(error, priv->lower, m, meta); 1438 return (error); 1439} 1440 1441#ifdef INVARIANTS 1442/* 1443 * Sanity check sequence number state. 1444 */ 1445static void 1446ng_l2tp_seq_check(struct l2tp_seq *seq) 1447{ 1448 const int self_unack = L2TP_SEQ_DIFF(seq->nr, seq->xack); 1449 const int peer_unack = L2TP_SEQ_DIFF(seq->ns, seq->rack); 1450 int i; 1451 1452#define CHECK(p) KASSERT((p), ("%s: not: %s", __FUNCTION__, #p)) 1453 1454 CHECK(seq->wmax <= L2TP_MAX_XWIN); 1455 CHECK(seq->cwnd >= 1); 1456 CHECK(seq->cwnd <= seq->wmax); 1457 CHECK(seq->ssth >= 1); 1458 CHECK(seq->ssth <= seq->wmax); 1459 if (seq->cwnd < seq->ssth) 1460 CHECK(seq->acks == 0); 1461 else 1462 CHECK(seq->acks <= seq->cwnd); 1463 CHECK(self_unack >= 0); 1464 CHECK(peer_unack >= 0); 1465 CHECK(peer_unack <= seq->wmax); 1466 CHECK((self_unack == 0) ^ seq->xack_timer_running); 1467 CHECK((peer_unack == 0) ^ seq->rack_timer_running); 1468 CHECK(seq->rack_timer_running || !callout_pending(&seq->rack_timer)); 1469 CHECK(seq->xack_timer_running || !callout_pending(&seq->xack_timer)); 1470 for (i = 0; i < peer_unack; i++) 1471 CHECK(seq->xwin[i] != NULL); 1472 for ( ; i < seq->cwnd; i++) /* verify peer's recv window full */ 1473 CHECK(seq->xwin[i] == NULL); 1474 1475#undef CHECK 1476} 1477#endif /* INVARIANTS */ 1478 1479
|