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 (1 * PPTP_TIME_SCALE) /* 1 second */ 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_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 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 /* Check if windowing is enabled */ 481 if (priv->conf.enableWindowing) { 482 /* Is our transmit window full? */ 483 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, 484 priv->recvAck) >= a->xmitWin) { 485 priv->stats.xmitDrops++; 486 NG_FREE_M(m); 487 NG_FREE_ITEM(item); 488 return (ENOBUFS); 489 } 490 } 491 492 /* Sanity check frame length */ 493 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 494 priv->stats.xmitTooBig++; 495 NG_FREE_M(m); 496 NG_FREE_ITEM(item); 497 return (EMSGSIZE); 498 } 499 } else { 500 priv->stats.xmitLoneAcks++; 501 } 502 503 /* Build GRE header */ 504 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE); 505 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 506 gre->cid = htons(priv->conf.peerCid); 507 508 /* Include sequence number if packet contains any data */ 509 if (m != NULL) { 510 gre->hasSeq = 1; 511 if (priv->conf.enableWindowing) { 512 a->timeSent[priv->xmitSeq - priv->recvAck] 513 = ng_pptpgre_time(node); 514 } 515 priv->xmitSeq++; 516 gre->data[0] = htonl(priv->xmitSeq); 517 } 518 519 /* Include acknowledgement (and stop send ack timer) if needed */ 520 if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) { 521 gre->hasAck = 1; 522 gre->data[gre->hasSeq] = htonl(priv->recvSeq); 523 priv->xmitAck = priv->recvSeq; 524 ng_pptpgre_stop_send_ack_timer(node); 525 } 526 527 /* Prepend GRE header to outgoing frame */ 528 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 529 if (m == NULL) { 530 MGETHDR(m, M_DONTWAIT, MT_DATA); 531 if (m == NULL) { 532 priv->stats.memoryFailures++; 533 if (item) 534 NG_FREE_ITEM(item); 535 return (ENOBUFS); 536 } 537 m->m_len = m->m_pkthdr.len = grelen; 538 m->m_pkthdr.rcvif = NULL; 539 } else { 540 M_PREPEND(m, grelen, M_DONTWAIT); 541 if (m == NULL || (m->m_len < grelen 542 && (m = m_pullup(m, grelen)) == NULL)) { 543 priv->stats.memoryFailures++; 544 if (item) 545 NG_FREE_ITEM(item); 546 return (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 /* Deliver packet */ 556 if (item) { 557 NG_FWD_NEW_DATA(error, item, priv->lower, m); 558 } else { 559 NG_SEND_DATA_ONLY(error, priv->lower, m); 560 } 561 562 563 /* Start receive ACK timer if data was sent and not already running */ 564 if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1) 565 ng_pptpgre_start_recv_ack_timer(node); 566 return (error); 567 } 568 569 /* 570 * Handle an incoming packet. The packet includes the IP header. 571 */ 572 static int 573 ng_pptpgre_recv(node_p node, item_p item) 574 { 575 const priv_p priv = NG_NODE_PRIVATE(node); 576 int iphlen, grelen, extralen; 577 const struct greheader *gre; 578 const struct ip *ip; 579 int error = 0; 580 struct mbuf *m; 581 582 NGI_GET_M(item, m); 583 /* Update stats */ 584 priv->stats.recvPackets++; 585 priv->stats.recvOctets += m->m_pkthdr.len; 586 587 /* Sanity check packet length */ 588 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 589 priv->stats.recvRunts++; 590 bad: 591 NG_FREE_M(m); 592 NG_FREE_ITEM(item); 593 return (EINVAL); 594 } 595 596 /* Safely pull up the complete IP+GRE headers */ 597 if (m->m_len < sizeof(*ip) + sizeof(*gre) 598 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 599 priv->stats.memoryFailures++; 600 NG_FREE_ITEM(item); 601 return (ENOBUFS); 602 } 603 ip = mtod(m, const struct ip *); 604 iphlen = ip->ip_hl << 2; 605 if (m->m_len < iphlen + sizeof(*gre)) { 606 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 607 priv->stats.memoryFailures++; 608 NG_FREE_ITEM(item); 609 return (ENOBUFS); 610 } 611 ip = mtod(m, const struct ip *); 612 } 613 gre = (const struct greheader *)((const u_char *)ip + iphlen); 614 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 615 if (m->m_pkthdr.len < iphlen + grelen) { 616 priv->stats.recvRunts++; 617 goto bad; 618 } 619 if (m->m_len < iphlen + grelen) { 620 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 621 priv->stats.memoryFailures++; 622 NG_FREE_ITEM(item); 623 return (ENOBUFS); 624 } 625 ip = mtod(m, const struct ip *); 626 gre = (const struct greheader *)((const u_char *)ip + iphlen); 627 } 628 629 /* Sanity check packet length and GRE header bits */ 630 extralen = m->m_pkthdr.len 631 - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length)); 632 if (extralen < 0) { 633 priv->stats.recvBadGRE++; 634 goto bad; 635 } 636 if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK) 637 != PPTP_INIT_VALUE) { 638 priv->stats.recvBadGRE++; 639 goto bad; 640 } 641 if (ntohs(gre->cid) != priv->conf.cid) { 642 priv->stats.recvBadCID++; 643 goto bad; 644 } 645 646 /* Look for peer ack */ 647 if (gre->hasAck) { 648 struct ng_pptpgre_ackp *const a = &priv->ackp; 649 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 650 const int index = ack - priv->recvAck - 1; 651 long sample; 652 long diff; 653 654 /* Sanity check ack value */ 655 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) { 656 priv->stats.recvBadAcks++; 657 goto badAck; /* we never sent it! */ 658 } 659 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0) 660 goto badAck; /* ack already timed out */ 661 priv->recvAck = ack; 662 663 /* Update adaptive timeout stuff */ 664 if (priv->conf.enableWindowing) { 665 sample = ng_pptpgre_time(node) - a->timeSent[index]; 666 diff = sample - a->rtt; 667 a->rtt += PPTP_ACK_ALPHA(diff); 668 if (diff < 0) 669 diff = -diff; 670 a->dev += PPTP_ACK_BETA(diff - a->dev); 671 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 672 if (a->ato > PPTP_MAX_TIMEOUT) 673 a->ato = PPTP_MAX_TIMEOUT; 674 if (a->ato < PPTP_MIN_TIMEOUT) 675 a->ato = PPTP_MIN_TIMEOUT; 676 677 /* Shift packet transmit times in our transmit window */ 678 bcopy(a->timeSent + index + 1, a->timeSent, 679 sizeof(*a->timeSent) 680 * (PPTP_XMIT_WIN - (index + 1))); 681 682 /* If we sent an entire window, increase window size */ 683 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0 684 && a->xmitWin < PPTP_XMIT_WIN) { 685 a->xmitWin++; 686 a->winAck = ack + a->xmitWin; 687 } 688 689 /* Stop/(re)start receive ACK timer as necessary */ 690 ng_pptpgre_stop_recv_ack_timer(node); 691 if (priv->recvAck != priv->xmitSeq) 692 ng_pptpgre_start_recv_ack_timer(node); 693 } 694 } 695 badAck: 696 697 /* See if frame contains any data */ 698 if (gre->hasSeq) { 699 struct ng_pptpgre_ackp *const a = &priv->ackp; 700 const u_int32_t seq = ntohl(gre->data[0]); 701 702 /* Sanity check sequence number */ 703 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) { 704 if (seq == priv->recvSeq) 705 priv->stats.recvDuplicates++; 706 else 707 priv->stats.recvOutOfOrder++; 708 goto bad; /* out-of-order or dup */ 709 } 710 priv->recvSeq = seq; 711 712 /* We need to acknowledge this packet; do it soon... */ 713 if (a->sackTimerPtr == NULL) { 714 int maxWait; 715 716 /* Take 1/4 of the estimated round trip time */ 717 maxWait = (a->rtt >> 2); 718 719 /* If delayed ACK is disabled, send it now */ 720 if (!priv->conf.enableDelayedAck) /* ack now */ 721 ng_pptpgre_xmit(node, NULL); 722 else { /* ack later */ 723 if (maxWait < PPTP_MIN_ACK_DELAY) 724 maxWait = PPTP_MIN_ACK_DELAY; 725 if (maxWait > PPTP_MAX_ACK_DELAY) 726 maxWait = PPTP_MAX_ACK_DELAY; 727 ng_pptpgre_start_send_ack_timer(node, maxWait); 728 } 729 } 730 731 /* Trim mbuf down to internal payload */ 732 m_adj(m, iphlen + grelen); 733 if (extralen > 0) 734 m_adj(m, -extralen); 735 736 /* Deliver frame to upper layers */ 737 NG_FWD_NEW_DATA(error, item, priv->upper, m); 738 } else { 739 priv->stats.recvLoneAcks++; 740 NG_FREE_ITEM(item); 741 NG_FREE_M(m); /* no data to deliver */ 742 } 743 return (error); 744 } 745 746 /************************************************************************* 747 TIMER RELATED FUNCTIONS 748 *************************************************************************/ 749 750 /* 751 * Start a timer for the peer's acknowledging our oldest unacknowledged 752 * sequence number. If we get an ack for this sequence number before 753 * the timer goes off, we cancel the timer. Resets currently running 754 * recv ack timer, if any. 755 */ 756 static void 757 ng_pptpgre_start_recv_ack_timer(node_p node) 758 { 759 const priv_p priv = NG_NODE_PRIVATE(node); 760 struct ng_pptpgre_ackp *const a = &priv->ackp; 761 int remain, ticks; 762 763 if (!priv->conf.enableWindowing) 764 return; 765 766 /* Compute how long until oldest unack'd packet times out, 767 and reset the timer to that time. */ 768 KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__)); 769 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node); 770 if (remain < 0) 771 remain = 0; 772 #ifdef DEBUG_RAT 773 a->timerLength = remain; 774 a->timerStart = ng_pptpgre_time(node); 775 #endif 776 777 /* Start new timer */ 778 MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 779 if (a->rackTimerPtr == NULL) { 780 priv->stats.memoryFailures++; 781 return; /* XXX potential hang here */ 782 } 783 *a->rackTimerPtr = node; /* ensures the correct timeout event */ 784 NG_NODE_REF(node); 785 priv->timers++; 786 787 /* Be conservative: timeout can happen up to 1 tick early */ 788 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1; 789 callout_reset(&a->rackTimer, ticks, 790 ng_pptpgre_recv_ack_timeout, a->rackTimerPtr); 791 } 792 793 /* 794 * Stop receive ack timer. 795 */ 796 static void 797 ng_pptpgre_stop_recv_ack_timer(node_p node) 798 { 799 const priv_p priv = NG_NODE_PRIVATE(node); 800 struct ng_pptpgre_ackp *const a = &priv->ackp; 801 802 if (!priv->conf.enableWindowing) 803 return; 804 805 if (callout_stop(&a->rackTimer)) { 806 FREE(a->rackTimerPtr, M_NETGRAPH); 807 priv->timers--; 808 NG_NODE_UNREF(node); 809 } 810 a->rackTimerPtr = NULL; 811 } 812 813 /* 814 * The peer has failed to acknowledge the oldest unacknowledged sequence 815 * number within the time allotted. Update our adaptive timeout parameters 816 * and reset/restart the recv ack timer. 817 */ 818 static void 819 ng_pptpgre_recv_ack_timeout(void *arg) 820 { 821 int s = splnet(); 822 const node_p node = *((node_p *)arg); 823 const priv_p priv = NG_NODE_PRIVATE(node); 824 struct ng_pptpgre_ackp *const a = &priv->ackp; 825 826 /* This complicated stuff is needed to avoid race conditions */ 827 FREE(arg, M_NETGRAPH); 828 KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__)); 829 KASSERT(priv != NULL, ("%s: priv=NULL", __func__)); 830 priv->timers--; 831 if (NG_NODE_NOT_VALID(node)) { /* shutdown race condition */ 832 if (priv->timers == 0) { 833 FREE(priv, M_NETGRAPH); 834 NG_NODE_SET_PRIVATE(node, NULL); 835 } 836 NG_NODE_UNREF(node); 837 splx(s); 838 return; 839 } 840 if (arg != a->rackTimerPtr) { /* timer stopped race condition */ 841 NG_NODE_UNREF(node); 842 splx(s); 843 return; 844 } 845 a->rackTimerPtr = NULL; 846 847 /* Update adaptive timeout stuff */ 848 priv->stats.recvAckTimeouts++; 849 a->rtt = PPTP_ACK_DELTA(a->rtt); 850 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 851 if (a->ato > PPTP_MAX_TIMEOUT) 852 a->ato = PPTP_MAX_TIMEOUT; 853 if (a->ato < PPTP_MIN_TIMEOUT) 854 a->ato = PPTP_MIN_TIMEOUT; 855 856 #ifdef DEBUG_RAT 857 log(LOG_DEBUG, 858 "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n", 859 (int)ng_pptpgre_time(node), priv->recvAck + 1, 860 (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato); 861 #endif 862 863 /* Reset ack and sliding window */ 864 priv->recvAck = priv->xmitSeq; /* pretend we got the ack */ 865 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 866 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 867 NG_NODE_UNREF(node); 868 splx(s); 869 } 870 871 /* 872 * Start the send ack timer. This assumes the timer is not 873 * already running. 874 */ 875 static void 876 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout) 877 { 878 const priv_p priv = NG_NODE_PRIVATE(node); 879 struct ng_pptpgre_ackp *const a = &priv->ackp; 880 int ticks; 881 882 /* Start new timer */ 883 KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__)); 884 MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 885 if (a->sackTimerPtr == NULL) { 886 priv->stats.memoryFailures++; 887 return; /* XXX potential hang here */ 888 } 889 *a->sackTimerPtr = node; /* ensures the correct timeout event */ 890 NG_NODE_REF(node); 891 priv->timers++; 892 893 /* Be conservative: timeout can happen up to 1 tick early */ 894 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE); 895 callout_reset(&a->sackTimer, ticks, 896 ng_pptpgre_send_ack_timeout, a->sackTimerPtr); 897 } 898 899 /* 900 * Stop send ack timer. 901 */ 902 static void 903 ng_pptpgre_stop_send_ack_timer(node_p node) 904 { 905 const priv_p priv = NG_NODE_PRIVATE(node); 906 struct ng_pptpgre_ackp *const a = &priv->ackp; 907 908 if (callout_stop(&a->sackTimer)) { 909 FREE(a->sackTimerPtr, M_NETGRAPH); 910 priv->timers--; 911 NG_NODE_UNREF(node); 912 } 913 a->sackTimerPtr = NULL; 914 } 915 916 /* 917 * We've waited as long as we're willing to wait before sending an 918 * acknowledgement to the peer for received frames. We had hoped to 919 * be able to piggy back our acknowledgement on an outgoing data frame, 920 * but apparently there haven't been any since. So send the ack now. 921 */ 922 static void 923 ng_pptpgre_send_ack_timeout(void *arg) 924 { 925 int s = splnet(); 926 const node_p node = *((node_p *)arg); 927 const priv_p priv = NG_NODE_PRIVATE(node); 928 struct ng_pptpgre_ackp *const a = &priv->ackp; 929 930 /* This complicated stuff is needed to avoid race conditions */ 931 FREE(arg, M_NETGRAPH); 932 KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__)); 933 KASSERT(priv != NULL, ("%s: priv=NULL", __func__)); 934 priv->timers--; 935 if (NG_NODE_NOT_VALID(node)) { /* shutdown race condition */ 936 if (priv->timers == 0) { 937 FREE(priv, M_NETGRAPH); 938 NG_NODE_SET_PRIVATE(node, NULL); 939 } 940 NG_NODE_UNREF(node); 941 splx(s); 942 return; 943 } 944 if (a->sackTimerPtr != arg) { /* timer stopped race condition */ 945 NG_NODE_UNREF(node); 946 splx(s); 947 return; 948 } 949 a->sackTimerPtr = NULL; 950 951 /* Send a frame with an ack but no payload */ 952 ng_pptpgre_xmit(node, NULL); 953 NG_NODE_UNREF(node); 954 splx(s); 955 } 956 957 /************************************************************************* 958 MISC FUNCTIONS 959 *************************************************************************/ 960 961 /* 962 * Reset state 963 */ 964 static void 965 ng_pptpgre_reset(node_p node) 966 { 967 const priv_p priv = NG_NODE_PRIVATE(node); 968 struct ng_pptpgre_ackp *const a = &priv->ackp; 969 970 /* Reset adaptive timeout state */ 971 a->ato = PPTP_MAX_TIMEOUT; 972 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 973 if (a->rtt < PPTP_MIN_RTT) 974 a->rtt = PPTP_MIN_RTT; 975 a->dev = 0; 976 a->xmitWin = (priv->conf.recvWin + 1) / 2; 977 if (a->xmitWin < 2) /* often the first packet is lost */ 978 a->xmitWin = 2; /* because the peer isn't ready */ 979 if (a->xmitWin > PPTP_XMIT_WIN) 980 a->xmitWin = PPTP_XMIT_WIN; 981 a->winAck = a->xmitWin; 982 983 /* Reset sequence numbers */ 984 priv->recvSeq = ~0; 985 priv->recvAck = ~0; 986 priv->xmitSeq = ~0; 987 priv->xmitAck = ~0; 988 989 /* Reset start time */ 990 getmicrouptime(&priv->startTime); 991 992 /* Reset stats */ 993 bzero(&priv->stats, sizeof(priv->stats)); 994 995 /* Stop timers */ 996 ng_pptpgre_stop_send_ack_timer(node); 997 ng_pptpgre_stop_recv_ack_timer(node); 998 } 999 1000 /* 1001 * Return the current time scaled & translated to our internally used format. 1002 */ 1003 static pptptime_t 1004 ng_pptpgre_time(node_p node) 1005 { 1006 const priv_p priv = NG_NODE_PRIVATE(node); 1007 struct timeval tv; 1008 pptptime_t t; 1009 1010 microuptime(&tv); 1011 if (tv.tv_sec < priv->startTime.tv_sec 1012 || (tv.tv_sec == priv->startTime.tv_sec 1013 && tv.tv_usec < priv->startTime.tv_usec)) 1014 return (0); 1015 timevalsub(&tv, &priv->startTime); 1016 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE; 1017 t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE); 1018 return(t); 1019 } 1020 1021