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