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