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 (10 * PPTP_TIME_SCALE) /* 10 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 node_p *sackTimerPtr; /* send ack timer pointer */ 148 node_p *rackTimerPtr; /* recv ack timer pointer */ 149 u_int32_t winAck; /* seq when xmitWin will grow */ 150 pptptime_t timeSent[PPTP_XMIT_WIN]; 151 #ifdef DEBUG_RAT 152 pptptime_t timerStart; /* when rackTimer started */ 153 pptptime_t timerLength; /* rackTimer duration */ 154 #endif 155 }; 156 157 /* Node private data */ 158 struct ng_pptpgre_private { 159 hook_p upper; /* hook to upper layers */ 160 hook_p lower; /* hook to lower layers */ 161 struct ng_pptpgre_conf conf; /* configuration info */ 162 struct ng_pptpgre_ackp ackp; /* packet transmit ack state */ 163 u_int32_t recvSeq; /* last seq # we rcv'd */ 164 u_int32_t xmitSeq; /* last seq # we sent */ 165 u_int32_t recvAck; /* last seq # peer ack'd */ 166 u_int32_t xmitAck; /* last seq # we ack'd */ 167 u_int timers; /* number of pending timers */ 168 struct timeval startTime; /* time node was created */ 169 struct ng_pptpgre_stats stats; /* node statistics */ 170 }; 171 typedef struct ng_pptpgre_private *priv_p; 172 173 /* Netgraph node methods */ 174 static ng_constructor_t ng_pptpgre_constructor; 175 static ng_rcvmsg_t ng_pptpgre_rcvmsg; 176 static ng_shutdown_t ng_pptpgre_shutdown; 177 static ng_newhook_t ng_pptpgre_newhook; 178 static ng_rcvdata_t ng_pptpgre_rcvdata; 179 static ng_disconnect_t ng_pptpgre_disconnect; 180 181 /* Helper functions */ 182 static int ng_pptpgre_xmit(node_p node, item_p item); 183 static int ng_pptpgre_recv(node_p node, item_p item); 184 static void ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout); 185 static void ng_pptpgre_stop_send_ack_timer(node_p node); 186 static void ng_pptpgre_start_recv_ack_timer(node_p node); 187 static void ng_pptpgre_stop_recv_ack_timer(node_p node); 188 static void ng_pptpgre_recv_ack_timeout(void *arg); 189 static void ng_pptpgre_send_ack_timeout(void *arg); 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_info 195 ng_pptpgre_conf_type_info = 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_info, 199 }; 200 201 /* Parse type for struct ng_pptpgre_stats */ 202 static const struct ng_parse_struct_info 203 ng_pptpgre_stats_type_info = 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_info 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 NG_ABI_VERSION, 252 NG_PPTPGRE_NODE_TYPE, 253 NULL, 254 ng_pptpgre_constructor, 255 ng_pptpgre_rcvmsg, 256 ng_pptpgre_shutdown, 257 ng_pptpgre_newhook, 258 NULL, 259 NULL, 260 ng_pptpgre_rcvdata, 261 ng_pptpgre_disconnect, 262 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 callout_init(&priv->ackp.sackTimer, 0); 289 callout_init(&priv->ackp.rackTimer, 0); 290 291 /* Done */ 292 return (0); 293 } 294 295 /* 296 * Give our OK for a hook to be added. 297 */ 298 static int 299 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 300 { 301 const priv_p priv = NG_NODE_PRIVATE(node); 302 hook_p *hookPtr; 303 304 /* Check hook name */ 305 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) 306 hookPtr = &priv->upper; 307 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) 308 hookPtr = &priv->lower; 309 else 310 return (EINVAL); 311 312 /* See if already connected */ 313 if (*hookPtr != NULL) 314 return (EISCONN); 315 316 /* OK */ 317 *hookPtr = hook; 318 return (0); 319 } 320 321 /* 322 * Receive a control message. 323 */ 324 static int 325 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook) 326 { 327 const priv_p priv = NG_NODE_PRIVATE(node); 328 struct ng_mesg *resp = NULL; 329 int error = 0; 330 struct ng_mesg *msg; 331 332 NGI_GET_MSG(item, msg); 333 switch (msg->header.typecookie) { 334 case NGM_PPTPGRE_COOKIE: 335 switch (msg->header.cmd) { 336 case NGM_PPTPGRE_SET_CONFIG: 337 { 338 struct ng_pptpgre_conf *const newConf = 339 (struct ng_pptpgre_conf *) msg->data; 340 341 /* Check for invalid or illegal config */ 342 if (msg->header.arglen != sizeof(*newConf)) 343 ERROUT(EINVAL); 344 ng_pptpgre_reset(node); /* reset on configure */ 345 priv->conf = *newConf; 346 break; 347 } 348 case NGM_PPTPGRE_GET_CONFIG: 349 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT); 350 if (resp == NULL) 351 ERROUT(ENOMEM); 352 bcopy(&priv->conf, resp->data, sizeof(priv->conf)); 353 break; 354 case NGM_PPTPGRE_GET_STATS: 355 case NGM_PPTPGRE_CLR_STATS: 356 case NGM_PPTPGRE_GETCLR_STATS: 357 { 358 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) { 359 NG_MKRESPONSE(resp, msg, 360 sizeof(priv->stats), M_NOWAIT); 361 if (resp == NULL) 362 ERROUT(ENOMEM); 363 bcopy(&priv->stats, 364 resp->data, sizeof(priv->stats)); 365 } 366 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS) 367 bzero(&priv->stats, sizeof(priv->stats)); 368 break; 369 } 370 default: 371 error = EINVAL; 372 break; 373 } 374 break; 375 default: 376 error = EINVAL; 377 break; 378 } 379 done: 380 NG_RESPOND_MSG(error, node, item, resp); 381 NG_FREE_MSG(msg); 382 return (error); 383 } 384 385 /* 386 * Receive incoming data on a hook. 387 */ 388 static int 389 ng_pptpgre_rcvdata(hook_p hook, item_p item) 390 { 391 const node_p node = NG_HOOK_NODE(hook); 392 const priv_p priv = NG_NODE_PRIVATE(node); 393 394 /* If not configured, reject */ 395 if (!priv->conf.enabled) { 396 NG_FREE_ITEM(item); 397 return (ENXIO); 398 } 399 400 /* Treat as xmit or recv data */ 401 if (hook == priv->upper) 402 return ng_pptpgre_xmit(node, item); 403 if (hook == priv->lower) 404 return ng_pptpgre_recv(node, item); 405 panic("%s: weird hook", __func__); 406 } 407 408 /* 409 * Destroy node 410 */ 411 static int 412 ng_pptpgre_shutdown(node_p node) 413 { 414 const priv_p priv = NG_NODE_PRIVATE(node); 415 416 /* Reset node */ 417 ng_pptpgre_reset(node); 418 419 /* If no timers remain, free private info as well */ 420 if (priv->timers == 0) { 421 bzero(priv, sizeof(*priv)); 422 FREE(priv, M_NETGRAPH); 423 NG_NODE_SET_PRIVATE(node, NULL); 424 } 425 426 /* Decrement ref count */ 427 NG_NODE_UNREF(node); 428 return (0); 429 } 430 431 /* 432 * Hook disconnection 433 */ 434 static int 435 ng_pptpgre_disconnect(hook_p hook) 436 { 437 const node_p node = NG_HOOK_NODE(hook); 438 const priv_p priv = NG_NODE_PRIVATE(node); 439 440 /* Zero out hook pointer */ 441 if (hook == priv->upper) 442 priv->upper = NULL; 443 else if (hook == priv->lower) 444 priv->lower = NULL; 445 else 446 panic("%s: unknown hook", __func__); 447 448 /* Go away if no longer connected to anything */ 449 if ((NG_NODE_NUMHOOKS(node) == 0) 450 && (NG_NODE_IS_VALID(node))) 451 ng_rmnode_self(node); 452 return (0); 453 } 454 455 /************************************************************************* 456 TRANSMIT AND RECEIVE FUNCTIONS 457 *************************************************************************/ 458 459 /* 460 * Transmit an outgoing frame, or just an ack if m is NULL. 461 */ 462 static int 463 ng_pptpgre_xmit(node_p node, item_p item) 464 { 465 const priv_p priv = NG_NODE_PRIVATE(node); 466 struct ng_pptpgre_ackp *const a = &priv->ackp; 467 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 468 struct greheader *const gre = (struct greheader *)buf; 469 int grelen, error; 470 struct mbuf *m; 471 472 if (item) { 473 NGI_GET_M(item, m); 474 } else { 475 m = NULL; 476 } 477 /* Check if there's data */ 478 if (m != NULL) { 479 480 /* Is our transmit window full? */ 481 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck) 482 >= a->xmitWin) { 483 priv->stats.xmitDrops++; 484 NG_FREE_M(m); 485 NG_FREE_ITEM(item); 486 return (ENOBUFS); 487 } 488 489 /* Sanity check frame length */ 490 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 491 priv->stats.xmitTooBig++; 492 NG_FREE_M(m); 493 NG_FREE_ITEM(item); 494 return (EMSGSIZE); 495 } 496 } else { 497 priv->stats.xmitLoneAcks++; 498 } 499 500 /* Build GRE header */ 501 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE); 502 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 503 gre->cid = htons(priv->conf.peerCid); 504 505 /* Include sequence number if packet contains any data */ 506 if (m != NULL) { 507 gre->hasSeq = 1; 508 a->timeSent[priv->xmitSeq - priv->recvAck] 509 = ng_pptpgre_time(node); 510 priv->xmitSeq++; 511 gre->data[0] = htonl(priv->xmitSeq); 512 } 513 514 /* Include acknowledgement (and stop send ack timer) if needed */ 515 if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) { 516 gre->hasAck = 1; 517 gre->data[gre->hasSeq] = htonl(priv->recvSeq); 518 priv->xmitAck = priv->recvSeq; 519 ng_pptpgre_stop_send_ack_timer(node); 520 } 521 522 /* Prepend GRE header to outgoing frame */ 523 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 524 if (m == NULL) { 525 MGETHDR(m, M_DONTWAIT, MT_DATA); 526 if (m == NULL) { 527 priv->stats.memoryFailures++; 528 if (item) 529 NG_FREE_ITEM(item); 530 return (ENOBUFS); 531 } 532 m->m_len = m->m_pkthdr.len = grelen; 533 m->m_pkthdr.rcvif = NULL; 534 } else { 535 M_PREPEND(m, grelen, M_NOWAIT); 536 if (m == NULL || (m->m_len < grelen 537 && (m = m_pullup(m, grelen)) == NULL)) { 538 priv->stats.memoryFailures++; 539 if (item) 540 NG_FREE_ITEM(item); 541 return (ENOBUFS); 542 } 543 } 544 bcopy(gre, mtod(m, u_char *), grelen); 545 546 /* Update stats */ 547 priv->stats.xmitPackets++; 548 priv->stats.xmitOctets += m->m_pkthdr.len; 549 550 /* Deliver packet */ 551 if (item) { 552 NG_FWD_NEW_DATA(error, item, priv->lower, m); 553 } else { 554 NG_SEND_DATA_ONLY(error, priv->lower, m); 555 } 556 557 558 /* Start receive ACK timer if data was sent and not already running */ 559 if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1) 560 ng_pptpgre_start_recv_ack_timer(node); 561 return (error); 562 } 563 564 /* 565 * Handle an incoming packet. The packet includes the IP header. 566 */ 567 static int 568 ng_pptpgre_recv(node_p node, item_p item) 569 { 570 const priv_p priv = NG_NODE_PRIVATE(node); 571 int iphlen, grelen, extralen; 572 struct greheader *gre; 573 struct ip *ip; 574 int error = 0; 575 struct mbuf *m; 576 577 NGI_GET_M(item, m); 578 /* Update stats */ 579 priv->stats.recvPackets++; 580 priv->stats.recvOctets += m->m_pkthdr.len; 581 582 /* Sanity check packet length */ 583 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 584 priv->stats.recvRunts++; 585 bad: 586 NG_FREE_M(m); 587 NG_FREE_ITEM(item); 588 return (EINVAL); 589 } 590 591 /* Safely pull up the complete IP+GRE headers */ 592 if (m->m_len < sizeof(*ip) + sizeof(*gre) 593 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 594 priv->stats.memoryFailures++; 595 NG_FREE_ITEM(item); 596 return (ENOBUFS); 597 } 598 ip = mtod(m, struct ip *); 599 iphlen = ip->ip_hl << 2; 600 if (m->m_len < iphlen + sizeof(*gre)) { 601 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 602 priv->stats.memoryFailures++; 603 NG_FREE_ITEM(item); 604 return (ENOBUFS); 605 } 606 ip = mtod(m, struct ip *); 607 } 608 gre = (struct greheader *)((u_char *)ip + iphlen); 609 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 610 if (m->m_pkthdr.len < iphlen + grelen) { 611 priv->stats.recvRunts++; 612 goto bad; 613 } 614 if (m->m_len < iphlen + grelen) { 615 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 616 priv->stats.memoryFailures++; 617 NG_FREE_ITEM(item); 618 return (ENOBUFS); 619 } 620 ip = mtod(m, struct ip *); 621 gre = (struct greheader *)((u_char *)ip + iphlen); 622 } 623 624 /* Sanity check packet length and GRE header bits */ 625 extralen = m->m_pkthdr.len 626 - (iphlen + grelen + (u_int16_t)ntohs(gre->length)); 627 if (extralen < 0) { 628 priv->stats.recvBadGRE++; 629 goto bad; 630 } 631 if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) { 632 priv->stats.recvBadGRE++; 633 goto bad; 634 } 635 if (ntohs(gre->cid) != priv->conf.cid) { 636 priv->stats.recvBadCID++; 637 goto bad; 638 } 639 640 /* Look for peer ack */ 641 if (gre->hasAck) { 642 struct ng_pptpgre_ackp *const a = &priv->ackp; 643 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 644 const int index = ack - priv->recvAck - 1; 645 long sample; 646 long diff; 647 648 /* Sanity check ack value */ 649 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) { 650 priv->stats.recvBadAcks++; 651 goto badAck; /* we never sent it! */ 652 } 653 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0) 654 goto badAck; /* ack already timed out */ 655 priv->recvAck = ack; 656 657 /* Update adaptive timeout stuff */ 658 sample = ng_pptpgre_time(node) - a->timeSent[index]; 659 diff = sample - a->rtt; 660 a->rtt += PPTP_ACK_ALPHA(diff); 661 if (diff < 0) 662 diff = -diff; 663 a->dev += PPTP_ACK_BETA(diff - a->dev); 664 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 665 if (a->ato > PPTP_MAX_TIMEOUT) 666 a->ato = PPTP_MAX_TIMEOUT; 667 if (a->ato < PPTP_MIN_TIMEOUT) 668 a->ato = PPTP_MIN_TIMEOUT; 669 670 /* Shift packet transmit times in our transmit window */ 671 ovbcopy(a->timeSent + index + 1, a->timeSent, 672 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1))); 673 674 /* If we sent an entire window, increase window size by one */ 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 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->sackTimerPtr == NULL) { 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 /* Compute how long until oldest unack'd packet times out, 755 and reset the timer to that time. */ 756 KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__)); 757 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node); 758 if (remain < 0) 759 remain = 0; 760 #ifdef DEBUG_RAT 761 a->timerLength = remain; 762 a->timerStart = ng_pptpgre_time(node); 763 #endif 764 765 /* Start new timer */ 766 MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 767 if (a->rackTimerPtr == NULL) { 768 priv->stats.memoryFailures++; 769 return; /* XXX potential hang here */ 770 } 771 *a->rackTimerPtr = node; /* ensures the correct timeout event */ 772 NG_NODE_REF(node); 773 priv->timers++; 774 775 /* Be conservative: timeout can happen up to 1 tick early */ 776 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1; 777 callout_reset(&a->rackTimer, ticks, 778 ng_pptpgre_recv_ack_timeout, a->rackTimerPtr); 779 } 780 781 /* 782 * Stop receive ack timer. 783 */ 784 static void 785 ng_pptpgre_stop_recv_ack_timer(node_p node) 786 { 787 const priv_p priv = NG_NODE_PRIVATE(node); 788 struct ng_pptpgre_ackp *const a = &priv->ackp; 789 790 if (callout_stop(&a->rackTimer)) { 791 FREE(a->rackTimerPtr, M_NETGRAPH); 792 priv->timers--; 793 NG_NODE_UNREF(node); 794 } 795 a->rackTimerPtr = NULL; 796 } 797 798 /* 799 * The peer has failed to acknowledge the oldest unacknowledged sequence 800 * number within the time allotted. Update our adaptive timeout parameters 801 * and reset/restart the recv ack timer. 802 */ 803 static void 804 ng_pptpgre_recv_ack_timeout(void *arg) 805 { 806 int s = splnet(); 807 const node_p node = *((node_p *)arg); 808 const priv_p priv = NG_NODE_PRIVATE(node); 809 struct ng_pptpgre_ackp *const a = &priv->ackp; 810 811 /* This complicated stuff is needed to avoid race conditions */ 812 FREE(arg, M_NETGRAPH); 813 KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__)); 814 KASSERT(priv != NULL, ("%s: priv=NULL", __func__)); 815 priv->timers--; 816 if (NG_NODE_NOT_VALID(node)) { /* shutdown race condition */ 817 if (priv->timers == 0) { 818 FREE(priv, M_NETGRAPH); 819 NG_NODE_SET_PRIVATE(node, NULL); 820 } 821 NG_NODE_UNREF(node); 822 splx(s); 823 return; 824 } 825 if (arg != a->rackTimerPtr) { /* timer stopped race condition */ 826 NG_NODE_UNREF(node); 827 splx(s); 828 return; 829 } 830 a->rackTimerPtr = NULL; 831 832 /* Update adaptive timeout stuff */ 833 priv->stats.recvAckTimeouts++; 834 a->rtt = PPTP_ACK_DELTA(a->rtt); 835 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 836 if (a->ato > PPTP_MAX_TIMEOUT) 837 a->ato = PPTP_MAX_TIMEOUT; 838 if (a->ato < PPTP_MIN_TIMEOUT) 839 a->ato = PPTP_MIN_TIMEOUT; 840 841 #ifdef DEBUG_RAT 842 log(LOG_DEBUG, 843 "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n", 844 (int)ng_pptpgre_time(node), priv->recvAck + 1, 845 (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato); 846 #endif 847 848 /* Reset ack and sliding window */ 849 priv->recvAck = priv->xmitSeq; /* pretend we got the ack */ 850 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 851 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 852 NG_NODE_UNREF(node); 853 splx(s); 854 } 855 856 /* 857 * Start the send ack timer. This assumes the timer is not 858 * already running. 859 */ 860 static void 861 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout) 862 { 863 const priv_p priv = NG_NODE_PRIVATE(node); 864 struct ng_pptpgre_ackp *const a = &priv->ackp; 865 int ticks; 866 867 /* Start new timer */ 868 KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__)); 869 MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 870 if (a->sackTimerPtr == NULL) { 871 priv->stats.memoryFailures++; 872 return; /* XXX potential hang here */ 873 } 874 *a->sackTimerPtr = node; /* ensures the correct timeout event */ 875 NG_NODE_REF(node); 876 priv->timers++; 877 878 /* Be conservative: timeout can happen up to 1 tick early */ 879 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE); 880 callout_reset(&a->sackTimer, ticks, 881 ng_pptpgre_send_ack_timeout, a->sackTimerPtr); 882 } 883 884 /* 885 * Stop send ack timer. 886 */ 887 static void 888 ng_pptpgre_stop_send_ack_timer(node_p node) 889 { 890 const priv_p priv = NG_NODE_PRIVATE(node); 891 struct ng_pptpgre_ackp *const a = &priv->ackp; 892 893 if (callout_stop(&a->sackTimer)) { 894 FREE(a->sackTimerPtr, M_NETGRAPH); 895 priv->timers--; 896 NG_NODE_UNREF(node); 897 } 898 a->sackTimerPtr = NULL; 899 } 900 901 /* 902 * We've waited as long as we're willing to wait before sending an 903 * acknowledgement to the peer for received frames. We had hoped to 904 * be able to piggy back our acknowledgement on an outgoing data frame, 905 * but apparently there haven't been any since. So send the ack now. 906 */ 907 static void 908 ng_pptpgre_send_ack_timeout(void *arg) 909 { 910 int s = splnet(); 911 const node_p node = *((node_p *)arg); 912 const priv_p priv = NG_NODE_PRIVATE(node); 913 struct ng_pptpgre_ackp *const a = &priv->ackp; 914 915 /* This complicated stuff is needed to avoid race conditions */ 916 FREE(arg, M_NETGRAPH); 917 KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__)); 918 KASSERT(priv != NULL, ("%s: priv=NULL", __func__)); 919 priv->timers--; 920 if (NG_NODE_NOT_VALID(node)) { /* shutdown race condition */ 921 if (priv->timers == 0) { 922 FREE(priv, M_NETGRAPH); 923 NG_NODE_SET_PRIVATE(node, NULL); 924 } 925 NG_NODE_UNREF(node); 926 splx(s); 927 return; 928 } 929 if (a->sackTimerPtr != arg) { /* timer stopped race condition */ 930 NG_NODE_UNREF(node); 931 splx(s); 932 return; 933 } 934 a->sackTimerPtr = NULL; 935 936 /* Send a frame with an ack but no payload */ 937 ng_pptpgre_xmit(node, NULL); 938 NG_NODE_UNREF(node); 939 splx(s); 940 } 941 942 /************************************************************************* 943 MISC FUNCTIONS 944 *************************************************************************/ 945 946 /* 947 * Reset state 948 */ 949 static void 950 ng_pptpgre_reset(node_p node) 951 { 952 const priv_p priv = NG_NODE_PRIVATE(node); 953 struct ng_pptpgre_ackp *const a = &priv->ackp; 954 955 /* Reset adaptive timeout state */ 956 a->ato = PPTP_MAX_TIMEOUT; 957 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 958 if (a->rtt < PPTP_MIN_RTT) 959 a->rtt = PPTP_MIN_RTT; 960 a->dev = 0; 961 a->xmitWin = (priv->conf.recvWin + 1) / 2; 962 if (a->xmitWin < 2) /* often the first packet is lost */ 963 a->xmitWin = 2; /* because the peer isn't ready */ 964 if (a->xmitWin > PPTP_XMIT_WIN) 965 a->xmitWin = PPTP_XMIT_WIN; 966 a->winAck = a->xmitWin; 967 968 /* Reset sequence numbers */ 969 priv->recvSeq = ~0; 970 priv->recvAck = ~0; 971 priv->xmitSeq = ~0; 972 priv->xmitAck = ~0; 973 974 /* Reset start time */ 975 getmicrouptime(&priv->startTime); 976 977 /* Reset stats */ 978 bzero(&priv->stats, sizeof(priv->stats)); 979 980 /* Stop timers */ 981 ng_pptpgre_stop_send_ack_timer(node); 982 ng_pptpgre_stop_recv_ack_timer(node); 983 } 984 985 /* 986 * Return the current time scaled & translated to our internally used format. 987 */ 988 static pptptime_t 989 ng_pptpgre_time(node_p node) 990 { 991 const priv_p priv = NG_NODE_PRIVATE(node); 992 struct timeval tv; 993 pptptime_t t; 994 995 microuptime(&tv); 996 if (tv.tv_sec < priv->startTime.tv_sec 997 || (tv.tv_sec == priv->startTime.tv_sec 998 && tv.tv_usec < priv->startTime.tv_usec)) 999 return (0); 1000 timevalsub(&tv, &priv->startTime); 1001 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE; 1002 t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE); 1003 return(t); 1004 } 1005 1006