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: src/sys/netgraph/ng_pptpgre.c,v 1.42 2008/03/26 21:19:03 mav Exp $ 41 * $DragonFly: src/sys/netgraph7/ng_pptpgre.c,v 1.2 2008/06/26 23:05:35 dillon Exp $ 42 * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $ 43 */ 44 45 /* 46 * PPTP/GRE netgraph node type. 47 * 48 * This node type does the GRE encapsulation as specified for the PPTP 49 * protocol (RFC 2637, section 4). This includes sequencing and 50 * retransmission of frames, but not the actual packet delivery nor 51 * any of the TCP control stream protocol. 52 * 53 * The "upper" hook of this node is suitable for attaching to a "ppp" 54 * node link hook. The "lower" hook of this node is suitable for attaching 55 * to a "ksocket" node on hook "inet/raw/gre". 56 */ 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/kernel.h> 61 #include <sys/time.h> 62 #include <sys/lock.h> 63 #include <sys/malloc.h> 64 #include <sys/mbuf.h> 65 #include <sys/errno.h> 66 67 #include <netinet/in.h> 68 #include <netinet/in_systm.h> 69 #include <netinet/ip.h> 70 71 #include <netgraph7/ng_message.h> 72 #include <netgraph7/netgraph.h> 73 #include <netgraph7/ng_parse.h> 74 #include "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 /* When we recieve a packet, we wait to see if there's an outgoing packet 127 we can piggy-back the ACK off of. These parameters determine the mimimum 128 and maxmimum length of time we're willing to wait in order to do that. 129 These have no effect unless "enableDelayedAck" is turned on. */ 130 #define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500) /* 2 milliseconds */ 131 #define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2) /* 500 milliseconds */ 132 133 /* See RFC 2637 section 4.4 */ 134 #define PPTP_ACK_ALPHA(x) (((x) + 4) >> 3) /* alpha = 0.125 */ 135 #define PPTP_ACK_BETA(x) (((x) + 2) >> 2) /* beta = 0.25 */ 136 #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 137 #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 138 139 #define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y)) 140 141 #define SESSHASHSIZE 0x0020 142 #define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1)) 143 144 /* We keep packet retransmit and acknowlegement state in this struct */ 145 struct ng_pptpgre_sess { 146 node_p node; /* this node pointer */ 147 hook_p hook; /* hook to upper layers */ 148 struct ng_pptpgre_conf conf; /* configuration info */ 149 struct mtx mtx; /* session mutex */ 150 u_int32_t recvSeq; /* last seq # we rcv'd */ 151 u_int32_t xmitSeq; /* last seq # we sent */ 152 u_int32_t recvAck; /* last seq # peer ack'd */ 153 u_int32_t xmitAck; /* last seq # we ack'd */ 154 int32_t ato; /* adaptive time-out value */ 155 int32_t rtt; /* round trip time estimate */ 156 int32_t dev; /* deviation estimate */ 157 u_int16_t xmitWin; /* size of xmit window */ 158 struct callout sackTimer; /* send ack timer */ 159 struct callout rackTimer; /* recv ack timer */ 160 u_int32_t winAck; /* seq when xmitWin will grow */ 161 pptptime_t timeSent[PPTP_XMIT_WIN]; 162 LIST_ENTRY(ng_pptpgre_sess) sessions; 163 }; 164 typedef struct ng_pptpgre_sess *hpriv_p; 165 166 /* Node private data */ 167 struct ng_pptpgre_private { 168 hook_p upper; /* hook to upper layers */ 169 hook_p lower; /* hook to lower layers */ 170 struct ng_pptpgre_sess uppersess; /* default session for compat */ 171 LIST_HEAD(, ng_pptpgre_sess) sesshash[SESSHASHSIZE]; 172 struct ng_pptpgre_stats stats; /* node statistics */ 173 }; 174 typedef struct ng_pptpgre_private *priv_p; 175 176 /* Netgraph node methods */ 177 static ng_constructor_t ng_pptpgre_constructor; 178 static ng_rcvmsg_t ng_pptpgre_rcvmsg; 179 static ng_shutdown_t ng_pptpgre_shutdown; 180 static ng_newhook_t ng_pptpgre_newhook; 181 static ng_rcvdata_t ng_pptpgre_rcvdata; 182 static ng_rcvdata_t ng_pptpgre_rcvdata_lower; 183 static ng_disconnect_t ng_pptpgre_disconnect; 184 185 /* Helper functions */ 186 static int ng_pptpgre_xmit(hpriv_p hpriv, item_p item); 187 static void ng_pptpgre_start_send_ack_timer(hpriv_p hpriv); 188 static void ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv); 189 static void ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, 190 void *arg1, int arg2); 191 static void ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, 192 void *arg1, int arg2); 193 static hpriv_p ng_pptpgre_find_session(priv_p privp, u_int16_t cid); 194 static void ng_pptpgre_reset(hpriv_p hpriv); 195 static pptptime_t ng_pptpgre_time(void); 196 197 /* Parse type for struct ng_pptpgre_conf */ 198 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[] 199 = NG_PPTPGRE_CONF_TYPE_INFO; 200 static const struct ng_parse_type ng_pptpgre_conf_type = { 201 &ng_parse_struct_type, 202 &ng_pptpgre_conf_type_fields, 203 }; 204 205 /* Parse type for struct ng_pptpgre_stats */ 206 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[] 207 = NG_PPTPGRE_STATS_TYPE_INFO; 208 static const struct ng_parse_type ng_pptp_stats_type = { 209 &ng_parse_struct_type, 210 &ng_pptpgre_stats_type_fields 211 }; 212 213 /* List of commands and how to convert arguments to/from ASCII */ 214 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 215 { 216 NGM_PPTPGRE_COOKIE, 217 NGM_PPTPGRE_SET_CONFIG, 218 "setconfig", 219 &ng_pptpgre_conf_type, 220 NULL 221 }, 222 { 223 NGM_PPTPGRE_COOKIE, 224 NGM_PPTPGRE_GET_CONFIG, 225 "getconfig", 226 &ng_parse_hint16_type, 227 &ng_pptpgre_conf_type 228 }, 229 { 230 NGM_PPTPGRE_COOKIE, 231 NGM_PPTPGRE_GET_STATS, 232 "getstats", 233 NULL, 234 &ng_pptp_stats_type 235 }, 236 { 237 NGM_PPTPGRE_COOKIE, 238 NGM_PPTPGRE_CLR_STATS, 239 "clrstats", 240 NULL, 241 NULL 242 }, 243 { 244 NGM_PPTPGRE_COOKIE, 245 NGM_PPTPGRE_GETCLR_STATS, 246 "getclrstats", 247 NULL, 248 &ng_pptp_stats_type 249 }, 250 { 0 } 251 }; 252 253 /* Node type descriptor */ 254 static struct ng_type ng_pptpgre_typestruct = { 255 .version = NG_ABI_VERSION, 256 .name = NG_PPTPGRE_NODE_TYPE, 257 .constructor = ng_pptpgre_constructor, 258 .rcvmsg = ng_pptpgre_rcvmsg, 259 .shutdown = ng_pptpgre_shutdown, 260 .newhook = ng_pptpgre_newhook, 261 .rcvdata = ng_pptpgre_rcvdata, 262 .disconnect = ng_pptpgre_disconnect, 263 .cmdlist = ng_pptpgre_cmdlist, 264 }; 265 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 266 267 #define ERROUT(x) do { error = (x); goto done; } while (0) 268 269 /************************************************************************ 270 NETGRAPH NODE STUFF 271 ************************************************************************/ 272 273 /* 274 * Node type constructor 275 */ 276 static int 277 ng_pptpgre_constructor(node_p node) 278 { 279 priv_p priv; 280 int i; 281 282 /* Allocate private structure */ 283 priv = kmalloc(sizeof(*priv), M_NETGRAPH, 284 M_WAITOK | M_NULLOK | M_ZERO); 285 if (priv == NULL) 286 return (ENOMEM); 287 288 NG_NODE_SET_PRIVATE(node, priv); 289 290 /* Initialize state */ 291 mtx_init(&priv->uppersess.mtx); 292 ng_callout_init(&priv->uppersess.sackTimer); 293 ng_callout_init(&priv->uppersess.rackTimer); 294 priv->uppersess.node = node; 295 296 for (i = 0; i < SESSHASHSIZE; i++) 297 LIST_INIT(&priv->sesshash[i]); 298 299 LIST_INSERT_HEAD(&priv->sesshash[0], &priv->uppersess, sessions); 300 301 /* Done */ 302 return (0); 303 } 304 305 /* 306 * Give our OK for a hook to be added. 307 */ 308 static int 309 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 310 { 311 const priv_p priv = NG_NODE_PRIVATE(node); 312 313 /* Check hook name */ 314 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) { 315 priv->upper = hook; 316 priv->uppersess.hook = hook; 317 NG_HOOK_SET_PRIVATE(hook, &priv->uppersess); 318 } else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) { 319 priv->lower = hook; 320 NG_HOOK_SET_RCVDATA(hook, ng_pptpgre_rcvdata_lower); 321 } else { 322 static const char hexdig[16] = "0123456789abcdef"; 323 const char *hex; 324 hpriv_p hpriv; 325 int i, j; 326 uint16_t cid, hash; 327 328 /* Parse hook name to get session ID */ 329 if (strncmp(name, NG_PPTPGRE_HOOK_SESSION_P, 330 sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1) != 0) 331 return (EINVAL); 332 hex = name + sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1; 333 for (cid = i = 0; i < 4; i++) { 334 for (j = 0; j < 16 && hex[i] != hexdig[j]; j++); 335 if (j == 16) 336 return (EINVAL); 337 cid = (cid << 4) | j; 338 } 339 if (hex[i] != '\0') 340 return (EINVAL); 341 342 hpriv = kmalloc(sizeof(*hpriv), M_NETGRAPH, M_WAITOK | M_NULLOK | M_ZERO); 343 if (hpriv == NULL) 344 return (ENOMEM); 345 346 /* Initialize state */ 347 mtx_init(&hpriv->mtx); 348 ng_callout_init(&hpriv->sackTimer); 349 ng_callout_init(&hpriv->rackTimer); 350 hpriv->conf.cid = cid; 351 hpriv->node = node; 352 hpriv->hook = hook; 353 NG_HOOK_SET_PRIVATE(hook, hpriv); 354 355 hash = SESSHASH(cid); 356 LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions); 357 } 358 359 return (0); 360 } 361 362 /* 363 * Receive a control message. 364 */ 365 static int 366 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook) 367 { 368 const priv_p priv = NG_NODE_PRIVATE(node); 369 struct ng_mesg *resp = NULL; 370 int error = 0; 371 struct ng_mesg *msg; 372 373 NGI_GET_MSG(item, msg); 374 switch (msg->header.typecookie) { 375 case NGM_PPTPGRE_COOKIE: 376 switch (msg->header.cmd) { 377 case NGM_PPTPGRE_SET_CONFIG: 378 { 379 struct ng_pptpgre_conf *const newConf = 380 (struct ng_pptpgre_conf *) msg->data; 381 hpriv_p hpriv; 382 uint16_t hash; 383 384 /* Check for invalid or illegal config */ 385 if (msg->header.arglen != sizeof(*newConf)) 386 ERROUT(EINVAL); 387 /* Try to find session by cid. */ 388 hpriv = ng_pptpgre_find_session(priv, newConf->cid); 389 /* If not present - use upper. */ 390 if (hpriv == NULL) { 391 hpriv = &priv->uppersess; 392 LIST_REMOVE(hpriv, sessions); 393 hash = SESSHASH(newConf->cid); 394 LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, 395 sessions); 396 } 397 ng_pptpgre_reset(hpriv); /* reset on configure */ 398 hpriv->conf = *newConf; 399 break; 400 } 401 case NGM_PPTPGRE_GET_CONFIG: 402 { 403 hpriv_p hpriv; 404 405 if (msg->header.arglen == 2) { 406 /* Try to find session by cid. */ 407 hpriv = ng_pptpgre_find_session(priv, 408 *((uint16_t *)msg->data)); 409 if (hpriv == NULL) 410 ERROUT(EINVAL); 411 } else if (msg->header.arglen == 0) { 412 /* Use upper. */ 413 hpriv = &priv->uppersess; 414 } else 415 ERROUT(EINVAL); 416 NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_WAITOK | M_NULLOK); 417 if (resp == NULL) 418 ERROUT(ENOMEM); 419 bcopy(&hpriv->conf, resp->data, sizeof(hpriv->conf)); 420 break; 421 } 422 case NGM_PPTPGRE_GET_STATS: 423 case NGM_PPTPGRE_CLR_STATS: 424 case NGM_PPTPGRE_GETCLR_STATS: 425 { 426 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) { 427 NG_MKRESPONSE(resp, msg, 428 sizeof(priv->stats), M_WAITOK | M_NULLOK); 429 if (resp == NULL) 430 ERROUT(ENOMEM); 431 bcopy(&priv->stats, 432 resp->data, sizeof(priv->stats)); 433 } 434 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS) 435 bzero(&priv->stats, sizeof(priv->stats)); 436 break; 437 } 438 default: 439 error = EINVAL; 440 break; 441 } 442 break; 443 default: 444 error = EINVAL; 445 break; 446 } 447 done: 448 NG_RESPOND_MSG(error, node, item, resp); 449 NG_FREE_MSG(msg); 450 return (error); 451 } 452 453 /* 454 * Receive incoming data on a hook. 455 */ 456 static int 457 ng_pptpgre_rcvdata(hook_p hook, item_p item) 458 { 459 const hpriv_p hpriv = NG_HOOK_PRIVATE(hook); 460 int rval; 461 462 /* If not configured, reject */ 463 if (!hpriv->conf.enabled) { 464 NG_FREE_ITEM(item); 465 return (ENXIO); 466 } 467 468 mtx_lock(&hpriv->mtx); 469 470 rval = ng_pptpgre_xmit(hpriv, item); 471 472 KKASSERT(mtx_notowned(&hpriv->mtx)); 473 474 return (rval); 475 } 476 477 /* 478 * Hook disconnection 479 */ 480 static int 481 ng_pptpgre_disconnect(hook_p hook) 482 { 483 const node_p node = NG_HOOK_NODE(hook); 484 const priv_p priv = NG_NODE_PRIVATE(node); 485 const hpriv_p hpriv = NG_HOOK_PRIVATE(hook); 486 487 /* Zero out hook pointer */ 488 if (hook == priv->upper) { 489 priv->upper = NULL; 490 priv->uppersess.hook = NULL; 491 } else if (hook == priv->lower) { 492 priv->lower = NULL; 493 } else { 494 /* Reset node (stops timers) */ 495 ng_pptpgre_reset(hpriv); 496 497 LIST_REMOVE(hpriv, sessions); 498 mtx_uninit(&hpriv->mtx); 499 kfree(hpriv, M_NETGRAPH); 500 } 501 502 /* Go away if no longer connected to anything */ 503 if ((NG_NODE_NUMHOOKS(node) == 0) 504 && (NG_NODE_IS_VALID(node))) 505 ng_rmnode_self(node); 506 return (0); 507 } 508 509 /* 510 * Destroy node 511 */ 512 static int 513 ng_pptpgre_shutdown(node_p node) 514 { 515 const priv_p priv = NG_NODE_PRIVATE(node); 516 517 /* Reset node (stops timers) */ 518 ng_pptpgre_reset(&priv->uppersess); 519 520 LIST_REMOVE(&priv->uppersess, sessions); 521 mtx_uninit(&priv->uppersess.mtx); 522 523 kfree(priv, M_NETGRAPH); 524 525 /* Decrement ref count */ 526 NG_NODE_UNREF(node); 527 return (0); 528 } 529 530 /************************************************************************* 531 TRANSMIT AND RECEIVE FUNCTIONS 532 *************************************************************************/ 533 534 /* 535 * Transmit an outgoing frame, or just an ack if m is NULL. 536 */ 537 static int 538 ng_pptpgre_xmit(hpriv_p hpriv, item_p item) 539 { 540 const priv_p priv = NG_NODE_PRIVATE(hpriv->node); 541 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 542 struct greheader *const gre = (struct greheader *)buf; 543 int grelen, error; 544 struct mbuf *m; 545 546 KKASSERT(mtx_owned(&hpriv->mtx)); 547 548 if (item) { 549 NGI_GET_M(item, m); 550 } else { 551 m = NULL; 552 } 553 /* Check if there's data */ 554 if (m != NULL) { 555 556 /* Check if windowing is enabled */ 557 if (hpriv->conf.enableWindowing) { 558 /* Is our transmit window full? */ 559 if ((u_int32_t)PPTP_SEQ_DIFF(hpriv->xmitSeq, 560 hpriv->recvAck) >= hpriv->xmitWin) { 561 priv->stats.xmitDrops++; 562 ERROUT(ENOBUFS); 563 } 564 } 565 566 /* Sanity check frame length */ 567 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 568 priv->stats.xmitTooBig++; 569 ERROUT(EMSGSIZE); 570 } 571 } else { 572 priv->stats.xmitLoneAcks++; 573 } 574 575 /* Build GRE header */ 576 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE); 577 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 578 gre->cid = htons(hpriv->conf.peerCid); 579 580 /* Include sequence number if packet contains any data */ 581 if (m != NULL) { 582 gre->hasSeq = 1; 583 if (hpriv->conf.enableWindowing) { 584 hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck] 585 = ng_pptpgre_time(); 586 } 587 hpriv->xmitSeq++; 588 gre->data[0] = htonl(hpriv->xmitSeq); 589 } 590 591 /* Include acknowledgement (and stop send ack timer) if needed */ 592 if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) { 593 gre->hasAck = 1; 594 gre->data[gre->hasSeq] = htonl(hpriv->recvSeq); 595 hpriv->xmitAck = hpriv->recvSeq; 596 if (hpriv->conf.enableDelayedAck) 597 ng_uncallout(&hpriv->sackTimer, hpriv->node); 598 } 599 600 /* Prepend GRE header to outgoing frame */ 601 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 602 if (m == NULL) { 603 MGETHDR(m, MB_DONTWAIT, MT_DATA); 604 if (m == NULL) { 605 priv->stats.memoryFailures++; 606 ERROUT(ENOBUFS); 607 } 608 m->m_len = m->m_pkthdr.len = grelen; 609 m->m_pkthdr.rcvif = NULL; 610 } else { 611 M_PREPEND(m, grelen, MB_DONTWAIT); 612 if (m == NULL || (m->m_len < grelen 613 && (m = m_pullup(m, grelen)) == NULL)) { 614 priv->stats.memoryFailures++; 615 ERROUT(ENOBUFS); 616 } 617 } 618 bcopy(gre, mtod(m, u_char *), grelen); 619 620 /* Update stats */ 621 priv->stats.xmitPackets++; 622 priv->stats.xmitOctets += m->m_pkthdr.len; 623 624 /* 625 * XXX: we should reset timer only after an item has been sent 626 * successfully. 627 */ 628 if (hpriv->conf.enableWindowing && 629 gre->hasSeq && hpriv->xmitSeq == hpriv->recvAck + 1) 630 ng_pptpgre_start_recv_ack_timer(hpriv); 631 632 mtx_unlock(&hpriv->mtx); 633 634 /* Deliver packet */ 635 if (item) { 636 NG_FWD_NEW_DATA(error, item, priv->lower, m); 637 } else { 638 NG_SEND_DATA_ONLY(error, priv->lower, m); 639 } 640 641 return (error); 642 643 done: 644 mtx_unlock(&hpriv->mtx); 645 NG_FREE_M(m); 646 if (item) 647 NG_FREE_ITEM(item); 648 return (error); 649 } 650 651 /* 652 * Handle an incoming packet. The packet includes the IP header. 653 */ 654 static int 655 ng_pptpgre_rcvdata_lower(hook_p hook, item_p item) 656 { 657 hpriv_p hpriv; 658 node_p node = NG_HOOK_NODE(hook); 659 const priv_p priv = NG_NODE_PRIVATE(node); 660 int iphlen, grelen, extralen; 661 const struct greheader *gre; 662 const struct ip *ip; 663 int error = 0; 664 struct mbuf *m; 665 666 NGI_GET_M(item, m); 667 /* Update stats */ 668 priv->stats.recvPackets++; 669 priv->stats.recvOctets += m->m_pkthdr.len; 670 671 /* Sanity check packet length */ 672 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 673 priv->stats.recvRunts++; 674 ERROUT(EINVAL); 675 } 676 677 /* Safely pull up the complete IP+GRE headers */ 678 if (m->m_len < sizeof(*ip) + sizeof(*gre) 679 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 680 priv->stats.memoryFailures++; 681 ERROUT(ENOBUFS); 682 } 683 ip = mtod(m, const struct ip *); 684 iphlen = ip->ip_hl << 2; 685 if (m->m_len < iphlen + sizeof(*gre)) { 686 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 687 priv->stats.memoryFailures++; 688 ERROUT(ENOBUFS); 689 } 690 ip = mtod(m, const struct ip *); 691 } 692 gre = (const struct greheader *)((const u_char *)ip + iphlen); 693 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 694 if (m->m_pkthdr.len < iphlen + grelen) { 695 priv->stats.recvRunts++; 696 ERROUT(EINVAL); 697 } 698 if (m->m_len < iphlen + grelen) { 699 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 700 priv->stats.memoryFailures++; 701 ERROUT(ENOBUFS); 702 } 703 ip = mtod(m, const struct ip *); 704 gre = (const struct greheader *)((const u_char *)ip + iphlen); 705 } 706 707 /* Sanity check packet length and GRE header bits */ 708 extralen = m->m_pkthdr.len 709 - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length)); 710 if (extralen < 0) { 711 priv->stats.recvBadGRE++; 712 ERROUT(EINVAL); 713 } 714 if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK) 715 != PPTP_INIT_VALUE) { 716 priv->stats.recvBadGRE++; 717 ERROUT(EINVAL); 718 } 719 720 hpriv = ng_pptpgre_find_session(priv, ntohs(gre->cid)); 721 if (hpriv == NULL || hpriv->hook == NULL || !hpriv->conf.enabled) { 722 priv->stats.recvBadCID++; 723 ERROUT(EINVAL); 724 } 725 mtx_lock(&hpriv->mtx); 726 727 /* Look for peer ack */ 728 if (gre->hasAck) { 729 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 730 const int index = ack - hpriv->recvAck - 1; 731 long sample; 732 long diff; 733 734 /* Sanity check ack value */ 735 if (PPTP_SEQ_DIFF(ack, hpriv->xmitSeq) > 0) { 736 priv->stats.recvBadAcks++; 737 goto badAck; /* we never sent it! */ 738 } 739 if (PPTP_SEQ_DIFF(ack, hpriv->recvAck) <= 0) 740 goto badAck; /* ack already timed out */ 741 hpriv->recvAck = ack; 742 743 /* Update adaptive timeout stuff */ 744 if (hpriv->conf.enableWindowing) { 745 sample = ng_pptpgre_time() - hpriv->timeSent[index]; 746 diff = sample - hpriv->rtt; 747 hpriv->rtt += PPTP_ACK_ALPHA(diff); 748 if (diff < 0) 749 diff = -diff; 750 hpriv->dev += PPTP_ACK_BETA(diff - hpriv->dev); 751 /* +2 to compensate low precision of int math */ 752 hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev + 2); 753 if (hpriv->ato > PPTP_MAX_TIMEOUT) 754 hpriv->ato = PPTP_MAX_TIMEOUT; 755 else if (hpriv->ato < PPTP_MIN_TIMEOUT) 756 hpriv->ato = PPTP_MIN_TIMEOUT; 757 758 /* Shift packet transmit times in our transmit window */ 759 bcopy(hpriv->timeSent + index + 1, hpriv->timeSent, 760 sizeof(*hpriv->timeSent) 761 * (PPTP_XMIT_WIN - (index + 1))); 762 763 /* If we sent an entire window, increase window size */ 764 if (PPTP_SEQ_DIFF(ack, hpriv->winAck) >= 0 765 && hpriv->xmitWin < PPTP_XMIT_WIN) { 766 hpriv->xmitWin++; 767 hpriv->winAck = ack + hpriv->xmitWin; 768 } 769 770 /* Stop/(re)start receive ACK timer as necessary */ 771 ng_uncallout(&hpriv->rackTimer, hpriv->node); 772 if (hpriv->recvAck != hpriv->xmitSeq) 773 ng_pptpgre_start_recv_ack_timer(hpriv); 774 } 775 } 776 badAck: 777 778 /* See if frame contains any data */ 779 if (gre->hasSeq) { 780 const u_int32_t seq = ntohl(gre->data[0]); 781 782 /* Sanity check sequence number */ 783 if (PPTP_SEQ_DIFF(seq, hpriv->recvSeq) <= 0) { 784 if (seq == hpriv->recvSeq) 785 priv->stats.recvDuplicates++; 786 else 787 priv->stats.recvOutOfOrder++; 788 mtx_unlock(&hpriv->mtx); 789 ERROUT(EINVAL); 790 } 791 hpriv->recvSeq = seq; 792 793 /* We need to acknowledge this packet; do it soon... */ 794 if (!(callout_pending(&hpriv->sackTimer))) { 795 /* If delayed ACK is disabled, send it now */ 796 if (!hpriv->conf.enableDelayedAck) { /* ack now */ 797 ng_pptpgre_xmit(hpriv, NULL); 798 /* ng_pptpgre_xmit() drops the mutex */ 799 } else { /* ack later */ 800 ng_pptpgre_start_send_ack_timer(hpriv); 801 mtx_unlock(&hpriv->mtx); 802 } 803 } else 804 mtx_unlock(&hpriv->mtx); 805 806 /* Trim mbuf down to internal payload */ 807 m_adj(m, iphlen + grelen); 808 if (extralen > 0) 809 m_adj(m, -extralen); 810 811 KKASSERT(mtx_notowned(&hpriv->mtx)); 812 813 /* Deliver frame to upper layers */ 814 NG_FWD_NEW_DATA(error, item, hpriv->hook, m); 815 } else { 816 priv->stats.recvLoneAcks++; 817 mtx_unlock(&hpriv->mtx); 818 NG_FREE_ITEM(item); 819 NG_FREE_M(m); /* no data to deliver */ 820 } 821 822 return (error); 823 824 done: 825 NG_FREE_ITEM(item); 826 NG_FREE_M(m); 827 return (error); 828 } 829 830 /************************************************************************* 831 TIMER RELATED FUNCTIONS 832 *************************************************************************/ 833 834 /* 835 * Start a timer for the peer's acknowledging our oldest unacknowledged 836 * sequence number. If we get an ack for this sequence number before 837 * the timer goes off, we cancel the timer. Resets currently running 838 * recv ack timer, if any. 839 */ 840 static void 841 ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv) 842 { 843 int remain, ticks; 844 845 /* Compute how long until oldest unack'd packet times out, 846 and reset the timer to that time. */ 847 remain = (hpriv->timeSent[0] + hpriv->ato) - ng_pptpgre_time(); 848 if (remain < 0) 849 remain = 0; 850 851 /* Be conservative: timeout can happen up to 1 tick early */ 852 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1; 853 ng_callout(&hpriv->rackTimer, hpriv->node, hpriv->hook, 854 ticks, ng_pptpgre_recv_ack_timeout, hpriv, 0); 855 } 856 857 /* 858 * The peer has failed to acknowledge the oldest unacknowledged sequence 859 * number within the time allotted. Update our adaptive timeout parameters 860 * and reset/restart the recv ack timer. 861 */ 862 static void 863 ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) 864 { 865 const priv_p priv = NG_NODE_PRIVATE(node); 866 const hpriv_p hpriv = arg1; 867 868 /* Update adaptive timeout stuff */ 869 priv->stats.recvAckTimeouts++; 870 hpriv->rtt = PPTP_ACK_DELTA(hpriv->rtt) + 1; /* +1 to avoid delta*0 case */ 871 hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev); 872 if (hpriv->ato > PPTP_MAX_TIMEOUT) 873 hpriv->ato = PPTP_MAX_TIMEOUT; 874 else if (hpriv->ato < PPTP_MIN_TIMEOUT) 875 hpriv->ato = PPTP_MIN_TIMEOUT; 876 877 /* Reset ack and sliding window */ 878 hpriv->recvAck = hpriv->xmitSeq; /* pretend we got the ack */ 879 hpriv->xmitWin = (hpriv->xmitWin + 1) / 2; /* shrink transmit window */ 880 hpriv->winAck = hpriv->recvAck + hpriv->xmitWin; /* reset win expand time */ 881 } 882 883 /* 884 * Start the send ack timer. This assumes the timer is not 885 * already running. 886 */ 887 static void 888 ng_pptpgre_start_send_ack_timer(hpriv_p hpriv) 889 { 890 int ackTimeout, ticks; 891 892 /* Take 1/4 of the estimated round trip time */ 893 ackTimeout = (hpriv->rtt >> 2); 894 if (ackTimeout < PPTP_MIN_ACK_DELAY) 895 ackTimeout = PPTP_MIN_ACK_DELAY; 896 else if (ackTimeout > PPTP_MAX_ACK_DELAY) 897 ackTimeout = PPTP_MAX_ACK_DELAY; 898 899 /* Be conservative: timeout can happen up to 1 tick early */ 900 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE); 901 ng_callout(&hpriv->sackTimer, hpriv->node, hpriv->hook, 902 ticks, ng_pptpgre_send_ack_timeout, hpriv, 0); 903 } 904 905 /* 906 * We've waited as long as we're willing to wait before sending an 907 * acknowledgement to the peer for received frames. We had hoped to 908 * be able to piggy back our acknowledgement on an outgoing data frame, 909 * but apparently there haven't been any since. So send the ack now. 910 */ 911 static void 912 ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) 913 { 914 const hpriv_p hpriv = arg1; 915 916 mtx_lock(&hpriv->mtx); 917 /* Send a frame with an ack but no payload */ 918 ng_pptpgre_xmit(hpriv, NULL); 919 KKASSERT(mtx_notowned(&hpriv->mtx)); 920 } 921 922 /************************************************************************* 923 MISC FUNCTIONS 924 *************************************************************************/ 925 926 /* 927 * Find the hook with a given session ID. 928 */ 929 static hpriv_p 930 ng_pptpgre_find_session(priv_p privp, u_int16_t cid) 931 { 932 uint16_t hash = SESSHASH(cid); 933 hpriv_p hpriv = NULL; 934 935 LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) { 936 if (hpriv->conf.cid == cid) 937 break; 938 } 939 940 return (hpriv); 941 } 942 943 /* 944 * Reset state (must be called with lock held or from writer) 945 */ 946 static void 947 ng_pptpgre_reset(hpriv_p hpriv) 948 { 949 /* Reset adaptive timeout state */ 950 hpriv->ato = PPTP_MAX_TIMEOUT; 951 hpriv->rtt = PPTP_TIME_SCALE / 10; 952 if (hpriv->conf.peerPpd > 1) /* ppd = 0 treat as = 1 */ 953 hpriv->rtt *= hpriv->conf.peerPpd; 954 hpriv->dev = 0; 955 hpriv->xmitWin = (hpriv->conf.recvWin + 1) / 2; 956 if (hpriv->xmitWin < 2) /* often the first packet is lost */ 957 hpriv->xmitWin = 2; /* because the peer isn't ready */ 958 else if (hpriv->xmitWin > PPTP_XMIT_WIN) 959 hpriv->xmitWin = PPTP_XMIT_WIN; 960 hpriv->winAck = hpriv->xmitWin; 961 962 /* Reset sequence numbers */ 963 hpriv->recvSeq = ~0; 964 hpriv->recvAck = ~0; 965 hpriv->xmitSeq = ~0; 966 hpriv->xmitAck = ~0; 967 968 /* Stop timers */ 969 ng_uncallout(&hpriv->sackTimer, hpriv->node); 970 ng_uncallout(&hpriv->rackTimer, hpriv->node); 971 } 972 973 /* 974 * Return the current time scaled & translated to our internally used format. 975 */ 976 static pptptime_t 977 ng_pptpgre_time(void) 978 { 979 struct timeval tv; 980 pptptime_t t; 981 982 microuptime(&tv); 983 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE; 984 t += tv.tv_usec / (1000000 / PPTP_TIME_SCALE); 985 return(t); 986 } 987