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/mbuf.h> 61 #include <sys/malloc.h> 62 #include <sys/errno.h> 63 #include <sys/socket.h> 64 #include <sys/syslog.h> 65 #include <sys/ctype.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 <netgraph/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 119 typedef u_int32_t pptptime_t; 120 121 /* Acknowledgment timeout parameters and functions */ 122 #define PPTP_XMIT_WIN 8 /* max xmit window */ 123 #define PPTP_MIN_RTT (PPTP_TIME_SCALE / 10) /* 1/10 second */ 124 #define PPTP_MAX_TIMEOUT (10 * PPTP_TIME_SCALE) /* 10 seconds */ 125 126 #define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */ 127 #define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */ 128 #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 129 #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 130 131 /* We keep packet retransmit and acknowlegement state in this struct */ 132 struct ng_pptpgre_ackp { 133 int32_t ato; /* adaptive time-out value */ 134 int32_t rtt; /* round trip time estimate */ 135 int32_t dev; /* deviation estimate */ 136 u_int16_t xmitWin; /* size of xmit window */ 137 u_char sackTimerRunning;/* send ack timer is running */ 138 u_int32_t winAck; /* seq when xmitWin will grow */ 139 struct callout_handle sackTimer; /* send ack timer */ 140 struct callout_handle rackTimer; /* recv ack timer */ 141 pptptime_t timeSent[PPTP_XMIT_WIN]; 142 }; 143 144 /* When we recieve a packet, we wait to see if there's an outgoing packet 145 we can piggy-back the ACK off of. These parameters determine the mimimum 146 and maxmimum length of time we're willing to wait in order to do that. */ 147 #define PPTP_MAX_ACK_DELAY ((int) (0.25 * PPTP_TIME_SCALE)) 148 149 /* Node private data */ 150 struct ng_pptpgre_private { 151 hook_p upper; /* hook to upper layers */ 152 hook_p lower; /* hook to lower layers */ 153 struct ng_pptpgre_conf conf; /* configuration info */ 154 struct ng_pptpgre_ackp ackp; /* packet transmit ack state */ 155 u_int32_t recvSeq; /* last seq # we rcv'd */ 156 u_int32_t xmitSeq; /* last seq # we sent */ 157 u_int32_t recvAck; /* last seq # peer ack'd */ 158 u_int32_t xmitAck; /* last seq # we ack'd */ 159 struct timeval startTime; /* time node was created */ 160 }; 161 typedef struct ng_pptpgre_private *priv_p; 162 163 /* Netgraph node methods */ 164 static ng_constructor_t ng_pptpgre_constructor; 165 static ng_rcvmsg_t ng_pptpgre_rcvmsg; 166 static ng_shutdown_t ng_pptpgre_rmnode; 167 static ng_newhook_t ng_pptpgre_newhook; 168 static ng_rcvdata_t ng_pptpgre_rcvdata; 169 static ng_disconnect_t ng_pptpgre_disconnect; 170 171 /* Helper functions */ 172 static int ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta); 173 static int ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta); 174 static void ng_pptpgre_start_recv_ack_timer(node_p node); 175 static void ng_pptpgre_recv_ack_timeout(void *arg); 176 static void ng_pptpgre_send_ack_timeout(void *arg); 177 static void ng_pptpgre_reset(node_p node); 178 static pptptime_t ng_pptpgre_time(node_p node); 179 180 /* Parse type for struct ng_pptpgre_conf */ 181 static const struct ng_parse_struct_info 182 ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO; 183 static const struct ng_parse_type ng_pptpgre_conf_type = { 184 &ng_parse_struct_type, 185 &ng_pptpgre_conf_type_info, 186 }; 187 188 /* List of commands and how to convert arguments to/from ASCII */ 189 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 190 { 191 NGM_PPTPGRE_COOKIE, 192 NGM_PPTPGRE_SET_CONFIG, 193 "setconfig", 194 &ng_pptpgre_conf_type, 195 NULL 196 }, 197 { 198 NGM_PPTPGRE_COOKIE, 199 NGM_PPTPGRE_GET_CONFIG, 200 "getconfig", 201 NULL, 202 &ng_pptpgre_conf_type 203 }, 204 { 0 } 205 }; 206 207 /* Node type descriptor */ 208 static struct ng_type ng_pptpgre_typestruct = { 209 NG_VERSION, 210 NG_PPTPGRE_NODE_TYPE, 211 NULL, 212 ng_pptpgre_constructor, 213 ng_pptpgre_rcvmsg, 214 ng_pptpgre_rmnode, 215 ng_pptpgre_newhook, 216 NULL, 217 NULL, 218 ng_pptpgre_rcvdata, 219 ng_pptpgre_rcvdata, 220 ng_pptpgre_disconnect, 221 ng_pptpgre_cmdlist 222 }; 223 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 224 225 #define ERROUT(x) do { error = (x); goto done; } while (0) 226 227 /************************************************************************ 228 NETGRAPH NODE STUFF 229 ************************************************************************/ 230 231 /* 232 * Node type constructor 233 */ 234 static int 235 ng_pptpgre_constructor(node_p *nodep) 236 { 237 priv_p priv; 238 int error; 239 240 /* Allocate private structure */ 241 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 242 if (priv == NULL) 243 return (ENOMEM); 244 bzero(priv, sizeof(*priv)); 245 246 /* Call generic node constructor */ 247 if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) { 248 FREE(priv, M_NETGRAPH); 249 return (error); 250 } 251 (*nodep)->private = priv; 252 253 /* Initialize state */ 254 callout_handle_init(&priv->ackp.sackTimer); 255 callout_handle_init(&priv->ackp.rackTimer); 256 257 /* Done */ 258 return (0); 259 } 260 261 /* 262 * Give our OK for a hook to be added. 263 */ 264 static int 265 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 266 { 267 const priv_p priv = node->private; 268 hook_p *hookPtr; 269 270 /* Check hook name */ 271 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) 272 hookPtr = &priv->upper; 273 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) 274 hookPtr = &priv->lower; 275 else 276 return (EINVAL); 277 278 /* See if already connected */ 279 if (*hookPtr != NULL) 280 return (EISCONN); 281 282 /* OK */ 283 *hookPtr = hook; 284 return (0); 285 } 286 287 /* 288 * Receive a control message. 289 */ 290 static int 291 ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg, 292 const char *raddr, struct ng_mesg **rptr, hook_p lasthook) 293 { 294 const priv_p priv = node->private; 295 struct ng_mesg *resp = NULL; 296 int error = 0; 297 298 switch (msg->header.typecookie) { 299 case NGM_PPTPGRE_COOKIE: 300 switch (msg->header.cmd) { 301 case NGM_PPTPGRE_SET_CONFIG: 302 { 303 struct ng_pptpgre_conf *const newConf = 304 (struct ng_pptpgre_conf *) msg->data; 305 306 /* Check for invalid or illegal config */ 307 if (msg->header.arglen != sizeof(*newConf)) 308 ERROUT(EINVAL); 309 ng_pptpgre_reset(node); /* reset on configure */ 310 priv->conf = *newConf; 311 break; 312 } 313 case NGM_PPTPGRE_GET_CONFIG: 314 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT); 315 if (resp == NULL) 316 ERROUT(ENOMEM); 317 bcopy(&priv->conf, resp->data, sizeof(priv->conf)); 318 break; 319 default: 320 error = EINVAL; 321 break; 322 } 323 break; 324 default: 325 error = EINVAL; 326 break; 327 } 328 if (rptr) 329 *rptr = resp; 330 else if (resp) 331 FREE(resp, M_NETGRAPH); 332 333 done: 334 FREE(msg, M_NETGRAPH); 335 return (error); 336 } 337 338 /* 339 * Receive incoming data on a hook. 340 */ 341 static int 342 ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 343 struct mbuf **ret_m, meta_p *ret_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 int s = splnet(); 662 const node_p node = arg; 663 const priv_p priv = node->private; 664 struct ng_pptpgre_ackp *const a = &priv->ackp; 665 666 /* Update adaptive timeout stuff */ 667 a->rtt = PPTP_ACK_DELTA(a->rtt); 668 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 669 if (a->ato > PPTP_MAX_TIMEOUT) 670 a->ato = PPTP_MAX_TIMEOUT; 671 priv->recvAck++; /* assume packet was lost */ 672 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 673 ovbcopy(a->timeSent + 1, a->timeSent, /* shift xmit window times */ 674 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - 1)); 675 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 676 677 /* Restart timer if there are any more outstanding frames */ 678 if (priv->recvAck != priv->xmitSeq) 679 ng_pptpgre_start_recv_ack_timer(node); 680 splx(s); 681 } 682 683 /* 684 * We've waited as long as we're willing to wait before sending an 685 * acknowledgement to the peer for received frames. We had hoped to 686 * be able to piggy back our acknowledgement on an outgoing data frame, 687 * but apparently there haven't been any since. So send the ack now. 688 */ 689 static void 690 ng_pptpgre_send_ack_timeout(void *arg) 691 { 692 int s = splnet(); 693 const node_p node = arg; 694 const priv_p priv = node->private; 695 struct ng_pptpgre_ackp *const a = &priv->ackp; 696 697 /* Send a frame with an ack but no payload */ 698 a->sackTimerRunning = 0; 699 ng_pptpgre_xmit(node, NULL, NULL); 700 splx(s); 701 } 702 703 /************************************************************************* 704 MISC FUNCTIONS 705 *************************************************************************/ 706 707 /* 708 * Reset state 709 */ 710 static void 711 ng_pptpgre_reset(node_p node) 712 { 713 const priv_p priv = node->private; 714 struct ng_pptpgre_ackp *const a = &priv->ackp; 715 716 /* Reset adaptive timeout state */ 717 a->ato = PPTP_MAX_TIMEOUT; 718 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 719 if (a->rtt < PPTP_MIN_RTT) 720 a->rtt = PPTP_MIN_RTT; 721 a->dev = 0; 722 a->xmitWin = (priv->conf.recvWin + 1) / 2; 723 if (a->xmitWin < 1) 724 a->xmitWin = 1; 725 if (a->xmitWin > PPTP_XMIT_WIN) 726 a->xmitWin = PPTP_XMIT_WIN; 727 a->winAck = a->xmitWin; 728 729 /* Reset sequence numbers */ 730 priv->recvSeq = 0; 731 priv->recvAck = 0; 732 priv->xmitSeq = 0; 733 priv->xmitAck = 0; 734 735 /* Reset start time */ 736 getmicrotime(&priv->startTime); 737 738 /* Stop timers */ 739 untimeout(ng_pptpgre_send_ack_timeout, node, a->sackTimer); 740 untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer); 741 a->sackTimerRunning = 0; 742 } 743 744 /* 745 * Return the current time scaled & translated to our internally used format. 746 */ 747 static pptptime_t 748 ng_pptpgre_time(node_p node) 749 { 750 const priv_p priv = node->private; 751 struct timeval tv; 752 753 getmicrotime(&tv); 754 if (tv.tv_sec < priv->startTime.tv_sec 755 || (tv.tv_sec == priv->startTime.tv_sec 756 && tv.tv_usec < priv->startTime.tv_usec)) 757 return (0); 758 timevalsub(&tv, &priv->startTime); 759 tv.tv_sec *= PPTP_TIME_SCALE; 760 tv.tv_usec /= 1000000 / PPTP_TIME_SCALE; 761 return(tv.tv_sec + tv.tv_usec); 762 } 763 764