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