1 2/* 3 * ng_pptpgre.c 4 * 5 * Copyright (c) 1996-1999 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Author: Archie Cobbs <archie@freebsd.org> 38 *
|
39 * $FreeBSD: head/sys/netgraph/ng_pptpgre.c 69922 2000-12-12 18:52:14Z julian $
|
39 * $FreeBSD: head/sys/netgraph/ng_pptpgre.c 70159 2000-12-18 20:03:32Z julian $ |
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,
|
248 NG_ABI_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_disconnect, 259 ng_pptpgre_cmdlist 260}; 261NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 262 263#define ERROUT(x) do { error = (x); goto done; } while (0) 264 265/************************************************************************ 266 NETGRAPH NODE STUFF 267 ************************************************************************/ 268 269/* 270 * Node type constructor 271 */ 272static int 273ng_pptpgre_constructor(node_p *nodep) 274{ 275 priv_p priv; 276 int error; 277 278 /* Allocate private structure */ 279 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 280 if (priv == NULL) 281 return (ENOMEM); 282 283 /* Call generic node constructor */ 284 if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) { 285 FREE(priv, M_NETGRAPH); 286 return (error); 287 } 288 (*nodep)->private = priv; 289 290 /* Initialize state */ 291 callout_handle_init(&priv->ackp.sackTimer); 292 callout_handle_init(&priv->ackp.rackTimer); 293 294 /* Done */ 295 return (0); 296} 297 298/* 299 * Give our OK for a hook to be added. 300 */ 301static int 302ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 303{ 304 const priv_p priv = node->private; 305 hook_p *hookPtr; 306 307 /* Check hook name */ 308 if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) 309 hookPtr = &priv->upper; 310 else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) 311 hookPtr = &priv->lower; 312 else 313 return (EINVAL); 314 315 /* See if already connected */ 316 if (*hookPtr != NULL) 317 return (EISCONN); 318 319 /* OK */ 320 *hookPtr = hook; 321 return (0); 322} 323 324/* 325 * Receive a control message. 326 */ 327static int 328ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg, 329 const char *raddr, struct ng_mesg **rptr, hook_p lasthook) 330{ 331 const priv_p priv = node->private; 332 struct ng_mesg *resp = NULL; 333 int error = 0; 334 335 switch (msg->header.typecookie) { 336 case NGM_PPTPGRE_COOKIE: 337 switch (msg->header.cmd) { 338 case NGM_PPTPGRE_SET_CONFIG: 339 { 340 struct ng_pptpgre_conf *const newConf = 341 (struct ng_pptpgre_conf *) msg->data; 342 343 /* Check for invalid or illegal config */ 344 if (msg->header.arglen != sizeof(*newConf)) 345 ERROUT(EINVAL); 346 ng_pptpgre_reset(node); /* reset on configure */ 347 priv->conf = *newConf; 348 break; 349 } 350 case NGM_PPTPGRE_GET_CONFIG: 351 NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT); 352 if (resp == NULL) 353 ERROUT(ENOMEM); 354 bcopy(&priv->conf, resp->data, sizeof(priv->conf)); 355 break; 356 case NGM_PPTPGRE_GET_STATS: 357 case NGM_PPTPGRE_CLR_STATS: 358 case NGM_PPTPGRE_GETCLR_STATS: 359 { 360 if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) { 361 NG_MKRESPONSE(resp, msg, 362 sizeof(priv->stats), M_NOWAIT); 363 if (resp == NULL) 364 ERROUT(ENOMEM); 365 bcopy(&priv->stats, 366 resp->data, sizeof(priv->stats)); 367 } 368 if (msg->header.cmd != NGM_PPTPGRE_GET_STATS) 369 bzero(&priv->stats, sizeof(priv->stats)); 370 break; 371 } 372 default: 373 error = EINVAL; 374 break; 375 } 376 break; 377 default: 378 error = EINVAL; 379 break; 380 }
|
381done: |
382 if (rptr) 383 *rptr = resp; 384 else if (resp) 385 FREE(resp, M_NETGRAPH); 386
|
386done:
|
387 FREE(msg, M_NETGRAPH); 388 return (error); 389} 390 391/* 392 * Receive incoming data on a hook. 393 */ 394static int 395ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 396 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 397{ 398 const node_p node = hook->node; 399 const priv_p priv = node->private; 400 401 /* If not configured, reject */ 402 if (!priv->conf.enabled) { 403 NG_FREE_DATA(m, meta); 404 return (ENXIO); 405 } 406 407 /* Treat as xmit or recv data */ 408 if (hook == priv->upper) 409 return ng_pptpgre_xmit(node, m, meta); 410 if (hook == priv->lower) 411 return ng_pptpgre_recv(node, m, meta); 412 panic("%s: weird hook", __FUNCTION__); 413} 414 415/* 416 * Destroy node 417 */ 418static int 419ng_pptpgre_rmnode(node_p node) 420{ 421 const priv_p priv = node->private; 422 423 /* Reset node */ 424 ng_pptpgre_reset(node); 425 426 /* Take down netgraph node */ 427 node->flags |= NG_INVALID; 428 ng_cutlinks(node); 429 ng_unname(node); 430 bzero(priv, sizeof(*priv)); 431 FREE(priv, M_NETGRAPH); 432 node->private = NULL; 433 ng_unref(node); 434 return (0); 435} 436 437/* 438 * Hook disconnection 439 */ 440static int 441ng_pptpgre_disconnect(hook_p hook) 442{ 443 const node_p node = hook->node; 444 const priv_p priv = node->private; 445 446 /* Zero out hook pointer */ 447 if (hook == priv->upper) 448 priv->upper = NULL; 449 else if (hook == priv->lower) 450 priv->lower = NULL; 451 else 452 panic("%s: unknown hook", __FUNCTION__); 453 454 /* Go away if no longer connected to anything */ 455 if (node->numhooks == 0) 456 ng_rmnode(node); 457 return (0); 458} 459 460/************************************************************************* 461 TRANSMIT AND RECEIVE FUNCTIONS 462*************************************************************************/ 463 464/* 465 * Transmit an outgoing frame, or just an ack if m is NULL. 466 */ 467static int 468ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta) 469{ 470 const priv_p priv = node->private; 471 struct ng_pptpgre_ackp *const a = &priv->ackp; 472 u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 473 struct greheader *const gre = (struct greheader *)buf; 474 int grelen, error; 475 476 /* Check if there's data */ 477 if (m != NULL) { 478 479 /* Is our transmit window full? */ 480 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck) 481 >= a->xmitWin) { 482 priv->stats.xmitDrops++; 483 NG_FREE_DATA(m, meta); 484 return (ENOBUFS); 485 } 486 487 /* Sanity check frame length */ 488 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 489 priv->stats.xmitTooBig++; 490 NG_FREE_DATA(m, meta); 491 return (EMSGSIZE); 492 } 493 } else 494 priv->stats.xmitLoneAcks++; 495 496 /* Build GRE header */ 497 ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE); 498 gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 499 gre->cid = htons(priv->conf.peerCid); 500 501 /* Include sequence number if packet contains any data */ 502 if (m != NULL) { 503 gre->hasSeq = 1; 504 a->timeSent[priv->xmitSeq - priv->recvAck] 505 = ng_pptpgre_time(node); 506 priv->xmitSeq++; 507 gre->data[0] = htonl(priv->xmitSeq); 508 } 509 510 /* Include acknowledgement (and stop send ack timer) if needed */ 511 if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) { 512 gre->hasAck = 1; 513 gre->data[gre->hasSeq] = htonl(priv->recvSeq); 514 priv->xmitAck = priv->recvSeq; 515 a->sackTimerPtr = NULL; /* "stop" timer */ 516 } 517 518 /* Prepend GRE header to outgoing frame */ 519 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 520 if (m == NULL) { 521 MGETHDR(m, M_DONTWAIT, MT_DATA); 522 if (m == NULL) { 523 priv->stats.memoryFailures++; 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 priv->stats.memoryFailures++; 534 NG_FREE_META(meta); 535 return (ENOBUFS); 536 } 537 } 538 bcopy(gre, mtod(m, u_char *), grelen); 539 540 /* Update stats */ 541 priv->stats.xmitPackets++; 542 priv->stats.xmitOctets += m->m_pkthdr.len; 543 544 /* Deliver packet */ 545 NG_SEND_DATA(error, priv->lower, m, meta); 546 547 /* Start receive ACK timer if data was sent and not already running */ 548 if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1) 549 ng_pptpgre_start_recv_ack_timer(node); 550 return (error); 551} 552 553/* 554 * Handle an incoming packet. The packet includes the IP header. 555 */ 556static int 557ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta) 558{ 559 const priv_p priv = node->private; 560 int iphlen, grelen, extralen; 561 struct greheader *gre; 562 struct ip *ip; 563 int error = 0; 564 565 /* Update stats */ 566 priv->stats.recvPackets++; 567 priv->stats.recvOctets += m->m_pkthdr.len; 568 569 /* Sanity check packet length */ 570 if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 571 priv->stats.recvRunts++; 572bad: 573 NG_FREE_DATA(m, meta); 574 return (EINVAL); 575 } 576 577 /* Safely pull up the complete IP+GRE headers */ 578 if (m->m_len < sizeof(*ip) + sizeof(*gre) 579 && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 580 priv->stats.memoryFailures++; 581 NG_FREE_META(meta); 582 return (ENOBUFS); 583 } 584 ip = mtod(m, struct ip *); 585 iphlen = ip->ip_hl << 2; 586 if (m->m_len < iphlen + sizeof(*gre)) { 587 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 588 priv->stats.memoryFailures++; 589 NG_FREE_META(meta); 590 return (ENOBUFS); 591 } 592 ip = mtod(m, struct ip *); 593 } 594 gre = (struct greheader *)((u_char *)ip + iphlen); 595 grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 596 if (m->m_pkthdr.len < iphlen + grelen) { 597 priv->stats.recvRunts++; 598 goto bad; 599 } 600 if (m->m_len < iphlen + grelen) { 601 if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 602 priv->stats.memoryFailures++; 603 NG_FREE_META(meta); 604 return (ENOBUFS); 605 } 606 ip = mtod(m, struct ip *); 607 gre = (struct greheader *)((u_char *)ip + iphlen); 608 } 609 610 /* Sanity check packet length and GRE header bits */ 611 extralen = m->m_pkthdr.len 612 - (iphlen + grelen + (u_int16_t)ntohs(gre->length)); 613 if (extralen < 0) { 614 priv->stats.recvBadGRE++; 615 goto bad; 616 } 617 if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) { 618 priv->stats.recvBadGRE++; 619 goto bad; 620 } 621 if (ntohs(gre->cid) != priv->conf.cid) { 622 priv->stats.recvBadCID++; 623 goto bad; 624 } 625 626 /* Look for peer ack */ 627 if (gre->hasAck) { 628 struct ng_pptpgre_ackp *const a = &priv->ackp; 629 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 630 const int index = ack - priv->recvAck - 1; 631 const long sample = ng_pptpgre_time(node) - a->timeSent[index]; 632 long diff; 633 634 /* Sanity check ack value */ 635 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) { 636 priv->stats.recvBadAcks++; 637 goto badAck; /* we never sent it! */ 638 } 639 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0) 640 goto badAck; /* ack already timed out */ 641 priv->recvAck = ack; 642 643 /* Update adaptive timeout stuff */ 644 diff = sample - a->rtt; 645 a->rtt += PPTP_ACK_ALPHA(diff); 646 if (diff < 0) 647 diff = -diff; 648 a->dev += PPTP_ACK_BETA(diff - a->dev); 649 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 650 if (a->ato > PPTP_MAX_TIMEOUT) 651 a->ato = PPTP_MAX_TIMEOUT; 652 if (a->ato < PPTP_MIN_TIMEOUT) 653 a->ato = PPTP_MIN_TIMEOUT; 654 655 /* Shift packet transmit times in our transmit window */ 656 ovbcopy(a->timeSent + index + 1, a->timeSent, 657 sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1))); 658 659 /* If we sent an entire window, increase window size by one */ 660 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0 661 && a->xmitWin < PPTP_XMIT_WIN) { 662 a->xmitWin++; 663 a->winAck = ack + a->xmitWin; 664 } 665 666 /* Stop/(re)start receive ACK timer as necessary */ 667 a->rackTimerPtr = NULL; 668 if (priv->recvAck != priv->xmitSeq) 669 ng_pptpgre_start_recv_ack_timer(node); 670 } 671badAck: 672 673 /* See if frame contains any data */ 674 if (gre->hasSeq) { 675 struct ng_pptpgre_ackp *const a = &priv->ackp; 676 const u_int32_t seq = ntohl(gre->data[0]); 677 678 /* Sanity check sequence number */ 679 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) { 680 if (seq == priv->recvSeq) 681 priv->stats.recvDuplicates++; 682 else 683 priv->stats.recvOutOfOrder++; 684 goto bad; /* out-of-order or dup */ 685 } 686 priv->recvSeq = seq; 687 688 /* We need to acknowledge this packet; do it soon... */ 689 if (a->sackTimerPtr == NULL) { 690 int maxWait; 691 692 /* Take 1/4 of the estimated round trip time */ 693 maxWait = (a->rtt >> 2); 694 695 /* If delayed ACK is disabled, send it now */ 696 if (!priv->conf.enableDelayedAck 697 || maxWait < PPTP_MIN_ACK_DELAY) 698 ng_pptpgre_xmit(node, NULL, NULL); 699 else { /* send the ack later */ 700 if (maxWait > PPTP_MAX_ACK_DELAY) 701 maxWait = PPTP_MAX_ACK_DELAY; 702 ng_pptpgre_start_send_ack_timer(node, maxWait); 703 } 704 } 705 706 /* Trim mbuf down to internal payload */ 707 m_adj(m, iphlen + grelen); 708 if (extralen > 0) 709 m_adj(m, -extralen); 710 711 /* Deliver frame to upper layers */ 712 NG_SEND_DATA(error, priv->upper, m, meta); 713 } else { 714 priv->stats.recvLoneAcks++; 715 NG_FREE_DATA(m, meta); /* no data to deliver */ 716 } 717 return (error); 718} 719 720/************************************************************************* 721 TIMER RELATED FUNCTIONS 722*************************************************************************/ 723 724/* 725 * Start a timer for the peer's acknowledging our oldest unacknowledged 726 * sequence number. If we get an ack for this sequence number before 727 * the timer goes off, we cancel the timer. Resets currently running 728 * recv ack timer, if any. 729 */ 730static void 731ng_pptpgre_start_recv_ack_timer(node_p node) 732{ 733 const priv_p priv = node->private; 734 struct ng_pptpgre_ackp *const a = &priv->ackp; 735 int remain, ticks; 736 737 /* Compute how long until oldest unack'd packet times out, 738 and reset the timer to that time. */ 739 KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __FUNCTION__)); 740 remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node); 741 if (remain < 0) 742 remain = 0; 743#ifdef DEBUG_RAT 744 a->timerLength = remain; 745 a->timerStart = ng_pptpgre_time(node); 746#endif 747 748 /* Start new timer */ 749 MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 750 if (a->rackTimerPtr == NULL) { 751 priv->stats.memoryFailures++; 752 return; /* XXX potential hang here */ 753 } 754 *a->rackTimerPtr = node; /* insures the correct timeout event */ 755 node->refs++; 756 757 /* Be conservative: timeout() can return up to 1 tick early */ 758 ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1; 759 a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout, 760 a->rackTimerPtr, ticks); 761} 762 763/* 764 * The peer has failed to acknowledge the oldest unacknowledged sequence 765 * number within the time allotted. Update our adaptive timeout parameters 766 * and reset/restart the recv ack timer. 767 */ 768static void 769ng_pptpgre_recv_ack_timeout(void *arg) 770{ 771 int s = splnet(); 772 const node_p node = *((node_p *)arg); 773 const priv_p priv = node->private; 774 struct ng_pptpgre_ackp *const a = &priv->ackp; 775 776 /* This complicated stuff is needed to avoid race conditions */ 777 FREE(arg, M_NETGRAPH); 778 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__)); 779 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */ 780 ng_unref(node); 781 splx(s); 782 return; 783 } 784 ng_unref(node); 785 if (arg != a->rackTimerPtr) { /* timer stopped race condition */ 786 splx(s); 787 return; 788 } 789 a->rackTimerPtr = NULL; 790 791 /* Update adaptive timeout stuff */ 792 priv->stats.recvAckTimeouts++; 793 a->rtt = PPTP_ACK_DELTA(a->rtt); 794 a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 795 if (a->ato > PPTP_MAX_TIMEOUT) 796 a->ato = PPTP_MAX_TIMEOUT; 797 if (a->ato < PPTP_MIN_TIMEOUT) 798 a->ato = PPTP_MIN_TIMEOUT; 799 800#ifdef DEBUG_RAT 801 log(LOG_DEBUG, 802 "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n", 803 (int)ng_pptpgre_time(node), priv->recvAck + 1, 804 (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato); 805#endif 806 807 /* Reset ack and sliding window */ 808 priv->recvAck = priv->xmitSeq; /* pretend we got the ack */ 809 a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 810 a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 811 splx(s); 812} 813 814/* 815 * Start the send ack timer. This assumes the timer is not 816 * already running. 817 */ 818static void 819ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout) 820{ 821 const priv_p priv = node->private; 822 struct ng_pptpgre_ackp *const a = &priv->ackp; 823 int ticks; 824 825 /* Start new timer */ 826 KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __FUNCTION__)); 827 MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT); 828 if (a->sackTimerPtr == NULL) { 829 priv->stats.memoryFailures++; 830 return; /* XXX potential hang here */ 831 } 832 *a->sackTimerPtr = node; 833 node->refs++; 834 835 /* Be conservative: timeout() can return up to 1 tick early */ 836 ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE); 837 a->sackTimer = timeout(ng_pptpgre_send_ack_timeout, 838 a->sackTimerPtr, ticks); 839} 840 841/* 842 * We've waited as long as we're willing to wait before sending an 843 * acknowledgement to the peer for received frames. We had hoped to 844 * be able to piggy back our acknowledgement on an outgoing data frame, 845 * but apparently there haven't been any since. So send the ack now. 846 */ 847static void 848ng_pptpgre_send_ack_timeout(void *arg) 849{ 850 int s = splnet(); 851 const node_p node = *((node_p *)arg); 852 const priv_p priv = node->private; 853 struct ng_pptpgre_ackp *const a = &priv->ackp; 854 855 /* This complicated stuff is needed to avoid race conditions */ 856 FREE(arg, M_NETGRAPH); 857 KASSERT(node->refs > 0, ("%s: no refs", __FUNCTION__)); 858 if ((node->flags & NG_INVALID) != 0) { /* shutdown race condition */ 859 ng_unref(node); 860 splx(s); 861 return; 862 } 863 ng_unref(node); 864 if (a->sackTimerPtr != arg) { /* timer stopped race condition */ 865 splx(s); 866 return; 867 } 868 a->sackTimerPtr = NULL; 869 870 /* Send a frame with an ack but no payload */ 871 ng_pptpgre_xmit(node, NULL, NULL); 872 splx(s); 873} 874 875/************************************************************************* 876 MISC FUNCTIONS 877*************************************************************************/ 878 879/* 880 * Reset state 881 */ 882static void 883ng_pptpgre_reset(node_p node) 884{ 885 const priv_p priv = node->private; 886 struct ng_pptpgre_ackp *const a = &priv->ackp; 887 888 /* Reset adaptive timeout state */ 889 a->ato = PPTP_MAX_TIMEOUT; 890 a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 891 if (a->rtt < PPTP_MIN_RTT) 892 a->rtt = PPTP_MIN_RTT; 893 a->dev = 0; 894 a->xmitWin = (priv->conf.recvWin + 1) / 2; 895 if (a->xmitWin < 2) /* often the first packet is lost */ 896 a->xmitWin = 2; /* because the peer isn't ready */ 897 if (a->xmitWin > PPTP_XMIT_WIN) 898 a->xmitWin = PPTP_XMIT_WIN; 899 a->winAck = a->xmitWin; 900 901 /* Reset sequence numbers */ 902 priv->recvSeq = ~0; 903 priv->recvAck = ~0; 904 priv->xmitSeq = ~0; 905 priv->xmitAck = ~0; 906 907 /* Reset start time */ 908 getmicrouptime(&priv->startTime); 909 910 /* Reset stats */ 911 bzero(&priv->stats, sizeof(priv->stats)); 912 913 /* "Stop" timers */ 914 a->sackTimerPtr = NULL; 915 a->rackTimerPtr = NULL; 916} 917 918/* 919 * Return the current time scaled & translated to our internally used format. 920 */ 921static pptptime_t 922ng_pptpgre_time(node_p node) 923{ 924 const priv_p priv = node->private; 925 struct timeval tv; 926 pptptime_t t; 927 928 microuptime(&tv); 929 if (tv.tv_sec < priv->startTime.tv_sec 930 || (tv.tv_sec == priv->startTime.tv_sec 931 && tv.tv_usec < priv->startTime.tv_usec)) 932 return (0); 933 timevalsub(&tv, &priv->startTime); 934 t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE; 935 t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE); 936 return(t); 937} 938
|