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 /* milliseconds */ 119 typedef u_int32_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 / 100) /* 10 milliseconds */ 125 #define PPTP_MAX_TIMEOUT (10 * PPTP_TIME_SCALE) /* 10 seconds */ 126 127 /* See RFC 2637 section 4.4 */ 128 #define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */ 129 #define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */ 130 #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 131 #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 132 133 #define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y)) 134 135 /* We keep packet retransmit and acknowlegement state in this struct */ 136 struct ng_pptpgre_ackp { 137 int32_t ato; /* adaptive time-out value */ 138 int32_t rtt; /* round trip time estimate */ 139 int32_t dev; /* deviation estimate */ 140 u_int16_t xmitWin; /* size of xmit window */ 141 struct callout_handle sackTimer; /* send ack timer */ 142 struct callout_handle rackTimer; /* recv ack timer */ 143 node_p *sackTimerPtr; /* send ack timer pointer */ 144 node_p *rackTimerPtr; /* recv ack timer pointer */ 145 u_int32_t winAck; /* seq when xmitWin will grow */ 146 pptptime_t timeSent[PPTP_XMIT_WIN]; 147 }; 148 149 /* When we recieve a packet, we wait to see if there's an outgoing packet 150 we can piggy-back the ACK off of. These parameters determine the mimimum 151 and maxmimum length of time we're willing to wait in order to do that. */ 152 #define PPTP_MAX_ACK_DELAY ((int) (0.25 * PPTP_TIME_SCALE)) 153 154 /* Node private data */ 155 struct ng_pptpgre_private { 156 hook_p upper; /* hook to upper layers */ 157 hook_p lower; /* hook to lower layers */ 158 struct ng_pptpgre_conf conf; /* configuration info */ 159 struct ng_pptpgre_ackp ackp; /* packet transmit ack state */ 160 u_int32_t recvSeq; /* last seq # we rcv'd */ 161 u_int32_t xmitSeq; /* last seq # we sent */ 162 u_int32_t recvAck; /* last seq # peer ack'd */ 163 u_int32_t xmitAck; /* last seq # we ack'd */ 164 struct timeval startTime; /* time node was created */ 165 struct ng_pptpgre_stats stats; /* node statistics */ 166 }; 167 typedef struct ng_pptpgre_private *priv_p; 168 169 /* Netgraph node methods */ 170 static ng_constructor_t ng_pptpgre_constructor; 171 static ng_rcvmsg_t ng_pptpgre_rcvmsg; 172 static ng_shutdown_t ng_pptpgre_rmnode; 173 static ng_newhook_t ng_pptpgre_newhook; 174 static ng_rcvdata_t ng_pptpgre_rcvdata; 175 static ng_disconnect_t ng_pptpgre_disconnect; 176 177 /* Helper functions */ 178 static int ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta); 179 static int ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta); 180 static void ng_pptpgre_start_send_ack_timer(node_p node, long ackTimeout); 181 static void ng_pptpgre_start_recv_ack_timer(node_p node); 182 static void ng_pptpgre_recv_ack_timeout(void *arg); 183 static void ng_pptpgre_send_ack_timeout(void *arg); 184 static void ng_pptpgre_reset(node_p node); 185 static pptptime_t ng_pptpgre_time(node_p node); 186 187 /* Parse type for struct ng_pptpgre_conf */ 188 static const struct ng_parse_struct_info 189 ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO; 190 static const struct ng_parse_type ng_pptpgre_conf_type = { 191 &ng_parse_struct_type, 192 &ng_pptpgre_conf_type_info, 193 }; 194 195 /* Parse type for struct ng_pptpgre_stats */ 196 static const struct ng_parse_struct_info 197 ng_pptpgre_stats_type_info = NG_PPTPGRE_STATS_TYPE_INFO; 198 static const struct ng_parse_type ng_pptp_stats_type = { 199 &ng_parse_struct_type, 200 &ng_pptpgre_stats_type_info 201 }; 202 203 /* List of commands and how to convert arguments to/from ASCII */ 204 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 205 { 206 NGM_PPTPGRE_COOKIE, 207 NGM_PPTPGRE_SET_CONFIG, 208 "setconfig", 209 &ng_pptpgre_conf_type, 210 NULL 211 }, 212 { 213 NGM_PPTPGRE_COOKIE, 214 NGM_PPTPGRE_GET_CONFIG, 215 "getconfig", 216 NULL, 217 &ng_pptpgre_conf_type 218 }, 219 { 220 NGM_PPTPGRE_COOKIE, 221 NGM_PPTPGRE_GET_STATS, 222 "getstats", 223 NULL, 224 &ng_pptp_stats_type 225 }, 226 { 227 NGM_PPTPGRE_COOKIE, 228 NGM_PPTPGRE_CLR_STATS, 229 "clrstats", 230 NULL, 231 NULL 232 }, 233 { 234 NGM_PPTPGRE_COOKIE, 235 NGM_PPTPGRE_GETCLR_STATS, 236 "getclrstats", 237 NULL, 238 &ng_pptp_stats_type 239 }, 240 { 0 } 241 }; 242 243 /* Node type descriptor */ 244 static struct ng_type ng_pptpgre_typestruct = { 245 NG_VERSION, 246 NG_PPTPGRE_NODE_TYPE, 247 NULL, 248 ng_pptpgre_constructor, 249 ng_pptpgre_rcvmsg, 250 ng_pptpgre_rmnode, 251 ng_pptpgre_newhook, 252 NULL, 253 NULL, 254 ng_pptpgre_rcvdata, 255 ng_pptpgre_rcvdata, 256 ng_pptpgre_disconnect, 257 ng_pptpgre_cmdlist 258 }; 259 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 260 261 #define ERROUT(x) do { error = (x); goto done; } while (0) 262 263 /************************************************************************ 264 NETGRAPH NODE STUFF 265 ************************************************************************/ 266 267 /* 268 * Node type constructor 269 */ 270 static int 271 ng_pptpgre_constructor(node_p *nodep) 272 { 273 priv_p priv; 274 int error; 275 276 /* Allocate private structure */ 277 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 278 if (priv == NULL) 279 return (ENOMEM); 280 bzero(priv, sizeof(*priv)); 281 282 /* Call generic node constructor */ 283 if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) { 284 FREE(priv, M_NETGRAPH); 285 return (error); 286 } 287 (*nodep)->private = priv; 288 289 /* Initialize state */ 290 callout_handle_init(&priv->ackp.sackTimer); 291 callout_handle_init(&priv->ackp.rackTimer); 292 293 /* Done */ 294 return (0); 295 } 296 297 /* 298 * Give our OK for a hook to be added. 299 */ 300 static int 301 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 302 { 303 const priv_p priv = node->private; 304 hook_p *hookPtr; 305 306 /* Check hook name */ 307 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) 308 hookPtr = &priv->upper; 309 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) 310 hookPtr = &priv->lower; 311 else 312 return (EINVAL); 313 314 /* See if already connected */ 315 if (*hookPtr != NULL) 316 return (EISCONN); 317 318 /* OK */ 319 *hookPtr = hook; 320 return (0); 321 } 322 323 /* 324 * Receive a control message. 325 */ 326 static int 327 ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg, 328 const char *raddr, struct ng_mesg **rptr, hook_p lasthook) 329 { 330 const priv_p priv = node->private; 331 struct ng_mesg *resp = NULL; 332 int error = 0; 333 334 switch (msg->header.typecookie) { 335 case NGM_PPTPGRE_COOKIE: 336 switch (msg->header.cmd) { 337 case NGM_PPTPGRE_SET_CONFIG: 338 { 339 struct ng_pptpgre_conf *const newConf = 340 (struct ng_pptpgre_conf *) msg->data; 341 342 /* Check for invalid or illegal config */ 343 if (msg->header.arglen != sizeof(*newConf)) 344 ERROUT(EINVAL); 345 ng_pptpgre_reset(node); /* reset on configure */ 346 priv->conf = *newConf; 347 break; 348 } 349 case NGM_PPTPGRE_GET_CONFIG: 350 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT); 351 if (resp == NULL) 352 ERROUT(ENOMEM); 353 bcopy(&priv->conf, resp->data, sizeof(priv->conf)); 354 break; 355 case NGM_PPTPGRE_GET_STATS: 356 case NGM_PPTPGRE_CLR_STATS: 357 case NGM_PPTPGRE_GETCLR_STATS: 358 { 359 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) { 360 NG_MKRESPONSE(resp, msg, 361 sizeof(priv->stats), M_NOWAIT); 362 if (resp == NULL) 363 ERROUT(ENOMEM); 364 bcopy(&priv->stats, 365 resp->data, sizeof(priv->stats)); 366 } 367 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS) 368 bzero(&priv->stats, sizeof(priv->stats)); 369 break; 370 } 371 default: 372 error = EINVAL; 373 break; 374 } 375 break; 376 default: 377 error = EINVAL; 378 break; 379 } 380 if (rptr) 381 *rptr = resp; 382 else if (resp) 383 FREE(resp, M_NETGRAPH); 384 385 done: 386 FREE(msg, M_NETGRAPH); 387 return (error); 388 } 389 390 /* 391 * Receive incoming data on a hook. 392 */ 393 static int 394 ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 395 struct mbuf **ret_m, meta_p *ret_meta) 396 { 397 const node_p node = hook->node; 398 const priv_p priv = node->private; 399 400 /* If not configured, reject */ 401 if (!priv->conf.enabled) { 402 NG_FREE_DATA(m, meta); 403 return (ENXIO); 404 } 405 406 /* Treat as xmit or recv data */ 407 if (hook == priv->upper) 408 return ng_pptpgre_xmit(node, m, meta); 409 if (hook == priv->lower) 410 return ng_pptpgre_recv(node, m, meta); 411 panic("%s: weird hook", __FUNCTION__); 412 } 413 414 /* 415 * Destroy node 416 */ 417 static int 418 ng_pptpgre_rmnode(node_p node) 419 { 420 const priv_p priv = node->private; 421 422 /* Reset node */ 423 ng_pptpgre_reset(node); 424 425 /* Take down netgraph node */ 426 node->flags |= NG_INVALID; 427 ng_cutlinks(node); 428 ng_unname(node); 429 bzero(priv, sizeof(*priv)); 430 FREE(priv, M_NETGRAPH); 431 node->private = NULL; 432 ng_unref(node); 433 return (0); 434 } 435 436 /* 437 * Hook disconnection 438 */ 439 static int 440 ng_pptpgre_disconnect(hook_p hook) 441 { 442 const node_p node = hook->node; 443 const priv_p priv = node->private; 444 445 /* Zero out hook pointer */ 446 if (hook == priv->upper) 447 priv->upper = NULL; 448 else if (hook == priv->lower) 449 priv->lower = NULL; 450 else 451 panic("%s: unknown hook", __FUNCTION__); 452 453 /* Go away if no longer connected to anything */ 454 if (node->numhooks == 0) 455 ng_rmnode(node); 456 return (0); 457 } 458 459 /************************************************************************* 460 TRANSMIT AND RECEIVE FUNCTIONS 461 *************************************************************************/ 462 463 /* 464 * Transmit an outgoing frame, or just an ack if m is NULL. 465 */ 466 static int 467 ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta) 468 { 469 const priv_p priv = node->private; 470 struct ng_pptpgre_ackp *const a = &priv->ackp; 471 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 472 struct greheader *const gre = (struct greheader *)buf; 473 int grelen, error; 474 475 /* Check if there's data */ 476 if (m != NULL) { 477 478 /* Is our transmit window full? */ 479 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck) 480 >= a->xmitWin) { 481 priv->stats.xmitDrops++; 482 NG_FREE_DATA(m, meta); 483 return (ENOBUFS); 484 } 485 486 /* Sanity check frame length */ 487 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 488 priv->stats.xmitTooBig++; 489 NG_FREE_DATA(m, meta); 490 return (EMSGSIZE); 491 } 492 } else 493 priv->stats.xmitLoneAcks++; 494 495 /* Build GRE header */ 496 ((u_int32_t *) gre)[0] = htonl(PPTP_INIT_VALUE); 497 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 498 gre->cid = htons(priv->conf.peerCid); 499 500 /* Include sequence number if packet contains any data */ 501 if (m != NULL) { 502 gre->hasSeq = 1; 503 a->timeSent[priv->xmitSeq - priv->recvAck] 504 = ng_pptpgre_time(node); 505 priv->xmitSeq++; 506 gre->data[0] = htonl(priv->xmitSeq); 507 if (priv->xmitSeq == priv->recvAck + 1) 508 ng_pptpgre_start_recv_ack_timer(node); 509 } 510 511 /* Include acknowledgement (and stop send ack timer) if needed */ 512 if (PPTP_SEQ_DIFF(priv->xmitAck, priv->recvSeq) < 0) { 513 gre->hasAck = 1; 514 priv->xmitAck = priv->recvSeq; 515 gre->data[gre->hasSeq] = htonl(priv->xmitAck); 516 a->sackTimerPtr = NULL; 517 } 518 519 /* Prepend GRE header to outgoing frame */ 520 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 521 if (m == NULL) { 522 MGETHDR(m, M_DONTWAIT, MT_DATA); 523 if (m == NULL) { 524 NG_FREE_META(meta); 525 return (ENOBUFS); 526 } 527 m->m_len = m->m_pkthdr.len = grelen; 528 m->m_pkthdr.rcvif = NULL; 529 } else { 530 M_PREPEND(m, grelen, M_NOWAIT); 531 if (m == NULL || (m->m_len < grelen 532 && (m = m_pullup(m, grelen)) == NULL)) { 533 NG_FREE_META(meta); 534 return (ENOBUFS); 535 } 536 } 537 bcopy(gre, mtod(m, u_char *), grelen); 538 539 /* Update stats */ 540 priv->stats.xmitPackets++; 541 priv->stats.xmitOctets += m->m_pkthdr.len; 542 543 /* Deliver packet */ 544 NG_SEND_DATA(error, priv->lower, m, meta); 545 return (error); 546 } 547 548 /* 549 * Handle an incoming packet. The packet includes the IP header. 550 */ 551 static int 552 ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta) 553 { 554 const priv_p priv = node->private; 555 int iphlen, grelen, extralen; 556 struct greheader *gre; 557 struct ip *ip; 558 int error = 0; 559 560 /* Update stats */ 561 priv->stats.recvPackets++; 562 priv->stats.recvOctets += m->m_pkthdr.len; 563 564 /* Sanity check packet length */ 565 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 566 priv->stats.recvRunts++; 567 bad: 568 NG_FREE_DATA(m, meta); 569 return (EINVAL); 570 } 571 572 /* Safely pull up the complete IP+GRE headers */ 573 if (m->m_len < sizeof(*ip) + sizeof(*gre) 574 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 575 NG_FREE_META(meta); 576 return (ENOBUFS); 577 } 578 ip = mtod(m, struct ip *); 579 iphlen = ip->ip_hl << 2; 580 if (m->m_len < iphlen + sizeof(*gre)) { 581 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 582 NG_FREE_META(meta); 583 return (ENOBUFS); 584 } 585 ip = mtod(m, struct ip *); 586 } 587 gre = (struct greheader *)((u_char *)ip + iphlen); 588 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 589 if (m->m_pkthdr.len < iphlen + grelen) { 590 priv->stats.recvRunts++; 591 goto bad; 592 } 593 if (m->m_len < iphlen + grelen) { 594 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 595 NG_FREE_META(meta); 596 return (ENOBUFS); 597 } 598 ip = mtod(m, struct ip *); 599 gre = (struct greheader *)((u_char *)ip + iphlen); 600 } 601 602 /* Sanity check packet length and GRE header bits */ 603 extralen = m->m_pkthdr.len 604 - (iphlen + grelen + (u_int16_t)ntohs(gre->length)); 605 if (extralen < 0) { 606 priv->stats.recvBadGRE++; 607 goto bad; 608 } 609 if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) { 610 priv->stats.recvBadGRE++; 611 goto bad; 612 } 613 if (ntohs(gre->cid) != priv->conf.cid) { 614 priv->stats.recvBadCID++; 615 goto bad; 616 } 617 618 /* Look for peer ack */ 619 if (gre->hasAck) { 620 struct ng_pptpgre_ackp *const a = &priv->ackp; 621 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 622 const int index = ack - priv->recvAck - 1; 623 const long sample = ng_pptpgre_time(node) - a->timeSent[index]; 624 long diff; 625 626 /* Sanity check ack value */ 627 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) { 628 priv->stats.recvBadAcks++; 629 goto badAck; /* we never sent it! */ 630 } 631 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0) 632 goto badAck; /* ack already timed out */ 633 priv->recvAck = ack; 634 635 /* Update adaptive timeout stuff */ 636 diff = sample - a->rtt; 637 a->rtt += PPTP_ACK_ALPHA(diff); 638 if (diff < 0) 639 diff = -diff; 640 a->dev += PPTP_ACK_BETA(diff - a->dev); 641 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 642 if (a->ato > PPTP_MAX_TIMEOUT) 643 a->ato = PPTP_MAX_TIMEOUT; 644 if (a->ato < PPTP_MIN_TIMEOUT) 645 a->ato = PPTP_MIN_TIMEOUT; 646 647 /* Shift packet transmit times in our transmit window */ 648 ovbcopy(a->timeSent + index + 1, a->timeSent, 649 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1))); 650 651 /* If we sent an entire window, increase window size by one */ 652 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0 653 && a->xmitWin < PPTP_XMIT_WIN) { 654 a->xmitWin++; 655 a->winAck = ack + a->xmitWin; 656 } 657 658 /* Stop/(re)start receive ACK timer as necessary */ 659 ng_pptpgre_start_recv_ack_timer(node); 660 } 661 badAck: 662 663 /* See if frame contains any data */ 664 if (gre->hasSeq) { 665 struct ng_pptpgre_ackp *const a = &priv->ackp; 666 const u_int32_t seq = ntohl(gre->data[0]); 667 668 /* Sanity check sequence number */ 669 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) { 670 if (seq == priv->recvSeq) 671 priv->stats.recvDuplicates++; 672 else 673 priv->stats.recvOutOfOrder++; 674 goto bad; /* out-of-order or dup */ 675 } 676 priv->recvSeq = seq; 677 678 /* We need to acknowledge this packet; do it soon... */ 679 if (a->sackTimerPtr == NULL) { 680 long maxWait; 681 682 /* Take half of the estimated round trip time */ 683 maxWait = (a->rtt >> 1); 684 685 /* If too soon, just send one right now */ 686 if (!priv->conf.enableDelayedAck) 687 ng_pptpgre_xmit(node, NULL, NULL); 688 else { /* send the ack later */ 689 if (maxWait > PPTP_MAX_ACK_DELAY) 690 maxWait = PPTP_MAX_ACK_DELAY; 691 ng_pptpgre_start_send_ack_timer(node, maxWait); 692 } 693 } 694 695 /* Trim mbuf down to internal payload */ 696 m_adj(m, iphlen + grelen); 697 if (extralen > 0) 698 m_adj(m, -extralen); 699 700 /* Deliver frame to upper layers */ 701 NG_SEND_DATA(error, priv->upper, m, meta); 702 } else { 703 priv->stats.recvLoneAcks++; 704 NG_FREE_DATA(m, meta); /* no data to deliver */ 705 } 706 return (error); 707 } 708 709 /************************************************************************* 710 TIMER RELATED FUNCTIONS 711 *************************************************************************/ 712 713 /* 714 * Start a timer for the peer's acknowledging our oldest unacknowledged 715 * sequence number. If we get an ack for this sequence number before 716 * the timer goes off, we cancel the timer. Resets currently running 717 * recv ack timer, if any. 718 */ 719 static void 720 ng_pptpgre_start_recv_ack_timer(node_p node) 721 { 722 const priv_p priv = node->private; 723 struct ng_pptpgre_ackp *const a = &priv->ackp; 724 int remain; 725 726 /* "Stop" current recv ack timer, if any */ 727 a->rackTimerPtr = NULL; 728 729 /* Are we waiting for an acknowlegement? */ 730 if (priv->recvAck == priv->xmitSeq) 731 return; 732 733 /* Compute how long until oldest unack'd packet times out, 734 and reset the timer to that time. */ 735 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node); 736 if (remain < 0) 737 remain = 0; 738 739 /* Start new timer */ 740 MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 741 if (a->rackTimerPtr == NULL) 742 return; /* XXX potential hang here */ 743 *a->rackTimerPtr = node; /* insures the correct timeout event */ 744 node->refs++; 745 a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout, 746 a->rackTimerPtr, remain * hz / PPTP_TIME_SCALE); 747 } 748 749 /* 750 * The peer has failed to acknowledge the oldest unacknowledged sequence 751 * number within the time allotted. Update our adaptive timeout parameters 752 * and reset/restart the recv ack timer. 753 */ 754 static void 755 ng_pptpgre_recv_ack_timeout(void *arg) 756 { 757 int s = splnet(); 758 const node_p node = *((node_p *)arg); 759 const priv_p priv = node->private; 760 struct ng_pptpgre_ackp *const a = &priv->ackp; 761 762 /* This complicated stuff is needed to avoid race conditions */ 763 FREE(arg, M_NETGRAPH); 764 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__)); 765 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */ 766 ng_unref(node); 767 splx(s); 768 return; 769 } 770 ng_unref(node); 771 if (arg != a->rackTimerPtr) { /* timer stopped race condition */ 772 splx(s); 773 return; 774 } 775 a->rackTimerPtr = NULL; 776 777 /* Update adaptive timeout stuff */ 778 priv->stats.recvAckTimeouts++; 779 a->rtt = PPTP_ACK_DELTA(a->rtt); 780 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 781 if (a->ato > PPTP_MAX_TIMEOUT) 782 a->ato = PPTP_MAX_TIMEOUT; 783 if (a->ato < PPTP_MIN_TIMEOUT) 784 a->ato = PPTP_MIN_TIMEOUT; 785 786 /* Reset ack and sliding window */ 787 priv->recvAck = priv->xmitSeq; /* pretend we got the ack */ 788 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 789 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 790 splx(s); 791 } 792 793 /* 794 * Start the send ack timer. This assumes the timer is not 795 * already running. 796 */ 797 static void 798 ng_pptpgre_start_send_ack_timer(node_p node, long ackTimeout) 799 { 800 const priv_p priv = node->private; 801 struct ng_pptpgre_ackp *const a = &priv->ackp; 802 803 /* Start new timer */ 804 KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __FUNCTION__)); 805 MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 806 if (a->sackTimerPtr == NULL) 807 return; /* XXX potential hang here */ 808 *a->sackTimerPtr = node; 809 node->refs++; 810 a->sackTimer = timeout(ng_pptpgre_send_ack_timeout, 811 a->sackTimerPtr, ackTimeout * hz / PPTP_TIME_SCALE); 812 } 813 814 /* 815 * We've waited as long as we're willing to wait before sending an 816 * acknowledgement to the peer for received frames. We had hoped to 817 * be able to piggy back our acknowledgement on an outgoing data frame, 818 * but apparently there haven't been any since. So send the ack now. 819 */ 820 static void 821 ng_pptpgre_send_ack_timeout(void *arg) 822 { 823 int s = splnet(); 824 const node_p node = *((node_p *)arg); 825 const priv_p priv = node->private; 826 struct ng_pptpgre_ackp *const a = &priv->ackp; 827 828 /* This complicated stuff is needed to avoid race conditions */ 829 FREE(arg, M_NETGRAPH); 830 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__)); 831 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */ 832 ng_unref(node); 833 splx(s); 834 return; 835 } 836 ng_unref(node); 837 if (a->sackTimerPtr != arg) { /* timer stopped race condition */ 838 splx(s); 839 return; 840 } 841 a->sackTimerPtr = NULL; 842 843 /* Send a frame with an ack but no payload */ 844 ng_pptpgre_xmit(node, NULL, NULL); 845 splx(s); 846 } 847 848 /************************************************************************* 849 MISC FUNCTIONS 850 *************************************************************************/ 851 852 /* 853 * Reset state 854 */ 855 static void 856 ng_pptpgre_reset(node_p node) 857 { 858 const priv_p priv = node->private; 859 struct ng_pptpgre_ackp *const a = &priv->ackp; 860 861 /* Reset adaptive timeout state */ 862 a->ato = PPTP_MAX_TIMEOUT; 863 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 864 if (a->rtt < PPTP_MIN_RTT) 865 a->rtt = PPTP_MIN_RTT; 866 a->dev = 0; 867 a->xmitWin = (priv->conf.recvWin + 1) / 2; 868 if (a->xmitWin < 2) /* often the first packet is lost */ 869 a->xmitWin = 2; /* because the peer isn't ready */ 870 if (a->xmitWin > PPTP_XMIT_WIN) 871 a->xmitWin = PPTP_XMIT_WIN; 872 a->winAck = a->xmitWin; 873 874 /* Reset sequence numbers */ 875 priv->recvSeq = ~0; 876 priv->recvAck = ~0; 877 priv->xmitSeq = ~0; 878 priv->xmitAck = ~0; 879 880 /* Reset start time */ 881 getmicrouptime(&priv->startTime); 882 883 /* Reset stats */ 884 bzero(&priv->stats, sizeof(priv->stats)); 885 886 /* "Stop" timers */ 887 a->sackTimerPtr = NULL; 888 a->rackTimerPtr = NULL; 889 } 890 891 /* 892 * Return the current time scaled & translated to our internally used format. 893 */ 894 static pptptime_t 895 ng_pptpgre_time(node_p node) 896 { 897 const priv_p priv = node->private; 898 struct timeval tv; 899 900 getmicrouptime(&tv); 901 if (tv.tv_sec < priv->startTime.tv_sec 902 || (tv.tv_sec == priv->startTime.tv_sec 903 && tv.tv_usec < priv->startTime.tv_usec)) 904 return (0); 905 timevalsub(&tv, &priv->startTime); 906 tv.tv_sec *= PPTP_TIME_SCALE; 907 tv.tv_usec /= 1000000 / PPTP_TIME_SCALE; 908 return(tv.tv_sec + tv.tv_usec); 909 } 910 911