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@whistle.com> 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/conf.h> 61 #include <sys/mbuf.h> 62 #include <sys/malloc.h> 63 #include <sys/errno.h> 64 #include <sys/socket.h> 65 #include <sys/syslog.h> 66 #include <sys/ctype.h> 67 68 #include <netinet/in.h> 69 #include <netinet/in_systm.h> 70 #include <netinet/ip.h> 71 72 #include <netgraph/ng_message.h> 73 #include <netgraph/netgraph.h> 74 #include <netgraph/ng_parse.h> 75 #include <netgraph/ng_pptpgre.h> 76 77 /* GRE packet format, as used by PPTP */ 78 struct greheader { 79 #if BYTE_ORDER == LITTLE_ENDIAN 80 u_char recursion:3; /* recursion control */ 81 u_char ssr:1; /* strict source route */ 82 u_char hasSeq:1; /* sequence number present */ 83 u_char hasKey:1; /* key present */ 84 u_char hasRoute:1; /* routing present */ 85 u_char hasSum:1; /* checksum present */ 86 u_char vers:3; /* version */ 87 u_char flags:4; /* flags */ 88 u_char hasAck:1; /* acknowlege number present */ 89 #elif BYTE_ORDER == BIG_ENDIAN 90 u_char hasSum:1; /* checksum present */ 91 u_char hasRoute:1; /* routing present */ 92 u_char hasKey:1; /* key present */ 93 u_char hasSeq:1; /* sequence number present */ 94 u_char ssr:1; /* strict source route */ 95 u_char recursion:3; /* recursion control */ 96 u_char hasAck:1; /* acknowlege number present */ 97 u_char flags:4; /* flags */ 98 u_char vers:3; /* version */ 99 #else 100 #error BYTE_ORDER is not defined properly 101 #endif 102 u_int16_t proto; /* protocol (ethertype) */ 103 u_int16_t length; /* payload length */ 104 u_int16_t cid; /* call id */ 105 u_int32_t data[0]; /* opt. seq, ack, then data */ 106 }; 107 108 /* The PPTP protocol ID used in the GRE 'proto' field */ 109 #define PPTP_GRE_PROTO 0x880b 110 111 /* Bits that must be set a certain way in all PPTP/GRE packets */ 112 #define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO) 113 #define PPTP_INIT_MASK 0xef7fffff 114 115 /* Min and max packet length */ 116 #define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8) 117 118 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */ 119 #define PPTP_TIME_SCALE 1000 120 typedef u_int32_t pptptime_t; 121 122 /* Acknowledgment timeout parameters and functions */ 123 #define PPTP_XMIT_WIN 8 /* max xmit window */ 124 #define PPTP_MIN_RTT (PPTP_TIME_SCALE / 10) /* 1/10 second */ 125 #define PPTP_MAX_TIMEOUT (10 * PPTP_TIME_SCALE) /* 10 seconds */ 126 127 #define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */ 128 #define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */ 129 #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 130 #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 131 132 /* We keep packet retransmit and acknowlegement state in this struct */ 133 struct ng_pptpgre_ackp { 134 int32_t ato; /* adaptive time-out value */ 135 int32_t rtt; /* round trip time estimate */ 136 int32_t dev; /* deviation estimate */ 137 u_int16_t xmitWin; /* size of xmit window */ 138 u_char sackTimerRunning;/* send ack timer is running */ 139 u_int32_t winAck; /* seq when xmitWin will grow */ 140 struct callout_handle sackTimer; /* send ack timer */ 141 struct callout_handle rackTimer; /* recv ack timer */ 142 pptptime_t timeSent[PPTP_XMIT_WIN]; 143 }; 144 145 /* When we recieve a packet, we wait to see if there's an outgoing packet 146 we can piggy-back the ACK off of. These parameters determine the mimimum 147 and maxmimum length of time we're willing to wait in order to do that. */ 148 #define PPTP_MAX_ACK_DELAY ((int) (0.25 * PPTP_TIME_SCALE)) 149 150 /* Node private data */ 151 struct ng_pptpgre_private { 152 hook_p upper; /* hook to upper layers */ 153 hook_p lower; /* hook to lower layers */ 154 struct ng_pptpgre_conf conf; /* configuration info */ 155 struct ng_pptpgre_ackp ackp; /* packet transmit ack state */ 156 u_int32_t recvSeq; /* last seq # we rcv'd */ 157 u_int32_t xmitSeq; /* last seq # we sent */ 158 u_int32_t recvAck; /* last seq # peer ack'd */ 159 u_int32_t xmitAck; /* last seq # we ack'd */ 160 struct timeval startTime; /* time node was created */ 161 }; 162 typedef struct ng_pptpgre_private *priv_p; 163 164 /* Netgraph node methods */ 165 static ng_constructor_t ng_pptpgre_constructor; 166 static ng_rcvmsg_t ng_pptpgre_rcvmsg; 167 static ng_shutdown_t ng_pptpgre_rmnode; 168 static ng_newhook_t ng_pptpgre_newhook; 169 static ng_rcvdata_t ng_pptpgre_rcvdata; 170 static ng_disconnect_t ng_pptpgre_disconnect; 171 172 /* Helper functions */ 173 static int ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta); 174 static int ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta); 175 static void ng_pptpgre_start_recv_ack_timer(node_p node); 176 static void ng_pptpgre_recv_ack_timeout(void *arg); 177 static void ng_pptpgre_send_ack_timeout(void *arg); 178 static void ng_pptpgre_reset(node_p node); 179 static pptptime_t ng_pptpgre_time(node_p node); 180 181 /* Parse type for struct ng_pptpgre_conf */ 182 static const struct ng_parse_struct_info 183 ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO; 184 static const struct ng_parse_type ng_pptpgre_conf_type = { 185 &ng_parse_struct_type, 186 &ng_pptpgre_conf_type_info, 187 }; 188 189 /* List of commands and how to convert arguments to/from ASCII */ 190 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 191 { 192 NGM_PPTPGRE_COOKIE, 193 NGM_PPTPGRE_SET_CONFIG, 194 "setconfig", 195 &ng_pptpgre_conf_type, 196 NULL 197 }, 198 { 199 NGM_PPTPGRE_COOKIE, 200 NGM_PPTPGRE_GET_CONFIG, 201 "getconfig", 202 NULL, 203 &ng_pptpgre_conf_type 204 }, 205 { 0 } 206 }; 207 208 /* Node type descriptor */ 209 static struct ng_type ng_pptpgre_typestruct = { 210 NG_VERSION, 211 NG_PPTPGRE_NODE_TYPE, 212 NULL, 213 ng_pptpgre_constructor, 214 ng_pptpgre_rcvmsg, 215 ng_pptpgre_rmnode, 216 ng_pptpgre_newhook, 217 NULL, 218 NULL, 219 ng_pptpgre_rcvdata, 220 ng_pptpgre_rcvdata, 221 ng_pptpgre_disconnect, 222 ng_pptpgre_cmdlist 223 }; 224 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 225 226 #define ERROUT(x) do { error = (x); goto done; } while (0) 227 228 /************************************************************************ 229 NETGRAPH NODE STUFF 230 ************************************************************************/ 231 232 /* 233 * Node type constructor 234 */ 235 static int 236 ng_pptpgre_constructor(node_p *nodep) 237 { 238 priv_p priv; 239 int error; 240 241 /* Allocate private structure */ 242 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 243 if (priv == NULL) 244 return (ENOMEM); 245 bzero(priv, sizeof(*priv)); 246 247 /* Call generic node constructor */ 248 if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) { 249 FREE(priv, M_NETGRAPH); 250 return (error); 251 } 252 (*nodep)->private = priv; 253 254 /* Initialize state */ 255 callout_handle_init(&priv->ackp.sackTimer); 256 callout_handle_init(&priv->ackp.rackTimer); 257 258 /* Done */ 259 return (0); 260 } 261 262 /* 263 * Give our OK for a hook to be added. 264 */ 265 static int 266 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 267 { 268 const priv_p priv = node->private; 269 hook_p *hookPtr; 270 271 /* Check hook name */ 272 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) 273 hookPtr = &priv->upper; 274 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) 275 hookPtr = &priv->lower; 276 else 277 return (EINVAL); 278 279 /* See if already connected */ 280 if (*hookPtr != NULL) 281 return (EISCONN); 282 283 /* OK */ 284 *hookPtr = hook; 285 return (0); 286 } 287 288 /* 289 * Receive a control message. 290 */ 291 static int 292 ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg, 293 const char *raddr, struct ng_mesg **rptr) 294 { 295 const priv_p priv = node->private; 296 struct ng_mesg *resp = NULL; 297 int error = 0; 298 299 switch (msg->header.typecookie) { 300 case NGM_PPTPGRE_COOKIE: 301 switch (msg->header.cmd) { 302 case NGM_PPTPGRE_SET_CONFIG: 303 { 304 struct ng_pptpgre_conf *const newConf = 305 (struct ng_pptpgre_conf *) msg->data; 306 307 /* Check for invalid or illegal config */ 308 if (msg->header.arglen != sizeof(*newConf)) 309 ERROUT(EINVAL); 310 ng_pptpgre_reset(node); /* reset on configure */ 311 priv->conf = *newConf; 312 break; 313 } 314 case NGM_PPTPGRE_GET_CONFIG: 315 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT); 316 if (resp == NULL) 317 ERROUT(ENOMEM); 318 bcopy(&priv->conf, resp->data, sizeof(priv->conf)); 319 break; 320 default: 321 error = EINVAL; 322 break; 323 } 324 break; 325 default: 326 error = EINVAL; 327 break; 328 } 329 if (rptr) 330 *rptr = resp; 331 else if (resp) 332 FREE(resp, M_NETGRAPH); 333 334 done: 335 FREE(msg, M_NETGRAPH); 336 return (error); 337 } 338 339 /* 340 * Receive incoming data on a hook. 341 */ 342 static int 343 ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 344 { 345 const node_p node = hook->node; 346 const priv_p priv = node->private; 347 348 /* If not configured, reject */ 349 if (!priv->conf.enabled) { 350 NG_FREE_DATA(m, meta); 351 return (ENXIO); 352 } 353 354 /* Treat as xmit or recv data */ 355 if (hook == priv->upper) 356 return ng_pptpgre_xmit(node, m, meta); 357 if (hook == priv->lower) 358 return ng_pptpgre_recv(node, m, meta); 359 panic("%s: weird hook", __FUNCTION__); 360 } 361 362 /* 363 * Destroy node 364 */ 365 static int 366 ng_pptpgre_rmnode(node_p node) 367 { 368 const priv_p priv = node->private; 369 370 /* Cancel timers */ 371 ng_pptpgre_reset(node); 372 373 /* Take down netgraph node */ 374 node->flags |= NG_INVALID; 375 ng_cutlinks(node); 376 ng_unname(node); 377 bzero(priv, sizeof(*priv)); 378 FREE(priv, M_NETGRAPH); 379 node->private = NULL; 380 ng_unref(node); 381 return (0); 382 } 383 384 /* 385 * Hook disconnection 386 */ 387 static int 388 ng_pptpgre_disconnect(hook_p hook) 389 { 390 const node_p node = hook->node; 391 const priv_p priv = node->private; 392 393 /* Zero out hook pointer */ 394 if (hook == priv->upper) 395 priv->upper = NULL; 396 else if (hook == priv->lower) 397 priv->lower = NULL; 398 else 399 panic("%s: unknown hook", __FUNCTION__); 400 401 /* Go away if no longer connected to anything */ 402 if (node->numhooks == 0) 403 ng_rmnode(node); 404 return (0); 405 } 406 407 /************************************************************************* 408 TRANSMIT AND RECEIVE FUNCTIONS 409 *************************************************************************/ 410 411 /* 412 * Transmit an outgoing frame, or just an ack if m is NULL. 413 */ 414 static int 415 ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta) 416 { 417 const priv_p priv = node->private; 418 struct ng_pptpgre_ackp *const a = &priv->ackp; 419 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 420 struct greheader *const gre = (struct greheader *)buf; 421 int grelen, error; 422 423 /* Is our transmit window full? */ 424 if (m != NULL && priv->xmitSeq - priv->recvAck >= a->xmitWin) { 425 NG_FREE_DATA(m, meta); 426 return (ENOBUFS); 427 } 428 429 /* Sanity check frame length */ 430 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 431 NG_FREE_DATA(m, meta); 432 return (EMSGSIZE); 433 } 434 435 /* Build GRE header */ 436 ((u_int32_t *) gre)[0] = htonl(PPTP_INIT_VALUE); 437 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 438 gre->cid = htons(priv->conf.peerCid); 439 440 /* Include sequence number if packet contains any data */ 441 if (m != NULL) { 442 gre->hasSeq = 1; 443 a->timeSent[priv->xmitSeq - priv->recvAck] 444 = ng_pptpgre_time(node); 445 priv->xmitSeq++; 446 gre->data[0] = htonl(priv->xmitSeq); 447 if (priv->xmitSeq == priv->recvAck + 1) 448 ng_pptpgre_start_recv_ack_timer(node); 449 } 450 451 /* Include acknowledgement (and stop send ack timer) if needed */ 452 if (priv->xmitAck < priv->recvSeq) { 453 gre->hasAck = 1; 454 priv->xmitAck = priv->recvSeq; 455 gre->data[gre->hasSeq] = htonl(priv->xmitAck); 456 if (a->sackTimerRunning) { 457 untimeout(ng_pptpgre_send_ack_timeout, 458 node, a->sackTimer); 459 a->sackTimerRunning = 0; 460 } 461 } 462 463 /* Prepend GRE header to outgoing frame */ 464 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 465 if (m == NULL) { 466 MGETHDR(m, M_DONTWAIT, MT_DATA); 467 if (m == NULL) { 468 NG_FREE_META(meta); 469 return (ENOBUFS); 470 } 471 m->m_len = m->m_pkthdr.len = grelen; 472 m->m_pkthdr.rcvif = NULL; 473 } else { 474 M_PREPEND(m, grelen, M_NOWAIT); 475 if (m == NULL || (m->m_len < grelen 476 && (m = m_pullup(m, grelen)) == NULL)) { 477 NG_FREE_META(meta); 478 return (ENOBUFS); 479 } 480 } 481 bcopy(gre, mtod(m, u_char *), grelen); 482 483 /* Deliver packet */ 484 NG_SEND_DATA(error, priv->lower, m, meta); 485 return (error); 486 } 487 488 /* 489 * Handle an incoming packet. The packet includes the IP header. 490 */ 491 static int 492 ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta) 493 { 494 const priv_p priv = node->private; 495 int iphlen, grelen, extralen; 496 struct greheader *gre; 497 struct ip *ip; 498 int error = 0; 499 500 /* Sanity check packet length */ 501 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 502 bad: 503 NG_FREE_DATA(m, meta); 504 return (EINVAL); 505 } 506 507 /* Safely pull up the complete IP+GRE headers */ 508 if (m->m_len < sizeof(*ip) + sizeof(*gre) 509 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 510 NG_FREE_META(meta); 511 return (ENOBUFS); 512 } 513 ip = mtod(m, struct ip *); 514 iphlen = ip->ip_hl << 2; 515 if (m->m_len < iphlen + sizeof(*gre)) { 516 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 517 NG_FREE_META(meta); 518 return (ENOBUFS); 519 } 520 ip = mtod(m, struct ip *); 521 } 522 gre = (struct greheader *)((u_char *)ip + iphlen); 523 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 524 if (m->m_pkthdr.len < iphlen + grelen) 525 goto bad; 526 if (m->m_len < iphlen + grelen) { 527 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 528 NG_FREE_META(meta); 529 return (ENOBUFS); 530 } 531 ip = mtod(m, struct ip *); 532 gre = (struct greheader *)((u_char *)ip + iphlen); 533 } 534 535 /* Sanity check packet length and GRE header bits */ 536 extralen = m->m_pkthdr.len 537 - (iphlen + grelen + (u_int16_t)ntohs(gre->length)); 538 if (extralen < 0) 539 goto bad; 540 if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) 541 goto bad; 542 if (ntohs(gre->cid) != priv->conf.cid) 543 goto bad; 544 545 /* Look for peer ack */ 546 if (gre->hasAck) { 547 struct ng_pptpgre_ackp *const a = &priv->ackp; 548 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 549 const int index = ack - priv->recvAck - 1; 550 const long sample = ng_pptpgre_time(node) - a->timeSent[index]; 551 long diff; 552 553 /* Sanity check ack value */ 554 if (ack <= priv->recvAck) /* ack already timed out */ 555 goto bad; 556 if (ack > priv->xmitSeq) /* we never sent it! */ 557 goto bad; 558 priv->recvAck = ack; 559 560 /* Update adaptive timeout stuff */ 561 diff = sample - a->rtt; 562 a->rtt += PPTP_ACK_ALPHA(diff); 563 if (diff < 0) 564 diff = -diff; 565 a->dev += PPTP_ACK_BETA(diff - a->dev); 566 a->ato = a->rtt + (u_int) (PPTP_ACK_CHI(a->dev)); 567 if (a->ato > PPTP_MAX_TIMEOUT) 568 a->ato = PPTP_MAX_TIMEOUT; 569 ovbcopy(a->timeSent + index + 1, a->timeSent, 570 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1))); 571 if (ack >= a->winAck && a->xmitWin < PPTP_XMIT_WIN) { 572 a->xmitWin++; 573 a->winAck = ack + a->xmitWin; 574 } 575 576 /* (Re)start receive ACK timer as necessary */ 577 ng_pptpgre_start_recv_ack_timer(node); 578 } 579 580 /* See if frame contains any data */ 581 if (gre->hasSeq) { 582 struct ng_pptpgre_ackp *const a = &priv->ackp; 583 const u_int32_t seq = ntohl(gre->data[0]); 584 585 /* Sanity check sequence number */ 586 if (seq <= priv->recvSeq) /* out-of-order or dup */ 587 goto bad; 588 priv->recvSeq = seq; 589 590 /* We need to acknowledge this packet; do it soon... */ 591 if (!a->sackTimerRunning) { 592 long ackTimeout; 593 594 /* Take half of the estimated round trip time */ 595 ackTimeout = (a->rtt >> 1); 596 597 /* If too soon, just send one right now */ 598 if (!priv->conf.enableDelayedAck) 599 ng_pptpgre_xmit(node, NULL, NULL); 600 else { /* send the ack later */ 601 if (ackTimeout > PPTP_MAX_ACK_DELAY) 602 ackTimeout = PPTP_MAX_ACK_DELAY; 603 a->sackTimer = timeout( 604 ng_pptpgre_send_ack_timeout, node, 605 ackTimeout * hz / PPTP_TIME_SCALE); 606 a->sackTimerRunning = 1; 607 } 608 } 609 610 /* Trim mbuf down to internal payload */ 611 m_adj(m, iphlen + grelen); 612 if (extralen > 0) 613 m_adj(m, -extralen); 614 615 /* Deliver frame to upper layers */ 616 NG_SEND_DATA(error, priv->upper, m, meta); 617 } else 618 NG_FREE_DATA(m, meta); /* no data to deliver */ 619 return (error); 620 } 621 622 /************************************************************************* 623 TIMER RELATED FUNCTIONS 624 *************************************************************************/ 625 626 /* 627 * Set a timer for the peer's acknowledging our oldest unacknowledged 628 * sequence number. If we get an ack for this sequence number before 629 * the timer goes off, we cancel the timer. Resets currently running 630 * recv ack timer, if any. 631 */ 632 static void 633 ng_pptpgre_start_recv_ack_timer(node_p node) 634 { 635 const priv_p priv = node->private; 636 struct ng_pptpgre_ackp *const a = &priv->ackp; 637 int remain; 638 639 /* Stop current recv ack timer, if any */ 640 untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer); 641 if (priv->recvAck == priv->xmitSeq) 642 return; 643 644 /* Compute how long until oldest unack'd packet times out, 645 and reset the timer to that time. */ 646 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node); 647 if (remain < 0) 648 remain = 0; 649 a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout, 650 node, remain * hz / PPTP_TIME_SCALE); 651 } 652 653 /* 654 * The peer has failed to acknowledge the oldest unacknowledged sequence 655 * number within the time allotted. Update our adaptive timeout parameters 656 * and reset/restart the recv ack timer. 657 */ 658 static void 659 ng_pptpgre_recv_ack_timeout(void *arg) 660 { 661 const node_p node = arg; 662 const priv_p priv = node->private; 663 struct ng_pptpgre_ackp *const a = &priv->ackp; 664 665 /* Update adaptive timeout stuff */ 666 a->rtt = PPTP_ACK_DELTA(a->rtt); 667 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 668 if (a->ato > PPTP_MAX_TIMEOUT) 669 a->ato = PPTP_MAX_TIMEOUT; 670 priv->recvAck++; /* assume packet was lost */ 671 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 672 ovbcopy(a->timeSent + 1, a->timeSent, /* shift xmit window times */ 673 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - 1)); 674 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 675 676 /* Restart timer if there are any more outstanding frames */ 677 if (priv->recvAck != priv->xmitSeq) 678 ng_pptpgre_start_recv_ack_timer(node); 679 } 680 681 /* 682 * We've waited as long as we're willing to wait before sending an 683 * acknowledgement to the peer for received frames. We had hoped to 684 * be able to piggy back our acknowledgement on an outgoing data frame, 685 * but apparently there haven't been any since. So send the ack now. 686 */ 687 static void 688 ng_pptpgre_send_ack_timeout(void *arg) 689 { 690 const node_p node = arg; 691 const priv_p priv = node->private; 692 struct ng_pptpgre_ackp *const a = &priv->ackp; 693 694 /* Send a frame with an ack but no payload */ 695 a->sackTimerRunning = 0; 696 ng_pptpgre_xmit(node, NULL, NULL); 697 } 698 699 /************************************************************************* 700 MISC FUNCTIONS 701 *************************************************************************/ 702 703 /* 704 * Reset state 705 */ 706 static void 707 ng_pptpgre_reset(node_p node) 708 { 709 const priv_p priv = node->private; 710 struct ng_pptpgre_ackp *const a = &priv->ackp; 711 712 /* Reset adaptive timeout state */ 713 a->ato = PPTP_MAX_TIMEOUT; 714 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 715 if (a->rtt < PPTP_MIN_RTT) 716 a->rtt = PPTP_MIN_RTT; 717 a->dev = 0; 718 a->xmitWin = (priv->conf.recvWin + 1) / 2; 719 if (a->xmitWin < 1) 720 a->xmitWin = 1; 721 if (a->xmitWin > PPTP_XMIT_WIN) 722 a->xmitWin = PPTP_XMIT_WIN; 723 a->winAck = a->xmitWin; 724 725 /* Reset sequence numbers */ 726 priv->recvSeq = 0; 727 priv->recvAck = 0; 728 priv->xmitSeq = 0; 729 priv->xmitAck = 0; 730 731 /* Reset start time */ 732 getmicrotime(&priv->startTime); 733 734 /* Stop timers */ 735 untimeout(ng_pptpgre_send_ack_timeout, node, a->sackTimer); 736 untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer); 737 a->sackTimerRunning = 0; 738 } 739 740 /* 741 * Return the current time scaled & translated to our internally used format. 742 */ 743 static pptptime_t 744 ng_pptpgre_time(node_p node) 745 { 746 const priv_p priv = node->private; 747 struct timeval tv; 748 749 getmicrotime(&tv); 750 if (tv.tv_sec < priv->startTime.tv_sec 751 || (tv.tv_sec == priv->startTime.tv_sec 752 && tv.tv_usec < priv->startTime.tv_usec)) 753 return (0); 754 timevalsub(&tv, &priv->startTime); 755 tv.tv_sec *= PPTP_TIME_SCALE; 756 tv.tv_usec /= 1000000 / PPTP_TIME_SCALE; 757 return(tv.tv_sec + tv.tv_usec); 758 } 759 760