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