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