1 /* 2 * ng_pptpgre.c 3 */ 4 5 /*- 6 * Copyright (c) 1996-1999 Whistle Communications, Inc. 7 * All rights reserved. 8 * 9 * Subject to the following obligations and disclaimer of warranty, use and 10 * redistribution of this software, in source or object code forms, with or 11 * without modifications are expressly permitted by Whistle Communications; 12 * provided, however, that: 13 * 1. Any and all reproductions of the source or object code must include the 14 * copyright notice above and the following disclaimer of warranties; and 15 * 2. No rights are granted, in any manner or form, to use Whistle 16 * Communications, Inc. trademarks, including the mark "WHISTLE 17 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 18 * such appears in the above copyright notice or in the software. 19 * 20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36 * OF SUCH DAMAGE. 37 * 38 * Author: Archie Cobbs <archie@freebsd.org> 39 * 40 * $FreeBSD$ 41 * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $ 42 */ 43 44 /* 45 * PPTP/GRE netgraph node type. 46 * 47 * This node type does the GRE encapsulation as specified for the PPTP 48 * protocol (RFC 2637, section 4). This includes sequencing and 49 * retransmission of frames, but not the actual packet delivery nor 50 * any of the TCP control stream protocol. 51 * 52 * The "upper" hook of this node is suitable for attaching to a "ppp" 53 * node link hook. The "lower" hook of this node is suitable for attaching 54 * to a "ksocket" node on hook "inet/raw/gre". 55 */ 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/kernel.h> 60 #include <sys/time.h> 61 #include <sys/lock.h> 62 #include <sys/malloc.h> 63 #include <sys/mbuf.h> 64 #include <sys/mutex.h> 65 #include <sys/endian.h> 66 #include <sys/errno.h> 67 #include <sys/sysctl.h> 68 69 #include <netinet/in.h> 70 #include <netinet/in_systm.h> 71 #include <netinet/ip.h> 72 73 #include <netgraph/ng_message.h> 74 #include <netgraph/netgraph.h> 75 #include <netgraph/ng_parse.h> 76 #include <netgraph/ng_pptpgre.h> 77 78 /* GRE packet format, as used by PPTP */ 79 struct greheader { 80 #if BYTE_ORDER == LITTLE_ENDIAN 81 u_char recursion:3; /* recursion control */ 82 u_char ssr:1; /* strict source route */ 83 u_char hasSeq:1; /* sequence number present */ 84 u_char hasKey:1; /* key present */ 85 u_char hasRoute:1; /* routing present */ 86 u_char hasSum:1; /* checksum present */ 87 u_char vers:3; /* version */ 88 u_char flags:4; /* flags */ 89 u_char hasAck:1; /* acknowlege number present */ 90 #elif BYTE_ORDER == BIG_ENDIAN 91 u_char hasSum:1; /* checksum present */ 92 u_char hasRoute:1; /* routing present */ 93 u_char hasKey:1; /* key present */ 94 u_char hasSeq:1; /* sequence number present */ 95 u_char ssr:1; /* strict source route */ 96 u_char recursion:3; /* recursion control */ 97 u_char hasAck:1; /* acknowlege number present */ 98 u_char flags:4; /* flags */ 99 u_char vers:3; /* version */ 100 #else 101 #error BYTE_ORDER is not defined properly 102 #endif 103 u_int16_t proto; /* protocol (ethertype) */ 104 u_int16_t length; /* payload length */ 105 u_int16_t cid; /* call id */ 106 u_int32_t data[0]; /* opt. seq, ack, then data */ 107 }; 108 109 /* The PPTP protocol ID used in the GRE 'proto' field */ 110 #define PPTP_GRE_PROTO 0x880b 111 112 /* Bits that must be set a certain way in all PPTP/GRE packets */ 113 #define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO) 114 #define PPTP_INIT_MASK 0xef7fffff 115 116 /* Min and max packet length */ 117 #define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8) 118 119 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */ 120 #define PPTP_TIME_SCALE 1024 /* milliseconds */ 121 typedef u_int64_t pptptime_t; 122 123 /* Acknowledgment timeout parameters and functions */ 124 #define PPTP_XMIT_WIN 16 /* max xmit window */ 125 #define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 83) /* 12 milliseconds */ 126 #define PPTP_MAX_TIMEOUT (3 * PPTP_TIME_SCALE) /* 3 seconds */ 127 128 #define PPTP_REORDER_TIMEOUT 1 129 130 /* When we receive a packet, we wait to see if there's an outgoing packet 131 we can piggy-back the ACK off of. These parameters determine the mimimum 132 and maxmimum length of time we're willing to wait in order to do that. 133 These have no effect unless "enableDelayedAck" is turned on. */ 134 #define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500) /* 2 milliseconds */ 135 #define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2) /* 500 milliseconds */ 136 137 /* See RFC 2637 section 4.4 */ 138 #define PPTP_ACK_ALPHA(x) (((x) + 4) >> 3) /* alpha = 0.125 */ 139 #define PPTP_ACK_BETA(x) (((x) + 2) >> 2) /* beta = 0.25 */ 140 #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 141 #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 142 143 #define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y)) 144 145 #define SESSHASHSIZE 0x0020 146 #define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1)) 147 148 SYSCTL_NODE(_net_graph, OID_AUTO, pptpgre, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 149 "PPTPGRE"); 150 151 /* 152 * Reorder queue maximum length. Zero disables reorder. 153 * 154 * The node may keep reorder_max queue entries per session 155 * if reorder is enabled, plus allocate one more for short time. 156 * 157 * Be conservative in memory consumption by default. 158 * Lots of sessions with large queues can overflow M_NETGRAPH zone. 159 */ 160 static int reorder_max = 1; /* reorder up to two swapped packets in a row */ 161 SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_max, CTLFLAG_RWTUN, 162 &reorder_max, 0, "Reorder queue maximum length"); 163 164 static int reorder_timeout = PPTP_REORDER_TIMEOUT; 165 SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_timeout, CTLFLAG_RWTUN, 166 &reorder_timeout, 0, "Reorder timeout is milliseconds"); 167 168 /* Packet reorder FIFO queue */ 169 struct ng_pptpgre_roq { 170 SLIST_ENTRY(ng_pptpgre_roq) next; /* next entry of the queue */ 171 item_p item; /* netgraph item */ 172 u_int32_t seq; /* packet sequence number */ 173 }; 174 SLIST_HEAD(ng_pptpgre_roq_head, ng_pptpgre_roq); 175 typedef struct ng_pptpgre_roq_head roqh; 176 177 /* We keep packet retransmit and acknowlegement state in this struct */ 178 struct ng_pptpgre_sess { 179 node_p node; /* this node pointer */ 180 hook_p hook; /* hook to upper layers */ 181 struct ng_pptpgre_conf conf; /* configuration info */ 182 struct mtx mtx; /* session mutex */ 183 u_int32_t recvSeq; /* last seq # we rcv'd */ 184 u_int32_t xmitSeq; /* last seq # we sent */ 185 u_int32_t recvAck; /* last seq # peer ack'd */ 186 u_int32_t xmitAck; /* last seq # we ack'd */ 187 int32_t ato; /* adaptive time-out value */ 188 int32_t rtt; /* round trip time estimate */ 189 int32_t dev; /* deviation estimate */ 190 u_int16_t xmitWin; /* size of xmit window */ 191 struct callout sackTimer; /* send ack timer */ 192 struct callout rackTimer; /* recv ack timer */ 193 u_int32_t winAck; /* seq when xmitWin will grow */ 194 pptptime_t timeSent[PPTP_XMIT_WIN]; 195 LIST_ENTRY(ng_pptpgre_sess) sessions; 196 roqh roq; /* reorder queue head */ 197 u_int8_t roq_len; /* reorder queue length */ 198 struct callout reorderTimer; /* reorder timeout handler */ 199 }; 200 typedef struct ng_pptpgre_sess *hpriv_p; 201 202 /* Node private data */ 203 struct ng_pptpgre_private { 204 hook_p upper; /* hook to upper layers */ 205 hook_p lower; /* hook to lower layers */ 206 struct ng_pptpgre_sess uppersess; /* default session for compat */ 207 LIST_HEAD(, ng_pptpgre_sess) sesshash[SESSHASHSIZE]; 208 struct ng_pptpgre_stats stats; /* node statistics */ 209 }; 210 typedef struct ng_pptpgre_private *priv_p; 211 212 /* Netgraph node methods */ 213 static ng_constructor_t ng_pptpgre_constructor; 214 static ng_rcvmsg_t ng_pptpgre_rcvmsg; 215 static ng_shutdown_t ng_pptpgre_shutdown; 216 static ng_newhook_t ng_pptpgre_newhook; 217 static ng_rcvdata_t ng_pptpgre_rcvdata; 218 static ng_rcvdata_t ng_pptpgre_rcvdata_lower; 219 static ng_disconnect_t ng_pptpgre_disconnect; 220 221 /* Helper functions */ 222 static int ng_pptpgre_xmit(hpriv_p hpriv, item_p item); 223 static void ng_pptpgre_start_send_ack_timer(hpriv_p hpriv); 224 static void ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv); 225 static void ng_pptpgre_start_reorder_timer(hpriv_p hpriv); 226 static void ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, 227 void *arg1, int arg2); 228 static void ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, 229 void *arg1, int arg2); 230 static void ng_pptpgre_reorder_timeout(node_p node, hook_p hook, 231 void *arg1, int arg2); 232 static hpriv_p ng_pptpgre_find_session(priv_p privp, u_int16_t cid); 233 static void ng_pptpgre_reset(hpriv_p hpriv); 234 static pptptime_t ng_pptpgre_time(void); 235 static void ng_pptpgre_ack(const hpriv_p hpriv); 236 static int ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q, 237 const struct ng_pptpgre_roq *st); 238 239 /* Parse type for struct ng_pptpgre_conf */ 240 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[] 241 = NG_PPTPGRE_CONF_TYPE_INFO; 242 static const struct ng_parse_type ng_pptpgre_conf_type = { 243 &ng_parse_struct_type, 244 &ng_pptpgre_conf_type_fields, 245 }; 246 247 /* Parse type for struct ng_pptpgre_stats */ 248 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[] 249 = NG_PPTPGRE_STATS_TYPE_INFO; 250 static const struct ng_parse_type ng_pptp_stats_type = { 251 &ng_parse_struct_type, 252 &ng_pptpgre_stats_type_fields 253 }; 254 255 /* List of commands and how to convert arguments to/from ASCII */ 256 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 257 { 258 NGM_PPTPGRE_COOKIE, 259 NGM_PPTPGRE_SET_CONFIG, 260 "setconfig", 261 &ng_pptpgre_conf_type, 262 NULL 263 }, 264 { 265 NGM_PPTPGRE_COOKIE, 266 NGM_PPTPGRE_GET_CONFIG, 267 "getconfig", 268 &ng_parse_hint16_type, 269 &ng_pptpgre_conf_type 270 }, 271 { 272 NGM_PPTPGRE_COOKIE, 273 NGM_PPTPGRE_GET_STATS, 274 "getstats", 275 NULL, 276 &ng_pptp_stats_type 277 }, 278 { 279 NGM_PPTPGRE_COOKIE, 280 NGM_PPTPGRE_CLR_STATS, 281 "clrstats", 282 NULL, 283 NULL 284 }, 285 { 286 NGM_PPTPGRE_COOKIE, 287 NGM_PPTPGRE_GETCLR_STATS, 288 "getclrstats", 289 NULL, 290 &ng_pptp_stats_type 291 }, 292 { 0 } 293 }; 294 295 /* Node type descriptor */ 296 static struct ng_type ng_pptpgre_typestruct = { 297 .version = NG_ABI_VERSION, 298 .name = NG_PPTPGRE_NODE_TYPE, 299 .constructor = ng_pptpgre_constructor, 300 .rcvmsg = ng_pptpgre_rcvmsg, 301 .shutdown = ng_pptpgre_shutdown, 302 .newhook = ng_pptpgre_newhook, 303 .rcvdata = ng_pptpgre_rcvdata, 304 .disconnect = ng_pptpgre_disconnect, 305 .cmdlist = ng_pptpgre_cmdlist, 306 }; 307 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 308 309 #define ERROUT(x) do { error = (x); goto done; } while (0) 310 311 /************************************************************************ 312 NETGRAPH NODE STUFF 313 ************************************************************************/ 314 315 /* 316 * Node type constructor 317 */ 318 static int 319 ng_pptpgre_constructor(node_p node) 320 { 321 priv_p priv; 322 int i; 323 324 /* Allocate private structure */ 325 priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 326 327 NG_NODE_SET_PRIVATE(node, priv); 328 329 /* Initialize state */ 330 mtx_init(&priv->uppersess.mtx, "ng_pptp", NULL, MTX_DEF); 331 ng_callout_init(&priv->uppersess.sackTimer); 332 ng_callout_init(&priv->uppersess.rackTimer); 333 priv->uppersess.node = node; 334 335 SLIST_INIT(&priv->uppersess.roq); 336 priv->uppersess.roq_len = 0; 337 ng_callout_init(&priv->uppersess.reorderTimer); 338 339 for (i = 0; i < SESSHASHSIZE; i++) 340 LIST_INIT(&priv->sesshash[i]); 341 342 LIST_INSERT_HEAD(&priv->sesshash[0], &priv->uppersess, sessions); 343 344 /* Done */ 345 return (0); 346 } 347 348 /* 349 * Give our OK for a hook to be added. 350 */ 351 static int 352 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 353 { 354 const priv_p priv = NG_NODE_PRIVATE(node); 355 356 /* Check hook name */ 357 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) { 358 priv->upper = hook; 359 priv->uppersess.hook = hook; 360 NG_HOOK_SET_PRIVATE(hook, &priv->uppersess); 361 } else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) { 362 priv->lower = hook; 363 NG_HOOK_SET_RCVDATA(hook, ng_pptpgre_rcvdata_lower); 364 } else { 365 static const char hexdig[16] = "0123456789abcdef"; 366 const char *hex; 367 hpriv_p hpriv; 368 int i, j; 369 uint16_t cid, hash; 370 371 /* Parse hook name to get session ID */ 372 if (strncmp(name, NG_PPTPGRE_HOOK_SESSION_P, 373 sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1) != 0) 374 return (EINVAL); 375 hex = name + sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1; 376 for (cid = i = 0; i < 4; i++) { 377 for (j = 0; j < 16 && hex[i] != hexdig[j]; j++); 378 if (j == 16) 379 return (EINVAL); 380 cid = (cid << 4) | j; 381 } 382 if (hex[i] != '\0') 383 return (EINVAL); 384 385 hpriv = malloc(sizeof(*hpriv), M_NETGRAPH, M_NOWAIT | M_ZERO); 386 if (hpriv == NULL) 387 return (ENOMEM); 388 389 /* Initialize state */ 390 mtx_init(&hpriv->mtx, "ng_pptp", NULL, MTX_DEF); 391 ng_callout_init(&hpriv->sackTimer); 392 ng_callout_init(&hpriv->rackTimer); 393 hpriv->conf.cid = cid; 394 hpriv->node = node; 395 hpriv->hook = hook; 396 397 SLIST_INIT(&hpriv->roq); 398 hpriv->roq_len = 0; 399 ng_callout_init(&hpriv->reorderTimer); 400 401 NG_HOOK_SET_PRIVATE(hook, hpriv); 402 403 hash = SESSHASH(cid); 404 LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions); 405 } 406 407 return (0); 408 } 409 410 /* 411 * Receive a control message. 412 */ 413 static int 414 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook) 415 { 416 const priv_p priv = NG_NODE_PRIVATE(node); 417 struct ng_mesg *resp = NULL; 418 int error = 0; 419 struct ng_mesg *msg; 420 421 NGI_GET_MSG(item, msg); 422 switch (msg->header.typecookie) { 423 case NGM_PPTPGRE_COOKIE: 424 switch (msg->header.cmd) { 425 case NGM_PPTPGRE_SET_CONFIG: 426 { 427 struct ng_pptpgre_conf *const newConf = 428 (struct ng_pptpgre_conf *) msg->data; 429 hpriv_p hpriv; 430 uint16_t hash; 431 432 /* Check for invalid or illegal config */ 433 if (msg->header.arglen != sizeof(*newConf)) 434 ERROUT(EINVAL); 435 /* Try to find session by cid. */ 436 hpriv = ng_pptpgre_find_session(priv, newConf->cid); 437 /* If not present - use upper. */ 438 if (hpriv == NULL) { 439 hpriv = &priv->uppersess; 440 LIST_REMOVE(hpriv, sessions); 441 hash = SESSHASH(newConf->cid); 442 LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, 443 sessions); 444 } 445 ng_pptpgre_reset(hpriv); /* reset on configure */ 446 hpriv->conf = *newConf; 447 break; 448 } 449 case NGM_PPTPGRE_GET_CONFIG: 450 { 451 hpriv_p hpriv; 452 453 if (msg->header.arglen == 2) { 454 /* Try to find session by cid. */ 455 hpriv = ng_pptpgre_find_session(priv, 456 *((uint16_t *)msg->data)); 457 if (hpriv == NULL) 458 ERROUT(EINVAL); 459 } else if (msg->header.arglen == 0) { 460 /* Use upper. */ 461 hpriv = &priv->uppersess; 462 } else 463 ERROUT(EINVAL); 464 NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT); 465 if (resp == NULL) 466 ERROUT(ENOMEM); 467 bcopy(&hpriv->conf, resp->data, sizeof(hpriv->conf)); 468 break; 469 } 470 case NGM_PPTPGRE_GET_STATS: 471 case NGM_PPTPGRE_CLR_STATS: 472 case NGM_PPTPGRE_GETCLR_STATS: 473 { 474 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) { 475 NG_MKRESPONSE(resp, msg, 476 sizeof(priv->stats), M_NOWAIT); 477 if (resp == NULL) 478 ERROUT(ENOMEM); 479 bcopy(&priv->stats, 480 resp->data, sizeof(priv->stats)); 481 } 482 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS) 483 bzero(&priv->stats, sizeof(priv->stats)); 484 break; 485 } 486 default: 487 error = EINVAL; 488 break; 489 } 490 break; 491 default: 492 error = EINVAL; 493 break; 494 } 495 done: 496 NG_RESPOND_MSG(error, node, item, resp); 497 NG_FREE_MSG(msg); 498 return (error); 499 } 500 501 /* 502 * Receive incoming data on a hook. 503 */ 504 static int 505 ng_pptpgre_rcvdata(hook_p hook, item_p item) 506 { 507 const hpriv_p hpriv = NG_HOOK_PRIVATE(hook); 508 int rval; 509 510 /* If not configured, reject */ 511 if (!hpriv->conf.enabled) { 512 NG_FREE_ITEM(item); 513 return (ENXIO); 514 } 515 516 mtx_lock(&hpriv->mtx); 517 518 rval = ng_pptpgre_xmit(hpriv, item); 519 520 mtx_assert(&hpriv->mtx, MA_NOTOWNED); 521 522 return (rval); 523 } 524 525 /* 526 * Hook disconnection 527 */ 528 static int 529 ng_pptpgre_disconnect(hook_p hook) 530 { 531 const node_p node = NG_HOOK_NODE(hook); 532 const priv_p priv = NG_NODE_PRIVATE(node); 533 const hpriv_p hpriv = NG_HOOK_PRIVATE(hook); 534 535 /* Zero out hook pointer */ 536 if (hook == priv->upper) { 537 priv->upper = NULL; 538 priv->uppersess.hook = NULL; 539 } else if (hook == priv->lower) { 540 priv->lower = NULL; 541 } else { 542 /* Reset node (stops timers) */ 543 ng_pptpgre_reset(hpriv); 544 545 LIST_REMOVE(hpriv, sessions); 546 mtx_destroy(&hpriv->mtx); 547 free(hpriv, M_NETGRAPH); 548 } 549 550 /* Go away if no longer connected to anything */ 551 if ((NG_NODE_NUMHOOKS(node) == 0) 552 && (NG_NODE_IS_VALID(node))) 553 ng_rmnode_self(node); 554 return (0); 555 } 556 557 /* 558 * Destroy node 559 */ 560 static int 561 ng_pptpgre_shutdown(node_p node) 562 { 563 const priv_p priv = NG_NODE_PRIVATE(node); 564 565 /* Reset node (stops timers) */ 566 ng_pptpgre_reset(&priv->uppersess); 567 568 LIST_REMOVE(&priv->uppersess, sessions); 569 mtx_destroy(&priv->uppersess.mtx); 570 571 free(priv, M_NETGRAPH); 572 573 /* Decrement ref count */ 574 NG_NODE_UNREF(node); 575 return (0); 576 } 577 578 /************************************************************************* 579 TRANSMIT AND RECEIVE FUNCTIONS 580 *************************************************************************/ 581 582 /* 583 * Transmit an outgoing frame, or just an ack if m is NULL. 584 */ 585 static int 586 ng_pptpgre_xmit(hpriv_p hpriv, item_p item) 587 { 588 const priv_p priv = NG_NODE_PRIVATE(hpriv->node); 589 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 590 struct greheader *const gre = (struct greheader *)buf; 591 int grelen, error; 592 struct mbuf *m; 593 594 mtx_assert(&hpriv->mtx, MA_OWNED); 595 596 if (item) { 597 NGI_GET_M(item, m); 598 } else { 599 m = NULL; 600 } 601 /* Check if there's data */ 602 if (m != NULL) { 603 604 /* Check if windowing is enabled */ 605 if (hpriv->conf.enableWindowing) { 606 /* Is our transmit window full? */ 607 if ((u_int32_t)PPTP_SEQ_DIFF(hpriv->xmitSeq, 608 hpriv->recvAck) >= hpriv->xmitWin) { 609 priv->stats.xmitDrops++; 610 ERROUT(ENOBUFS); 611 } 612 } 613 614 /* Sanity check frame length */ 615 if (m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 616 priv->stats.xmitTooBig++; 617 ERROUT(EMSGSIZE); 618 } 619 } else { 620 priv->stats.xmitLoneAcks++; 621 } 622 623 /* Build GRE header */ 624 be32enc(gre, PPTP_INIT_VALUE); 625 be16enc(&gre->length, (m != NULL) ? m->m_pkthdr.len : 0); 626 be16enc(&gre->cid, hpriv->conf.peerCid); 627 628 /* Include sequence number if packet contains any data */ 629 if (m != NULL) { 630 gre->hasSeq = 1; 631 if (hpriv->conf.enableWindowing) { 632 hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck] 633 = ng_pptpgre_time(); 634 } 635 hpriv->xmitSeq++; 636 be32enc(&gre->data[0], hpriv->xmitSeq); 637 } 638 639 /* Include acknowledgement (and stop send ack timer) if needed */ 640 if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) { 641 gre->hasAck = 1; 642 be32enc(&gre->data[gre->hasSeq], hpriv->recvSeq); 643 hpriv->xmitAck = hpriv->recvSeq; 644 if (hpriv->conf.enableDelayedAck) 645 ng_uncallout(&hpriv->sackTimer, hpriv->node); 646 } 647 648 /* Prepend GRE header to outgoing frame */ 649 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 650 if (m == NULL) { 651 MGETHDR(m, M_NOWAIT, MT_DATA); 652 if (m == NULL) { 653 priv->stats.memoryFailures++; 654 ERROUT(ENOBUFS); 655 } 656 m->m_len = m->m_pkthdr.len = grelen; 657 m->m_pkthdr.rcvif = NULL; 658 } else { 659 M_PREPEND(m, grelen, M_NOWAIT); 660 if (m == NULL || (m->m_len < grelen 661 && (m = m_pullup(m, grelen)) == NULL)) { 662 priv->stats.memoryFailures++; 663 ERROUT(ENOBUFS); 664 } 665 } 666 bcopy(gre, mtod(m, u_char *), grelen); 667 668 /* Update stats */ 669 priv->stats.xmitPackets++; 670 priv->stats.xmitOctets += m->m_pkthdr.len; 671 672 /* 673 * XXX: we should reset timer only after an item has been sent 674 * successfully. 675 */ 676 if (hpriv->conf.enableWindowing && 677 gre->hasSeq && hpriv->xmitSeq == hpriv->recvAck + 1) 678 ng_pptpgre_start_recv_ack_timer(hpriv); 679 680 mtx_unlock(&hpriv->mtx); 681 682 /* Deliver packet */ 683 if (item) { 684 NG_FWD_NEW_DATA(error, item, priv->lower, m); 685 } else { 686 NG_SEND_DATA_ONLY(error, priv->lower, m); 687 } 688 689 return (error); 690 691 done: 692 mtx_unlock(&hpriv->mtx); 693 NG_FREE_M(m); 694 if (item) 695 NG_FREE_ITEM(item); 696 return (error); 697 } 698 699 static void 700 ng_pptpgre_ack(const hpriv_p hpriv) 701 { 702 mtx_assert(&hpriv->mtx, MA_OWNED); 703 if (!(callout_pending(&hpriv->sackTimer))) { 704 /* If delayed ACK is disabled, send it now */ 705 if (!hpriv->conf.enableDelayedAck) { /* ack now */ 706 ng_pptpgre_xmit(hpriv, NULL); 707 /* ng_pptpgre_xmit() drops the mutex */ 708 return; 709 } 710 /* ack later */ 711 ng_pptpgre_start_send_ack_timer(hpriv); 712 mtx_unlock(&hpriv->mtx); 713 return; 714 } 715 mtx_unlock(&hpriv->mtx); 716 } 717 718 /* 719 * Delivers packets from the queue "q" to upper layers. Frees delivered 720 * entries with the exception of one equal to "st" that is allocated 721 * on caller's stack and not on the heap. 722 */ 723 static int 724 ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q, const struct ng_pptpgre_roq *st) 725 { 726 struct ng_pptpgre_roq *np; 727 struct mbuf *m; 728 int error = 0; 729 730 mtx_assert(&hpriv->mtx, MA_NOTOWNED); 731 while (!SLIST_EMPTY(q)) { 732 np = SLIST_FIRST(q); 733 SLIST_REMOVE_HEAD(q, next); 734 NGI_GET_M(np->item, m); 735 NG_FWD_NEW_DATA(error, np->item, hpriv->hook, m); 736 if (np != st) 737 free(np, M_NETGRAPH); 738 } 739 return (error); 740 } 741 742 /* 743 * Handle an incoming packet. The packet includes the IP header. 744 */ 745 static int 746 ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) 747 { 748 hpriv_p hpriv; 749 node_p node = NG_HOOK_NODE(hook); 750 const priv_p priv = NG_NODE_PRIVATE(node); 751 int iphlen, grelen, extralen; 752 const struct greheader *gre; 753 const struct ip *ip; 754 int error = 0; 755 struct mbuf *m; 756 757 roqh sendq = SLIST_HEAD_INITIALIZER(sendq); /* send queue on stack */ 758 struct ng_pptpgre_roq *last = NULL; /* last packet in the sendq */ 759 struct ng_pptpgre_roq *np, *prev; 760 struct ng_pptpgre_roq temp = { { NULL }, NULL, 0 }; 761 long diff; 762 u_int32_t seq; 763 764 m = NGI_M(item); 765 /* Update stats */ 766 priv->stats.recvPackets++; 767 priv->stats.recvOctets += m->m_pkthdr.len; 768 769 /* Sanity check packet length */ 770 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 771 priv->stats.recvRunts++; 772 ERROUT(EINVAL); 773 } 774 775 /* Safely pull up the complete IP+GRE headers */ 776 if (m->m_len < sizeof(*ip) + sizeof(*gre)) { 777 if ((m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 778 priv->stats.memoryFailures++; 779 _NGI_M(item) = NULL; 780 ERROUT(ENOBUFS); 781 } 782 _NGI_M(item) = m; 783 } 784 ip = mtod(m, const struct ip *); 785 iphlen = ip->ip_hl << 2; 786 if (m->m_len < iphlen + sizeof(*gre)) { 787 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 788 priv->stats.memoryFailures++; 789 _NGI_M(item) = NULL; 790 ERROUT(ENOBUFS); 791 } 792 _NGI_M(item) = m; 793 ip = mtod(m, const struct ip *); 794 } 795 gre = (const struct greheader *)((const u_char *)ip + iphlen); 796 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 797 if (m->m_pkthdr.len < iphlen + grelen) { 798 priv->stats.recvRunts++; 799 ERROUT(EINVAL); 800 } 801 if (m->m_len < iphlen + grelen) { 802 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 803 priv->stats.memoryFailures++; 804 _NGI_M(item) = NULL; 805 ERROUT(ENOBUFS); 806 } 807 _NGI_M(item) = m; 808 ip = mtod(m, const struct ip *); 809 gre = (const struct greheader *)((const u_char *)ip + iphlen); 810 } 811 812 /* Sanity check packet length and GRE header bits */ 813 extralen = m->m_pkthdr.len 814 - (iphlen + grelen + gre->hasSeq * be16dec(&gre->length)); 815 if (extralen < 0) { 816 priv->stats.recvBadGRE++; 817 ERROUT(EINVAL); 818 } 819 if ((be32dec(gre) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) { 820 priv->stats.recvBadGRE++; 821 ERROUT(EINVAL); 822 } 823 824 hpriv = ng_pptpgre_find_session(priv, be16dec(&gre->cid)); 825 if (hpriv == NULL || hpriv->hook == NULL || !hpriv->conf.enabled) { 826 priv->stats.recvBadCID++; 827 ERROUT(EINVAL); 828 } 829 mtx_lock(&hpriv->mtx); 830 831 /* Look for peer ack */ 832 if (gre->hasAck) { 833 const u_int32_t ack = be32dec(&gre->data[gre->hasSeq]); 834 const int index = ack - hpriv->recvAck - 1; 835 long sample; 836 837 /* Sanity check ack value */ 838 if (PPTP_SEQ_DIFF(ack, hpriv->xmitSeq) > 0) { 839 priv->stats.recvBadAcks++; 840 goto badAck; /* we never sent it! */ 841 } 842 if (PPTP_SEQ_DIFF(ack, hpriv->recvAck) <= 0) 843 goto badAck; /* ack already timed out */ 844 hpriv->recvAck = ack; 845 846 /* Update adaptive timeout stuff */ 847 if (hpriv->conf.enableWindowing) { 848 sample = ng_pptpgre_time() - hpriv->timeSent[index]; 849 diff = sample - hpriv->rtt; 850 hpriv->rtt += PPTP_ACK_ALPHA(diff); 851 if (diff < 0) 852 diff = -diff; 853 hpriv->dev += PPTP_ACK_BETA(diff - hpriv->dev); 854 /* +2 to compensate low precision of int math */ 855 hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev + 2); 856 if (hpriv->ato > PPTP_MAX_TIMEOUT) 857 hpriv->ato = PPTP_MAX_TIMEOUT; 858 else if (hpriv->ato < PPTP_MIN_TIMEOUT) 859 hpriv->ato = PPTP_MIN_TIMEOUT; 860 861 /* Shift packet transmit times in our transmit window */ 862 bcopy(hpriv->timeSent + index + 1, hpriv->timeSent, 863 sizeof(*hpriv->timeSent) 864 * (PPTP_XMIT_WIN - (index + 1))); 865 866 /* If we sent an entire window, increase window size */ 867 if (PPTP_SEQ_DIFF(ack, hpriv->winAck) >= 0 868 && hpriv->xmitWin < PPTP_XMIT_WIN) { 869 hpriv->xmitWin++; 870 hpriv->winAck = ack + hpriv->xmitWin; 871 } 872 873 /* Stop/(re)start receive ACK timer as necessary */ 874 ng_uncallout(&hpriv->rackTimer, hpriv->node); 875 if (hpriv->recvAck != hpriv->xmitSeq) 876 ng_pptpgre_start_recv_ack_timer(hpriv); 877 } 878 } 879 badAck: 880 881 /* See if frame contains any data */ 882 if (!gre->hasSeq) { /* no data to deliver */ 883 priv->stats.recvLoneAcks++; 884 mtx_unlock(&hpriv->mtx); 885 ERROUT(0); 886 } 887 888 seq = be32dec(&gre->data[0]); 889 890 diff = PPTP_SEQ_DIFF(seq, hpriv->recvSeq); 891 if (diff <= 0) { /* late or duplicate packet */ 892 if (diff < 0 && reorder_max == 0) /* reorder disabled */ 893 priv->stats.recvOutOfOrder++; /* late */ 894 else 895 priv->stats.recvDuplicates++; /* duplicate */ 896 mtx_unlock(&hpriv->mtx); 897 ERROUT(EINVAL); 898 } 899 900 /* Trim mbuf down to internal payload */ 901 m_adj(m, iphlen + grelen); 902 if (extralen > 0) 903 m_adj(m, -extralen); 904 905 #define INIT_SENDQ(t) do { \ 906 t.item = item; \ 907 t.seq = seq; \ 908 SLIST_INSERT_HEAD(&sendq, &t, next); \ 909 last = &t; \ 910 hpriv->recvSeq = seq; \ 911 goto deliver; \ 912 } while(0) 913 914 if (diff == 1) 915 /* the packet came in order, place it at the start of sendq */ 916 INIT_SENDQ(temp); 917 918 /* The packet came too early, try to enqueue it. 919 * 920 * Check for duplicate in the queue. After this loop, "prev" will be 921 * NULL if the packet should become new head of the queue, 922 * or else it should be inserted after the "prev". 923 */ 924 prev = SLIST_FIRST(&hpriv->roq); 925 SLIST_FOREACH(np, &hpriv->roq, next) { 926 diff = PPTP_SEQ_DIFF(np->seq, seq); 927 if (diff == 0) { /* do not add duplicate, drop it */ 928 priv->stats.recvDuplicates++; 929 mtx_unlock(&hpriv->mtx); 930 ERROUT(EINVAL); 931 } 932 if (diff > 0) { /* we found newer packet */ 933 if (np == prev) /* that is the head of the queue */ 934 prev = NULL; /* put current packet to the head */ 935 break; 936 } 937 prev = np; 938 } 939 940 priv->stats.recvOutOfOrder++; /* duplicate not found */ 941 if (hpriv->roq_len < reorder_max) 942 goto enqueue; /* reorder enabled and there is a room */ 943 944 /* 945 * There is no room in the queue or reorder disabled. 946 * 947 * It the latter case, we may still have non-empty reorder queue 948 * if reorder was disabled in process of reordering. 949 * Then we correctly deliver the queue without growing it. 950 * 951 * In both cases, no malloc()'s until the queue is shortened. 952 */ 953 priv->stats.recvReorderOverflow++; 954 if (prev == NULL) { /* new packet goes before the head */ 955 INIT_SENDQ(temp); /* of reorder queue, so put it to sendq */ 956 } 957 #undef INIT_SENDQ 958 959 /* 960 * Current packet goes after the head of reorder queue. 961 * Move the head to sendq to make room for current packet. 962 */ 963 np = SLIST_FIRST(&hpriv->roq); 964 if (prev == np) 965 prev = NULL; 966 SLIST_REMOVE_HEAD(&hpriv->roq, next); 967 hpriv->roq_len--; /* we are allowed to use malloc() now */ 968 SLIST_INSERT_HEAD(&sendq, np, next); 969 last = np; 970 hpriv->recvSeq = np->seq; 971 972 enqueue: 973 np = malloc(sizeof(*np), M_NETGRAPH, M_NOWAIT | M_ZERO); 974 if (np == NULL) { 975 priv->stats.memoryFailures++; 976 /* 977 * Emergency: we cannot save new data. 978 * Flush the queue delivering all queued packets preceeding 979 * current one despite of gaps. 980 */ 981 while (!SLIST_EMPTY(&hpriv->roq)) { 982 np = SLIST_FIRST(&hpriv->roq); 983 if (np->seq > seq) 984 break; 985 SLIST_REMOVE_HEAD(&hpriv->roq, next); 986 hpriv->roq_len--; 987 if (last == NULL) 988 SLIST_INSERT_HEAD(&sendq, np, next); 989 else 990 SLIST_INSERT_AFTER(last, np, next); 991 last = np; 992 } 993 994 /* 995 * Pretend we got all packets till the current one 996 * and acknowledge it. 997 */ 998 hpriv->recvSeq = seq; 999 ng_pptpgre_ack(hpriv); /* drops lock */ 1000 ng_pptpgre_sendq(hpriv, &sendq, &temp); 1001 NG_FWD_NEW_DATA(error, item, hpriv->hook, m); 1002 ERROUT(ENOMEM); 1003 } 1004 1005 /* Add current (early) packet to the reorder queue. */ 1006 np->item = item; 1007 np->seq = seq; 1008 if (prev == NULL) 1009 SLIST_INSERT_HEAD(&hpriv->roq, np, next); 1010 else 1011 SLIST_INSERT_AFTER(prev, np, next); 1012 hpriv->roq_len++; 1013 1014 deliver: 1015 /* Look if we have some packets in sequence after sendq. */ 1016 while (!SLIST_EMPTY(&hpriv->roq)) { 1017 np = SLIST_FIRST(&hpriv->roq); 1018 if (PPTP_SEQ_DIFF(np->seq, hpriv->recvSeq) > 1) 1019 break; /* the gap in the sequence */ 1020 1021 /* "np" is in sequence, move it to the sendq. */ 1022 SLIST_REMOVE_HEAD(&hpriv->roq, next); 1023 hpriv->roq_len--; 1024 hpriv->recvSeq = np->seq; 1025 1026 if (last == NULL) 1027 SLIST_INSERT_HEAD(&sendq, np, next); 1028 else 1029 SLIST_INSERT_AFTER(last, np, next); 1030 last = np; 1031 } 1032 1033 if (SLIST_EMPTY(&hpriv->roq)) { 1034 if (callout_pending(&hpriv->reorderTimer)) 1035 ng_uncallout(&hpriv->reorderTimer, hpriv->node); 1036 } else { 1037 if (!callout_pending(&hpriv->reorderTimer)) 1038 ng_pptpgre_start_reorder_timer(hpriv); 1039 } 1040 1041 if (SLIST_EMPTY(&sendq)) { 1042 /* Current packet has been queued, nothing to free/deliver. */ 1043 mtx_unlock(&hpriv->mtx); 1044 return (error); 1045 } 1046 1047 /* We need to acknowledge last packet; do it soon... */ 1048 ng_pptpgre_ack(hpriv); /* drops lock */ 1049 ng_pptpgre_sendq(hpriv, &sendq, &temp); 1050 return (error); 1051 1052 done: 1053 NG_FREE_ITEM(item); 1054 return (error); 1055 } 1056 1057 /************************************************************************* 1058 TIMER RELATED FUNCTIONS 1059 *************************************************************************/ 1060 1061 /* 1062 * Start a timer for the peer's acknowledging our oldest unacknowledged 1063 * sequence number. If we get an ack for this sequence number before 1064 * the timer goes off, we cancel the timer. Resets currently running 1065 * recv ack timer, if any. 1066 */ 1067 static void 1068 ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv) 1069 { 1070 int remain, ticks; 1071 1072 /* Compute how long until oldest unack'd packet times out, 1073 and reset the timer to that time. */ 1074 remain = (hpriv->timeSent[0] + hpriv->ato) - ng_pptpgre_time(); 1075 if (remain < 0) 1076 remain = 0; 1077 1078 /* Be conservative: timeout can happen up to 1 tick early */ 1079 ticks = howmany(remain * hz, PPTP_TIME_SCALE) + 1; 1080 ng_callout(&hpriv->rackTimer, hpriv->node, hpriv->hook, 1081 ticks, ng_pptpgre_recv_ack_timeout, hpriv, 0); 1082 } 1083 1084 /* 1085 * The peer has failed to acknowledge the oldest unacknowledged sequence 1086 * number within the time allotted. Update our adaptive timeout parameters 1087 * and reset/restart the recv ack timer. 1088 */ 1089 static void 1090 ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) 1091 { 1092 const priv_p priv = NG_NODE_PRIVATE(node); 1093 const hpriv_p hpriv = arg1; 1094 1095 /* Update adaptive timeout stuff */ 1096 priv->stats.recvAckTimeouts++; 1097 hpriv->rtt = PPTP_ACK_DELTA(hpriv->rtt) + 1; /* +1 to avoid delta*0 case */ 1098 hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev); 1099 if (hpriv->ato > PPTP_MAX_TIMEOUT) 1100 hpriv->ato = PPTP_MAX_TIMEOUT; 1101 else if (hpriv->ato < PPTP_MIN_TIMEOUT) 1102 hpriv->ato = PPTP_MIN_TIMEOUT; 1103 1104 /* Reset ack and sliding window */ 1105 hpriv->recvAck = hpriv->xmitSeq; /* pretend we got the ack */ 1106 hpriv->xmitWin = (hpriv->xmitWin + 1) / 2; /* shrink transmit window */ 1107 hpriv->winAck = hpriv->recvAck + hpriv->xmitWin; /* reset win expand time */ 1108 } 1109 1110 /* 1111 * Start the send ack timer. This assumes the timer is not 1112 * already running. 1113 */ 1114 static void 1115 ng_pptpgre_start_send_ack_timer(hpriv_p hpriv) 1116 { 1117 int ackTimeout, ticks; 1118 1119 /* Take 1/4 of the estimated round trip time */ 1120 ackTimeout = (hpriv->rtt >> 2); 1121 if (ackTimeout < PPTP_MIN_ACK_DELAY) 1122 ackTimeout = PPTP_MIN_ACK_DELAY; 1123 else if (ackTimeout > PPTP_MAX_ACK_DELAY) 1124 ackTimeout = PPTP_MAX_ACK_DELAY; 1125 1126 /* Be conservative: timeout can happen up to 1 tick early */ 1127 ticks = howmany(ackTimeout * hz, PPTP_TIME_SCALE); 1128 ng_callout(&hpriv->sackTimer, hpriv->node, hpriv->hook, 1129 ticks, ng_pptpgre_send_ack_timeout, hpriv, 0); 1130 } 1131 1132 /* 1133 * We've waited as long as we're willing to wait before sending an 1134 * acknowledgement to the peer for received frames. We had hoped to 1135 * be able to piggy back our acknowledgement on an outgoing data frame, 1136 * but apparently there haven't been any since. So send the ack now. 1137 */ 1138 static void 1139 ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) 1140 { 1141 const hpriv_p hpriv = arg1; 1142 1143 mtx_lock(&hpriv->mtx); 1144 /* Send a frame with an ack but no payload */ 1145 ng_pptpgre_xmit(hpriv, NULL); 1146 mtx_assert(&hpriv->mtx, MA_NOTOWNED); 1147 } 1148 1149 /* 1150 * Start a timer for the reorder queue. This assumes the timer is not 1151 * already running. 1152 */ 1153 static void 1154 ng_pptpgre_start_reorder_timer(hpriv_p hpriv) 1155 { 1156 int ticks; 1157 1158 /* Be conservative: timeout can happen up to 1 tick early */ 1159 ticks = (((reorder_timeout * hz) + 1000 - 1) / 1000) + 1; 1160 ng_callout(&hpriv->reorderTimer, hpriv->node, hpriv->hook, 1161 ticks, ng_pptpgre_reorder_timeout, hpriv, 0); 1162 } 1163 1164 /* 1165 * The oldest packet spent too much time in the reorder queue. 1166 * Deliver it and next packets in sequence, if any. 1167 */ 1168 static void 1169 ng_pptpgre_reorder_timeout(node_p node, hook_p hook, void *arg1, int arg2) 1170 { 1171 const priv_p priv = NG_NODE_PRIVATE(node); 1172 const hpriv_p hpriv = arg1; 1173 roqh sendq = SLIST_HEAD_INITIALIZER(sendq); 1174 struct ng_pptpgre_roq *np, *last = NULL; 1175 1176 priv->stats.recvReorderTimeouts++; 1177 mtx_lock(&hpriv->mtx); 1178 if (SLIST_EMPTY(&hpriv->roq)) { /* should not happen */ 1179 mtx_unlock(&hpriv->mtx); 1180 return; 1181 } 1182 1183 last = np = SLIST_FIRST(&hpriv->roq); 1184 hpriv->roq_len--; 1185 SLIST_REMOVE_HEAD(&hpriv->roq, next); 1186 SLIST_INSERT_HEAD(&sendq, np, next); 1187 1188 /* Look if we have more packets in sequence */ 1189 while (!SLIST_EMPTY(&hpriv->roq)) { 1190 np = SLIST_FIRST(&hpriv->roq); 1191 if (PPTP_SEQ_DIFF(np->seq, last->seq) > 1) 1192 break; /* the gap in the sequence */ 1193 1194 /* Next packet is in sequence, move it to the sendq. */ 1195 hpriv->roq_len--; 1196 SLIST_REMOVE_HEAD(&hpriv->roq, next); 1197 SLIST_INSERT_AFTER(last, np, next); 1198 last = np; 1199 } 1200 1201 hpriv->recvSeq = last->seq; 1202 if (!SLIST_EMPTY(&hpriv->roq)) 1203 ng_pptpgre_start_reorder_timer(hpriv); 1204 1205 /* We need to acknowledge last packet; do it soon... */ 1206 ng_pptpgre_ack(hpriv); /* drops lock */ 1207 ng_pptpgre_sendq(hpriv, &sendq, NULL); 1208 mtx_assert(&hpriv->mtx, MA_NOTOWNED); 1209 } 1210 1211 /************************************************************************* 1212 MISC FUNCTIONS 1213 *************************************************************************/ 1214 1215 /* 1216 * Find the hook with a given session ID. 1217 */ 1218 static hpriv_p 1219 ng_pptpgre_find_session(priv_p privp, u_int16_t cid) 1220 { 1221 uint16_t hash = SESSHASH(cid); 1222 hpriv_p hpriv = NULL; 1223 1224 LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) { 1225 if (hpriv->conf.cid == cid) 1226 break; 1227 } 1228 1229 return (hpriv); 1230 } 1231 1232 /* 1233 * Reset state (must be called with lock held or from writer) 1234 */ 1235 static void 1236 ng_pptpgre_reset(hpriv_p hpriv) 1237 { 1238 struct ng_pptpgre_roq *np; 1239 1240 /* Reset adaptive timeout state */ 1241 hpriv->ato = PPTP_MAX_TIMEOUT; 1242 hpriv->rtt = PPTP_TIME_SCALE / 10; 1243 if (hpriv->conf.peerPpd > 1) /* ppd = 0 treat as = 1 */ 1244 hpriv->rtt *= hpriv->conf.peerPpd; 1245 hpriv->dev = 0; 1246 hpriv->xmitWin = (hpriv->conf.recvWin + 1) / 2; 1247 if (hpriv->xmitWin < 2) /* often the first packet is lost */ 1248 hpriv->xmitWin = 2; /* because the peer isn't ready */ 1249 else if (hpriv->xmitWin > PPTP_XMIT_WIN) 1250 hpriv->xmitWin = PPTP_XMIT_WIN; 1251 hpriv->winAck = hpriv->xmitWin; 1252 1253 /* Reset sequence numbers */ 1254 hpriv->recvSeq = ~0; 1255 hpriv->recvAck = ~0; 1256 hpriv->xmitSeq = ~0; 1257 hpriv->xmitAck = ~0; 1258 1259 /* Stop timers */ 1260 ng_uncallout(&hpriv->sackTimer, hpriv->node); 1261 ng_uncallout(&hpriv->rackTimer, hpriv->node); 1262 ng_uncallout(&hpriv->reorderTimer, hpriv->node); 1263 1264 /* Clear reorder queue */ 1265 while (!SLIST_EMPTY(&hpriv->roq)) { 1266 np = SLIST_FIRST(&hpriv->roq); 1267 SLIST_REMOVE_HEAD(&hpriv->roq, next); 1268 NG_FREE_ITEM(np->item); 1269 free(np, M_NETGRAPH); 1270 } 1271 hpriv->roq_len = 0; 1272 } 1273 1274 /* 1275 * Return the current time scaled & translated to our internally used format. 1276 */ 1277 static pptptime_t 1278 ng_pptpgre_time(void) 1279 { 1280 struct timeval tv; 1281 pptptime_t t; 1282 1283 microuptime(&tv); 1284 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE; 1285 t += tv.tv_usec / (1000000 / PPTP_TIME_SCALE); 1286 return(t); 1287 } 1288