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