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