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