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