154331Sarchie/* 254331Sarchie * ng_pptpgre.c 3139823Simp */ 4139823Simp 5139823Simp/*- 654331Sarchie * Copyright (c) 1996-1999 Whistle Communications, Inc. 754331Sarchie * All rights reserved. 854331Sarchie * 954331Sarchie * Subject to the following obligations and disclaimer of warranty, use and 1054331Sarchie * redistribution of this software, in source or object code forms, with or 1154331Sarchie * without modifications are expressly permitted by Whistle Communications; 1254331Sarchie * provided, however, that: 1354331Sarchie * 1. Any and all reproductions of the source or object code must include the 1454331Sarchie * copyright notice above and the following disclaimer of warranties; and 1554331Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1654331Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1754331Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1854331Sarchie * such appears in the above copyright notice or in the software. 1954331Sarchie * 2054331Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2154331Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2254331Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2354331Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2454331Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2554331Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2654331Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2754331Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2854331Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2954331Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3054331Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3154331Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3254331Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3354331Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3454331Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3554331Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3654331Sarchie * OF SUCH DAMAGE. 3754331Sarchie * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3954331Sarchie * 4054331Sarchie * $FreeBSD$ 4154331Sarchie * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $ 4254331Sarchie */ 4354331Sarchie 4454331Sarchie/* 4554331Sarchie * PPTP/GRE netgraph node type. 4654331Sarchie * 4754331Sarchie * This node type does the GRE encapsulation as specified for the PPTP 4854331Sarchie * protocol (RFC 2637, section 4). This includes sequencing and 4954331Sarchie * retransmission of frames, but not the actual packet delivery nor 5054331Sarchie * any of the TCP control stream protocol. 5154331Sarchie * 5254331Sarchie * The "upper" hook of this node is suitable for attaching to a "ppp" 5354331Sarchie * node link hook. The "lower" hook of this node is suitable for attaching 5454331Sarchie * to a "ksocket" node on hook "inet/raw/gre". 5554331Sarchie */ 5654331Sarchie 5754331Sarchie#include <sys/param.h> 5854331Sarchie#include <sys/systm.h> 5954331Sarchie#include <sys/kernel.h> 6054331Sarchie#include <sys/time.h> 61149615Sglebius#include <sys/lock.h> 62149615Sglebius#include <sys/malloc.h> 6354331Sarchie#include <sys/mbuf.h> 64149615Sglebius#include <sys/mutex.h> 65206050Smav#include <sys/endian.h> 6654331Sarchie#include <sys/errno.h> 6754331Sarchie 6854331Sarchie#include <netinet/in.h> 6954331Sarchie#include <netinet/in_systm.h> 7054331Sarchie#include <netinet/ip.h> 7154331Sarchie 7254331Sarchie#include <netgraph/ng_message.h> 7354331Sarchie#include <netgraph/netgraph.h> 7454331Sarchie#include <netgraph/ng_parse.h> 7554331Sarchie#include <netgraph/ng_pptpgre.h> 7654331Sarchie 7754331Sarchie/* GRE packet format, as used by PPTP */ 7854331Sarchiestruct greheader { 7954331Sarchie#if BYTE_ORDER == LITTLE_ENDIAN 8054331Sarchie u_char recursion:3; /* recursion control */ 8154331Sarchie u_char ssr:1; /* strict source route */ 8254331Sarchie u_char hasSeq:1; /* sequence number present */ 8354331Sarchie u_char hasKey:1; /* key present */ 8454331Sarchie u_char hasRoute:1; /* routing present */ 8554331Sarchie u_char hasSum:1; /* checksum present */ 8654331Sarchie u_char vers:3; /* version */ 8754331Sarchie u_char flags:4; /* flags */ 8854331Sarchie u_char hasAck:1; /* acknowlege number present */ 8954331Sarchie#elif BYTE_ORDER == BIG_ENDIAN 9054331Sarchie u_char hasSum:1; /* checksum present */ 9154331Sarchie u_char hasRoute:1; /* routing present */ 9254331Sarchie u_char hasKey:1; /* key present */ 9354331Sarchie u_char hasSeq:1; /* sequence number present */ 9454331Sarchie u_char ssr:1; /* strict source route */ 9554331Sarchie u_char recursion:3; /* recursion control */ 9654331Sarchie u_char hasAck:1; /* acknowlege number present */ 9754331Sarchie u_char flags:4; /* flags */ 9854331Sarchie u_char vers:3; /* version */ 9954331Sarchie#else 10054331Sarchie#error BYTE_ORDER is not defined properly 10154331Sarchie#endif 10254331Sarchie u_int16_t proto; /* protocol (ethertype) */ 10354331Sarchie u_int16_t length; /* payload length */ 10454331Sarchie u_int16_t cid; /* call id */ 10554331Sarchie u_int32_t data[0]; /* opt. seq, ack, then data */ 10654331Sarchie}; 10754331Sarchie 10854331Sarchie/* The PPTP protocol ID used in the GRE 'proto' field */ 10954331Sarchie#define PPTP_GRE_PROTO 0x880b 11054331Sarchie 11154331Sarchie/* Bits that must be set a certain way in all PPTP/GRE packets */ 11254331Sarchie#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO) 11354331Sarchie#define PPTP_INIT_MASK 0xef7fffff 11454331Sarchie 11554331Sarchie/* Min and max packet length */ 11654331Sarchie#define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8) 11754331Sarchie 11854331Sarchie/* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */ 119177646Smav#define PPTP_TIME_SCALE 1024 /* milliseconds */ 12063822Sarchietypedef u_int64_t pptptime_t; 12154331Sarchie 12254331Sarchie/* Acknowledgment timeout parameters and functions */ 12362222Sarchie#define PPTP_XMIT_WIN 16 /* max xmit window */ 12494667Sarchie#define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 83) /* 12 milliseconds */ 125134865Sglebius#define PPTP_MAX_TIMEOUT (3 * PPTP_TIME_SCALE) /* 3 seconds */ 12654331Sarchie 12763852Sarchie/* When we recieve a packet, we wait to see if there's an outgoing packet 12863852Sarchie we can piggy-back the ACK off of. These parameters determine the mimimum 12963852Sarchie and maxmimum length of time we're willing to wait in order to do that. 13063852Sarchie These have no effect unless "enableDelayedAck" is turned on. */ 13163852Sarchie#define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500) /* 2 milliseconds */ 13263852Sarchie#define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2) /* 500 milliseconds */ 13363852Sarchie 13462222Sarchie/* See RFC 2637 section 4.4 */ 135166424Sglebius#define PPTP_ACK_ALPHA(x) (((x) + 4) >> 3) /* alpha = 0.125 */ 136166424Sglebius#define PPTP_ACK_BETA(x) (((x) + 2) >> 2) /* beta = 0.25 */ 13754331Sarchie#define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 13854331Sarchie#define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 13954331Sarchie 14060009Sarchie#define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y)) 14160009Sarchie 142177587Smav#define SESSHASHSIZE 0x0020 143177587Smav#define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1)) 144177587Smav 14554331Sarchie/* We keep packet retransmit and acknowlegement state in this struct */ 146177587Smavstruct ng_pptpgre_sess { 147177587Smav node_p node; /* this node pointer */ 148177587Smav hook_p hook; /* hook to upper layers */ 149177587Smav struct ng_pptpgre_conf conf; /* configuration info */ 150177587Smav struct mtx mtx; /* session mutex */ 151177587Smav u_int32_t recvSeq; /* last seq # we rcv'd */ 152177587Smav u_int32_t xmitSeq; /* last seq # we sent */ 153177587Smav u_int32_t recvAck; /* last seq # peer ack'd */ 154177587Smav u_int32_t xmitAck; /* last seq # we ack'd */ 15554331Sarchie int32_t ato; /* adaptive time-out value */ 15654331Sarchie int32_t rtt; /* round trip time estimate */ 15754331Sarchie int32_t dev; /* deviation estimate */ 15854331Sarchie u_int16_t xmitWin; /* size of xmit window */ 15994667Sarchie struct callout sackTimer; /* send ack timer */ 16094667Sarchie struct callout rackTimer; /* recv ack timer */ 16162129Sarchie u_int32_t winAck; /* seq when xmitWin will grow */ 16254331Sarchie pptptime_t timeSent[PPTP_XMIT_WIN]; 163177587Smav LIST_ENTRY(ng_pptpgre_sess) sessions; 16454331Sarchie}; 165177587Smavtypedef struct ng_pptpgre_sess *hpriv_p; 16654331Sarchie 16754331Sarchie/* Node private data */ 16854331Sarchiestruct ng_pptpgre_private { 16954331Sarchie hook_p upper; /* hook to upper layers */ 17054331Sarchie hook_p lower; /* hook to lower layers */ 171177587Smav struct ng_pptpgre_sess uppersess; /* default session for compat */ 172177587Smav LIST_HEAD(, ng_pptpgre_sess) sesshash[SESSHASHSIZE]; 17360009Sarchie struct ng_pptpgre_stats stats; /* node statistics */ 17454331Sarchie}; 17554331Sarchietypedef struct ng_pptpgre_private *priv_p; 17654331Sarchie 17754331Sarchie/* Netgraph node methods */ 17854331Sarchiestatic ng_constructor_t ng_pptpgre_constructor; 17954331Sarchiestatic ng_rcvmsg_t ng_pptpgre_rcvmsg; 18070700Sjulianstatic ng_shutdown_t ng_pptpgre_shutdown; 18154331Sarchiestatic ng_newhook_t ng_pptpgre_newhook; 18254331Sarchiestatic ng_rcvdata_t ng_pptpgre_rcvdata; 183177587Smavstatic ng_rcvdata_t ng_pptpgre_rcvdata_lower; 18454331Sarchiestatic ng_disconnect_t ng_pptpgre_disconnect; 18554331Sarchie 18654331Sarchie/* Helper functions */ 187177587Smavstatic int ng_pptpgre_xmit(hpriv_p hpriv, item_p item); 188177646Smavstatic void ng_pptpgre_start_send_ack_timer(hpriv_p hpriv); 189177587Smavstatic void ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv); 190138618Sglebiusstatic void ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, 191138618Sglebius void *arg1, int arg2); 192138618Sglebiusstatic void ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, 193138618Sglebius void *arg1, int arg2); 194177587Smavstatic hpriv_p ng_pptpgre_find_session(priv_p privp, u_int16_t cid); 195177587Smavstatic void ng_pptpgre_reset(hpriv_p hpriv); 196177587Smavstatic pptptime_t ng_pptpgre_time(void); 19754331Sarchie 19854331Sarchie/* Parse type for struct ng_pptpgre_conf */ 19997685Sarchiestatic const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[] 20097685Sarchie = NG_PPTPGRE_CONF_TYPE_INFO; 20154331Sarchiestatic const struct ng_parse_type ng_pptpgre_conf_type = { 20254331Sarchie &ng_parse_struct_type, 20397685Sarchie &ng_pptpgre_conf_type_fields, 20454331Sarchie}; 20554331Sarchie 20660009Sarchie/* Parse type for struct ng_pptpgre_stats */ 20797685Sarchiestatic const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[] 20897685Sarchie = NG_PPTPGRE_STATS_TYPE_INFO; 20960009Sarchiestatic const struct ng_parse_type ng_pptp_stats_type = { 21060009Sarchie &ng_parse_struct_type, 21197685Sarchie &ng_pptpgre_stats_type_fields 21260009Sarchie}; 21360009Sarchie 21454331Sarchie/* List of commands and how to convert arguments to/from ASCII */ 21554331Sarchiestatic const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 21654331Sarchie { 21754331Sarchie NGM_PPTPGRE_COOKIE, 21854331Sarchie NGM_PPTPGRE_SET_CONFIG, 21954331Sarchie "setconfig", 22054331Sarchie &ng_pptpgre_conf_type, 22154331Sarchie NULL 22254331Sarchie }, 22354331Sarchie { 22454331Sarchie NGM_PPTPGRE_COOKIE, 22554331Sarchie NGM_PPTPGRE_GET_CONFIG, 22654331Sarchie "getconfig", 227177587Smav &ng_parse_hint16_type, 22854331Sarchie &ng_pptpgre_conf_type 22954331Sarchie }, 23060009Sarchie { 23160009Sarchie NGM_PPTPGRE_COOKIE, 23260009Sarchie NGM_PPTPGRE_GET_STATS, 23360009Sarchie "getstats", 23460009Sarchie NULL, 23560009Sarchie &ng_pptp_stats_type 23660009Sarchie }, 23760009Sarchie { 23860009Sarchie NGM_PPTPGRE_COOKIE, 23960009Sarchie NGM_PPTPGRE_CLR_STATS, 24060009Sarchie "clrstats", 24160009Sarchie NULL, 24260009Sarchie NULL 24360009Sarchie }, 24460009Sarchie { 24560009Sarchie NGM_PPTPGRE_COOKIE, 24660009Sarchie NGM_PPTPGRE_GETCLR_STATS, 24760009Sarchie "getclrstats", 24860009Sarchie NULL, 24960009Sarchie &ng_pptp_stats_type 25060009Sarchie }, 25154331Sarchie { 0 } 25254331Sarchie}; 25354331Sarchie 25454331Sarchie/* Node type descriptor */ 25554331Sarchiestatic struct ng_type ng_pptpgre_typestruct = { 256129823Sjulian .version = NG_ABI_VERSION, 257129823Sjulian .name = NG_PPTPGRE_NODE_TYPE, 258129823Sjulian .constructor = ng_pptpgre_constructor, 259129823Sjulian .rcvmsg = ng_pptpgre_rcvmsg, 260129823Sjulian .shutdown = ng_pptpgre_shutdown, 261129823Sjulian .newhook = ng_pptpgre_newhook, 262129823Sjulian .rcvdata = ng_pptpgre_rcvdata, 263129823Sjulian .disconnect = ng_pptpgre_disconnect, 264129823Sjulian .cmdlist = ng_pptpgre_cmdlist, 26554331Sarchie}; 26654331SarchieNETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 26754331Sarchie 26854331Sarchie#define ERROUT(x) do { error = (x); goto done; } while (0) 26954331Sarchie 27054331Sarchie/************************************************************************ 27154331Sarchie NETGRAPH NODE STUFF 27254331Sarchie ************************************************************************/ 27354331Sarchie 27454331Sarchie/* 27554331Sarchie * Node type constructor 27654331Sarchie */ 27754331Sarchiestatic int 27870700Sjulianng_pptpgre_constructor(node_p node) 27954331Sarchie{ 28054331Sarchie priv_p priv; 281177587Smav int i; 28254331Sarchie 28354331Sarchie /* Allocate private structure */ 284220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 28554331Sarchie 28670784Sjulian NG_NODE_SET_PRIVATE(node, priv); 28754331Sarchie 28854331Sarchie /* Initialize state */ 289177587Smav mtx_init(&priv->uppersess.mtx, "ng_pptp", NULL, MTX_DEF); 290177587Smav ng_callout_init(&priv->uppersess.sackTimer); 291177587Smav ng_callout_init(&priv->uppersess.rackTimer); 292177587Smav priv->uppersess.node = node; 29354331Sarchie 294177587Smav for (i = 0; i < SESSHASHSIZE; i++) 295177587Smav LIST_INIT(&priv->sesshash[i]); 296177587Smav 297177587Smav LIST_INSERT_HEAD(&priv->sesshash[0], &priv->uppersess, sessions); 298177587Smav 29954331Sarchie /* Done */ 30054331Sarchie return (0); 30154331Sarchie} 30254331Sarchie 30354331Sarchie/* 30454331Sarchie * Give our OK for a hook to be added. 30554331Sarchie */ 30654331Sarchiestatic int 30754331Sarchieng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 30854331Sarchie{ 30970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 31054331Sarchie 31154331Sarchie /* Check hook name */ 312177587Smav if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) { 313177587Smav priv->upper = hook; 314177587Smav priv->uppersess.hook = hook; 315177587Smav NG_HOOK_SET_PRIVATE(hook, &priv->uppersess); 316177587Smav } else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) { 317177587Smav priv->lower = hook; 318177587Smav NG_HOOK_SET_RCVDATA(hook, ng_pptpgre_rcvdata_lower); 319177587Smav } else { 320177587Smav static const char hexdig[16] = "0123456789abcdef"; 321177587Smav const char *hex; 322177587Smav hpriv_p hpriv; 323177587Smav int i, j; 324177587Smav uint16_t cid, hash; 32554331Sarchie 326177587Smav /* Parse hook name to get session ID */ 327177587Smav if (strncmp(name, NG_PPTPGRE_HOOK_SESSION_P, 328177587Smav sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1) != 0) 329177587Smav return (EINVAL); 330177587Smav hex = name + sizeof(NG_PPTPGRE_HOOK_SESSION_P) - 1; 331177587Smav for (cid = i = 0; i < 4; i++) { 332177587Smav for (j = 0; j < 16 && hex[i] != hexdig[j]; j++); 333177587Smav if (j == 16) 334177587Smav return (EINVAL); 335177587Smav cid = (cid << 4) | j; 336177587Smav } 337177587Smav if (hex[i] != '\0') 338177587Smav return (EINVAL); 33954331Sarchie 340177587Smav hpriv = malloc(sizeof(*hpriv), M_NETGRAPH, M_NOWAIT | M_ZERO); 341177587Smav if (hpriv == NULL) 342177587Smav return (ENOMEM); 343177587Smav 344177587Smav /* Initialize state */ 345177587Smav mtx_init(&hpriv->mtx, "ng_pptp", NULL, MTX_DEF); 346177587Smav ng_callout_init(&hpriv->sackTimer); 347177587Smav ng_callout_init(&hpriv->rackTimer); 348177587Smav hpriv->conf.cid = cid; 349177587Smav hpriv->node = node; 350177587Smav hpriv->hook = hook; 351177587Smav NG_HOOK_SET_PRIVATE(hook, hpriv); 352177587Smav 353177587Smav hash = SESSHASH(cid); 354177587Smav LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions); 355177587Smav } 356177587Smav 35754331Sarchie return (0); 35854331Sarchie} 35954331Sarchie 36054331Sarchie/* 36154331Sarchie * Receive a control message. 36254331Sarchie */ 36354331Sarchiestatic int 36470700Sjulianng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook) 36554331Sarchie{ 36670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 36754331Sarchie struct ng_mesg *resp = NULL; 36854331Sarchie int error = 0; 36970700Sjulian struct ng_mesg *msg; 37054331Sarchie 37170700Sjulian NGI_GET_MSG(item, msg); 37254331Sarchie switch (msg->header.typecookie) { 37354331Sarchie case NGM_PPTPGRE_COOKIE: 37454331Sarchie switch (msg->header.cmd) { 37554331Sarchie case NGM_PPTPGRE_SET_CONFIG: 37654331Sarchie { 37754331Sarchie struct ng_pptpgre_conf *const newConf = 37854331Sarchie (struct ng_pptpgre_conf *) msg->data; 379177587Smav hpriv_p hpriv; 380177587Smav uint16_t hash; 38154331Sarchie 38254331Sarchie /* Check for invalid or illegal config */ 38354331Sarchie if (msg->header.arglen != sizeof(*newConf)) 38454331Sarchie ERROUT(EINVAL); 385177587Smav /* Try to find session by cid. */ 386177587Smav hpriv = ng_pptpgre_find_session(priv, newConf->cid); 387177587Smav /* If not present - use upper. */ 388177587Smav if (hpriv == NULL) { 389177587Smav hpriv = &priv->uppersess; 390177587Smav LIST_REMOVE(hpriv, sessions); 391177587Smav hash = SESSHASH(newConf->cid); 392177587Smav LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, 393177587Smav sessions); 394177587Smav } 395177587Smav ng_pptpgre_reset(hpriv); /* reset on configure */ 396177587Smav hpriv->conf = *newConf; 39754331Sarchie break; 39854331Sarchie } 39954331Sarchie case NGM_PPTPGRE_GET_CONFIG: 400177587Smav { 401177587Smav hpriv_p hpriv; 402177587Smav 403177587Smav if (msg->header.arglen == 2) { 404177587Smav /* Try to find session by cid. */ 405177587Smav hpriv = ng_pptpgre_find_session(priv, 406177587Smav *((uint16_t *)msg->data)); 407177587Smav if (hpriv == NULL) 408177587Smav ERROUT(EINVAL); 409177587Smav } else if (msg->header.arglen == 0) { 410177587Smav /* Use upper. */ 411177587Smav hpriv = &priv->uppersess; 412177587Smav } else 413177587Smav ERROUT(EINVAL); 414177587Smav NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT); 41554331Sarchie if (resp == NULL) 41654331Sarchie ERROUT(ENOMEM); 417177587Smav bcopy(&hpriv->conf, resp->data, sizeof(hpriv->conf)); 41854331Sarchie break; 419177587Smav } 42060009Sarchie case NGM_PPTPGRE_GET_STATS: 42160009Sarchie case NGM_PPTPGRE_CLR_STATS: 42260009Sarchie case NGM_PPTPGRE_GETCLR_STATS: 42360009Sarchie { 42460009Sarchie if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) { 42560009Sarchie NG_MKRESPONSE(resp, msg, 42660009Sarchie sizeof(priv->stats), M_NOWAIT); 42760009Sarchie if (resp == NULL) 42860009Sarchie ERROUT(ENOMEM); 42960009Sarchie bcopy(&priv->stats, 43060009Sarchie resp->data, sizeof(priv->stats)); 43160009Sarchie } 43260009Sarchie if (msg->header.cmd != NGM_PPTPGRE_GET_STATS) 43360009Sarchie bzero(&priv->stats, sizeof(priv->stats)); 43460009Sarchie break; 43560009Sarchie } 43654331Sarchie default: 43754331Sarchie error = EINVAL; 43854331Sarchie break; 43954331Sarchie } 44054331Sarchie break; 44154331Sarchie default: 44254331Sarchie error = EINVAL; 44354331Sarchie break; 44454331Sarchie } 44570159Sjuliandone: 44670700Sjulian NG_RESPOND_MSG(error, node, item, resp); 44770700Sjulian NG_FREE_MSG(msg); 44854331Sarchie return (error); 44954331Sarchie} 45054331Sarchie 45154331Sarchie/* 45254331Sarchie * Receive incoming data on a hook. 45354331Sarchie */ 45454331Sarchiestatic int 45570700Sjulianng_pptpgre_rcvdata(hook_p hook, item_p item) 45654331Sarchie{ 457177587Smav const hpriv_p hpriv = NG_HOOK_PRIVATE(hook); 458149615Sglebius int rval; 45954331Sarchie 46054331Sarchie /* If not configured, reject */ 461177587Smav if (!hpriv->conf.enabled) { 46270700Sjulian NG_FREE_ITEM(item); 46354331Sarchie return (ENXIO); 46454331Sarchie } 46554331Sarchie 466177587Smav mtx_lock(&hpriv->mtx); 467149615Sglebius 468177587Smav rval = ng_pptpgre_xmit(hpriv, item); 469149615Sglebius 470177587Smav mtx_assert(&hpriv->mtx, MA_NOTOWNED); 471149615Sglebius 472149615Sglebius return (rval); 47354331Sarchie} 47454331Sarchie 47554331Sarchie/* 476177587Smav * Hook disconnection 47754331Sarchie */ 47854331Sarchiestatic int 479177587Smavng_pptpgre_disconnect(hook_p hook) 48054331Sarchie{ 481177587Smav const node_p node = NG_HOOK_NODE(hook); 48270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 483177587Smav const hpriv_p hpriv = NG_HOOK_PRIVATE(hook); 48454331Sarchie 485177587Smav /* Zero out hook pointer */ 486177587Smav if (hook == priv->upper) { 487177587Smav priv->upper = NULL; 488177587Smav priv->uppersess.hook = NULL; 489177587Smav } else if (hook == priv->lower) { 490177587Smav priv->lower = NULL; 491177587Smav } else { 492177587Smav /* Reset node (stops timers) */ 493177587Smav ng_pptpgre_reset(hpriv); 49454331Sarchie 495177587Smav LIST_REMOVE(hpriv, sessions); 496177587Smav mtx_destroy(&hpriv->mtx); 497177587Smav free(hpriv, M_NETGRAPH); 498177587Smav } 499149615Sglebius 500177587Smav /* Go away if no longer connected to anything */ 501177587Smav if ((NG_NODE_NUMHOOKS(node) == 0) 502177587Smav && (NG_NODE_IS_VALID(node))) 503177587Smav ng_rmnode_self(node); 50454331Sarchie return (0); 50554331Sarchie} 50654331Sarchie 50754331Sarchie/* 508177587Smav * Destroy node 50954331Sarchie */ 51054331Sarchiestatic int 511177587Smavng_pptpgre_shutdown(node_p node) 51254331Sarchie{ 51370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 51454331Sarchie 515177587Smav /* Reset node (stops timers) */ 516177587Smav ng_pptpgre_reset(&priv->uppersess); 51754331Sarchie 518177587Smav LIST_REMOVE(&priv->uppersess, sessions); 519177587Smav mtx_destroy(&priv->uppersess.mtx); 520177587Smav 521184205Sdes free(priv, M_NETGRAPH); 522177587Smav 523177587Smav /* Decrement ref count */ 524177587Smav NG_NODE_UNREF(node); 52554331Sarchie return (0); 52654331Sarchie} 52754331Sarchie 52854331Sarchie/************************************************************************* 52954331Sarchie TRANSMIT AND RECEIVE FUNCTIONS 53054331Sarchie*************************************************************************/ 53154331Sarchie 53254331Sarchie/* 53354331Sarchie * Transmit an outgoing frame, or just an ack if m is NULL. 53454331Sarchie */ 53554331Sarchiestatic int 536177587Smavng_pptpgre_xmit(hpriv_p hpriv, item_p item) 53754331Sarchie{ 538177587Smav const priv_p priv = NG_NODE_PRIVATE(hpriv->node); 53954331Sarchie u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 54054331Sarchie struct greheader *const gre = (struct greheader *)buf; 54154331Sarchie int grelen, error; 54270700Sjulian struct mbuf *m; 54354331Sarchie 544177587Smav mtx_assert(&hpriv->mtx, MA_OWNED); 545149880Sglebius 54670700Sjulian if (item) { 54770700Sjulian NGI_GET_M(item, m); 54870700Sjulian } else { 54970700Sjulian m = NULL; 55070700Sjulian } 55160009Sarchie /* Check if there's data */ 55260009Sarchie if (m != NULL) { 55354331Sarchie 554128657Sarchie /* Check if windowing is enabled */ 555177587Smav if (hpriv->conf.enableWindowing) { 556128657Sarchie /* Is our transmit window full? */ 557177587Smav if ((u_int32_t)PPTP_SEQ_DIFF(hpriv->xmitSeq, 558177587Smav hpriv->recvAck) >= hpriv->xmitWin) { 559128657Sarchie priv->stats.xmitDrops++; 560149880Sglebius ERROUT(ENOBUFS); 561128657Sarchie } 56260009Sarchie } 56354331Sarchie 56460009Sarchie /* Sanity check frame length */ 565239007Smav if (m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 56660009Sarchie priv->stats.xmitTooBig++; 567149880Sglebius ERROUT(EMSGSIZE); 56860009Sarchie } 56970700Sjulian } else { 57060009Sarchie priv->stats.xmitLoneAcks++; 57170700Sjulian } 57260009Sarchie 57354331Sarchie /* Build GRE header */ 574206050Smav be32enc(gre, PPTP_INIT_VALUE); 575206050Smav be16enc(&gre->length, (m != NULL) ? m->m_pkthdr.len : 0); 576206050Smav be16enc(&gre->cid, hpriv->conf.peerCid); 57754331Sarchie 57854331Sarchie /* Include sequence number if packet contains any data */ 57954331Sarchie if (m != NULL) { 58054331Sarchie gre->hasSeq = 1; 581177587Smav if (hpriv->conf.enableWindowing) { 582177587Smav hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck] 583177587Smav = ng_pptpgre_time(); 584128657Sarchie } 585177587Smav hpriv->xmitSeq++; 586206050Smav be32enc(&gre->data[0], hpriv->xmitSeq); 58754331Sarchie } 58854331Sarchie 58954331Sarchie /* Include acknowledgement (and stop send ack timer) if needed */ 590177587Smav if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) { 59154331Sarchie gre->hasAck = 1; 592206050Smav be32enc(&gre->data[gre->hasSeq], hpriv->recvSeq); 593177587Smav hpriv->xmitAck = hpriv->recvSeq; 594177646Smav if (hpriv->conf.enableDelayedAck) 595177646Smav ng_uncallout(&hpriv->sackTimer, hpriv->node); 59654331Sarchie } 59754331Sarchie 59854331Sarchie /* Prepend GRE header to outgoing frame */ 59954331Sarchie grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 60054331Sarchie if (m == NULL) { 601243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 60254331Sarchie if (m == NULL) { 60363822Sarchie priv->stats.memoryFailures++; 604149880Sglebius ERROUT(ENOBUFS); 60554331Sarchie } 60654331Sarchie m->m_len = m->m_pkthdr.len = grelen; 60754331Sarchie m->m_pkthdr.rcvif = NULL; 60854331Sarchie } else { 609243882Sglebius M_PREPEND(m, grelen, M_NOWAIT); 61054331Sarchie if (m == NULL || (m->m_len < grelen 61154331Sarchie && (m = m_pullup(m, grelen)) == NULL)) { 61263822Sarchie priv->stats.memoryFailures++; 613149880Sglebius ERROUT(ENOBUFS); 61454331Sarchie } 61554331Sarchie } 61654331Sarchie bcopy(gre, mtod(m, u_char *), grelen); 61754331Sarchie 61860009Sarchie /* Update stats */ 61960009Sarchie priv->stats.xmitPackets++; 62060009Sarchie priv->stats.xmitOctets += m->m_pkthdr.len; 62160009Sarchie 622149880Sglebius /* 623149880Sglebius * XXX: we should reset timer only after an item has been sent 624149880Sglebius * successfully. 625149880Sglebius */ 626177587Smav if (hpriv->conf.enableWindowing && 627177587Smav gre->hasSeq && hpriv->xmitSeq == hpriv->recvAck + 1) 628177587Smav ng_pptpgre_start_recv_ack_timer(hpriv); 629149880Sglebius 630177587Smav mtx_unlock(&hpriv->mtx); 631149880Sglebius 63254331Sarchie /* Deliver packet */ 63370700Sjulian if (item) { 63470700Sjulian NG_FWD_NEW_DATA(error, item, priv->lower, m); 63570700Sjulian } else { 63670700Sjulian NG_SEND_DATA_ONLY(error, priv->lower, m); 63770700Sjulian } 63863822Sarchie 639149880Sglebius return (error); 64070700Sjulian 641149880Sglebiusdone: 642177587Smav mtx_unlock(&hpriv->mtx); 643149880Sglebius NG_FREE_M(m); 644149880Sglebius if (item) 645149880Sglebius NG_FREE_ITEM(item); 64654331Sarchie return (error); 64754331Sarchie} 64854331Sarchie 64954331Sarchie/* 65054331Sarchie * Handle an incoming packet. The packet includes the IP header. 65154331Sarchie */ 65254331Sarchiestatic int 653177587Smavng_pptpgre_rcvdata_lower(hook_p hook, item_p item) 65454331Sarchie{ 655177587Smav hpriv_p hpriv; 656177587Smav node_p node = NG_HOOK_NODE(hook); 65770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 65854331Sarchie int iphlen, grelen, extralen; 65997897Sarchie const struct greheader *gre; 66097897Sarchie const struct ip *ip; 66154331Sarchie int error = 0; 66270700Sjulian struct mbuf *m; 66354331Sarchie 66470700Sjulian NGI_GET_M(item, m); 66560009Sarchie /* Update stats */ 66660009Sarchie priv->stats.recvPackets++; 66760009Sarchie priv->stats.recvOctets += m->m_pkthdr.len; 66860009Sarchie 66954331Sarchie /* Sanity check packet length */ 67054331Sarchie if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 67160009Sarchie priv->stats.recvRunts++; 672149880Sglebius ERROUT(EINVAL); 67354331Sarchie } 67454331Sarchie 67554331Sarchie /* Safely pull up the complete IP+GRE headers */ 67654331Sarchie if (m->m_len < sizeof(*ip) + sizeof(*gre) 67754331Sarchie && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 67863822Sarchie priv->stats.memoryFailures++; 679149880Sglebius ERROUT(ENOBUFS); 68054331Sarchie } 68197897Sarchie ip = mtod(m, const struct ip *); 68254331Sarchie iphlen = ip->ip_hl << 2; 68354331Sarchie if (m->m_len < iphlen + sizeof(*gre)) { 68454331Sarchie if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 68563822Sarchie priv->stats.memoryFailures++; 686149880Sglebius ERROUT(ENOBUFS); 68754331Sarchie } 68897897Sarchie ip = mtod(m, const struct ip *); 68954331Sarchie } 69097897Sarchie gre = (const struct greheader *)((const u_char *)ip + iphlen); 69154331Sarchie grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 69260009Sarchie if (m->m_pkthdr.len < iphlen + grelen) { 69360009Sarchie priv->stats.recvRunts++; 694149880Sglebius ERROUT(EINVAL); 69560009Sarchie } 69654331Sarchie if (m->m_len < iphlen + grelen) { 69754331Sarchie if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 69863822Sarchie priv->stats.memoryFailures++; 699149880Sglebius ERROUT(ENOBUFS); 70054331Sarchie } 70197897Sarchie ip = mtod(m, const struct ip *); 70297897Sarchie gre = (const struct greheader *)((const u_char *)ip + iphlen); 70354331Sarchie } 70454331Sarchie 70554331Sarchie /* Sanity check packet length and GRE header bits */ 70654331Sarchie extralen = m->m_pkthdr.len 707206050Smav - (iphlen + grelen + gre->hasSeq * be16dec(&gre->length)); 70860009Sarchie if (extralen < 0) { 70960009Sarchie priv->stats.recvBadGRE++; 710149880Sglebius ERROUT(EINVAL); 71160009Sarchie } 712206050Smav if ((be32dec(gre) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) { 71360009Sarchie priv->stats.recvBadGRE++; 714149880Sglebius ERROUT(EINVAL); 71560009Sarchie } 716177587Smav 717206050Smav hpriv = ng_pptpgre_find_session(priv, be16dec(&gre->cid)); 718177587Smav if (hpriv == NULL || hpriv->hook == NULL || !hpriv->conf.enabled) { 71960009Sarchie priv->stats.recvBadCID++; 720149880Sglebius ERROUT(EINVAL); 72160009Sarchie } 722177587Smav mtx_lock(&hpriv->mtx); 72354331Sarchie 72454331Sarchie /* Look for peer ack */ 72554331Sarchie if (gre->hasAck) { 726206050Smav const u_int32_t ack = be32dec(&gre->data[gre->hasSeq]); 727177587Smav const int index = ack - hpriv->recvAck - 1; 72873998Sarchie long sample; 72954331Sarchie long diff; 73054331Sarchie 73154331Sarchie /* Sanity check ack value */ 732177587Smav if (PPTP_SEQ_DIFF(ack, hpriv->xmitSeq) > 0) { 73360009Sarchie priv->stats.recvBadAcks++; 73460009Sarchie goto badAck; /* we never sent it! */ 73560009Sarchie } 736177587Smav if (PPTP_SEQ_DIFF(ack, hpriv->recvAck) <= 0) 73760009Sarchie goto badAck; /* ack already timed out */ 738177587Smav hpriv->recvAck = ack; 73954331Sarchie 74054331Sarchie /* Update adaptive timeout stuff */ 741177587Smav if (hpriv->conf.enableWindowing) { 742177587Smav sample = ng_pptpgre_time() - hpriv->timeSent[index]; 743177587Smav diff = sample - hpriv->rtt; 744177587Smav hpriv->rtt += PPTP_ACK_ALPHA(diff); 745128657Sarchie if (diff < 0) 746128657Sarchie diff = -diff; 747177587Smav hpriv->dev += PPTP_ACK_BETA(diff - hpriv->dev); 748166424Sglebius /* +2 to compensate low precision of int math */ 749177587Smav hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev + 2); 750177587Smav if (hpriv->ato > PPTP_MAX_TIMEOUT) 751177587Smav hpriv->ato = PPTP_MAX_TIMEOUT; 752177587Smav else if (hpriv->ato < PPTP_MIN_TIMEOUT) 753177587Smav hpriv->ato = PPTP_MIN_TIMEOUT; 75462222Sarchie 755128657Sarchie /* Shift packet transmit times in our transmit window */ 756177587Smav bcopy(hpriv->timeSent + index + 1, hpriv->timeSent, 757177587Smav sizeof(*hpriv->timeSent) 758128657Sarchie * (PPTP_XMIT_WIN - (index + 1))); 75962222Sarchie 760128657Sarchie /* If we sent an entire window, increase window size */ 761177587Smav if (PPTP_SEQ_DIFF(ack, hpriv->winAck) >= 0 762177587Smav && hpriv->xmitWin < PPTP_XMIT_WIN) { 763177587Smav hpriv->xmitWin++; 764177587Smav hpriv->winAck = ack + hpriv->xmitWin; 765128657Sarchie } 766128657Sarchie 767128657Sarchie /* Stop/(re)start receive ACK timer as necessary */ 768177646Smav ng_uncallout(&hpriv->rackTimer, hpriv->node); 769177587Smav if (hpriv->recvAck != hpriv->xmitSeq) 770177587Smav ng_pptpgre_start_recv_ack_timer(hpriv); 77154331Sarchie } 77254331Sarchie } 77360009SarchiebadAck: 77454331Sarchie 77554331Sarchie /* See if frame contains any data */ 77654331Sarchie if (gre->hasSeq) { 777206050Smav const u_int32_t seq = be32dec(&gre->data[0]); 77854331Sarchie 77954331Sarchie /* Sanity check sequence number */ 780177587Smav if (PPTP_SEQ_DIFF(seq, hpriv->recvSeq) <= 0) { 781177587Smav if (seq == hpriv->recvSeq) 78260009Sarchie priv->stats.recvDuplicates++; 78360009Sarchie else 78460009Sarchie priv->stats.recvOutOfOrder++; 785177587Smav mtx_unlock(&hpriv->mtx); 786149880Sglebius ERROUT(EINVAL); 78760009Sarchie } 788177587Smav hpriv->recvSeq = seq; 78954331Sarchie 79054331Sarchie /* We need to acknowledge this packet; do it soon... */ 791177587Smav if (!(callout_pending(&hpriv->sackTimer))) { 79263822Sarchie /* If delayed ACK is disabled, send it now */ 793177587Smav if (!hpriv->conf.enableDelayedAck) { /* ack now */ 794177587Smav ng_pptpgre_xmit(hpriv, NULL); 795177587Smav /* ng_pptpgre_xmit() drops the mutex */ 796149880Sglebius } else { /* ack later */ 797177646Smav ng_pptpgre_start_send_ack_timer(hpriv); 798177587Smav mtx_unlock(&hpriv->mtx); 79954331Sarchie } 800177587Smav } else 801177587Smav mtx_unlock(&hpriv->mtx); 80254331Sarchie 80354331Sarchie /* Trim mbuf down to internal payload */ 80454331Sarchie m_adj(m, iphlen + grelen); 80554331Sarchie if (extralen > 0) 80654331Sarchie m_adj(m, -extralen); 80754331Sarchie 808177587Smav mtx_assert(&hpriv->mtx, MA_NOTOWNED); 809177587Smav 81054331Sarchie /* Deliver frame to upper layers */ 811177587Smav NG_FWD_NEW_DATA(error, item, hpriv->hook, m); 81260009Sarchie } else { 81360009Sarchie priv->stats.recvLoneAcks++; 814177587Smav mtx_unlock(&hpriv->mtx); 81570700Sjulian NG_FREE_ITEM(item); 81670700Sjulian NG_FREE_M(m); /* no data to deliver */ 81760009Sarchie } 818149880Sglebius 81954331Sarchie return (error); 820149880Sglebius 821149880Sglebiusdone: 822149880Sglebius NG_FREE_ITEM(item); 823149880Sglebius NG_FREE_M(m); 824149880Sglebius return (error); 82554331Sarchie} 82654331Sarchie 82754331Sarchie/************************************************************************* 82854331Sarchie TIMER RELATED FUNCTIONS 82954331Sarchie*************************************************************************/ 83054331Sarchie 83154331Sarchie/* 83260009Sarchie * Start a timer for the peer's acknowledging our oldest unacknowledged 83354331Sarchie * sequence number. If we get an ack for this sequence number before 83454331Sarchie * the timer goes off, we cancel the timer. Resets currently running 83554331Sarchie * recv ack timer, if any. 83654331Sarchie */ 83754331Sarchiestatic void 838177587Smavng_pptpgre_start_recv_ack_timer(hpriv_p hpriv) 83954331Sarchie{ 84063822Sarchie int remain, ticks; 84154331Sarchie 84254331Sarchie /* Compute how long until oldest unack'd packet times out, 84354331Sarchie and reset the timer to that time. */ 844177587Smav remain = (hpriv->timeSent[0] + hpriv->ato) - ng_pptpgre_time(); 84554331Sarchie if (remain < 0) 84654331Sarchie remain = 0; 84760009Sarchie 84894667Sarchie /* Be conservative: timeout can happen up to 1 tick early */ 84963822Sarchie ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1; 850177587Smav ng_callout(&hpriv->rackTimer, hpriv->node, hpriv->hook, 851177587Smav ticks, ng_pptpgre_recv_ack_timeout, hpriv, 0); 85254331Sarchie} 85354331Sarchie 85454331Sarchie/* 85554331Sarchie * The peer has failed to acknowledge the oldest unacknowledged sequence 85654331Sarchie * number within the time allotted. Update our adaptive timeout parameters 85754331Sarchie * and reset/restart the recv ack timer. 85854331Sarchie */ 85954331Sarchiestatic void 860138618Sglebiusng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) 86154331Sarchie{ 86270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 863177587Smav const hpriv_p hpriv = arg1; 86454331Sarchie 86554331Sarchie /* Update adaptive timeout stuff */ 86660009Sarchie priv->stats.recvAckTimeouts++; 867177587Smav hpriv->rtt = PPTP_ACK_DELTA(hpriv->rtt) + 1; /* +1 to avoid delta*0 case */ 868177587Smav hpriv->ato = hpriv->rtt + PPTP_ACK_CHI(hpriv->dev); 869177587Smav if (hpriv->ato > PPTP_MAX_TIMEOUT) 870177587Smav hpriv->ato = PPTP_MAX_TIMEOUT; 871177587Smav else if (hpriv->ato < PPTP_MIN_TIMEOUT) 872177587Smav hpriv->ato = PPTP_MIN_TIMEOUT; 87362222Sarchie 87462222Sarchie /* Reset ack and sliding window */ 875177587Smav hpriv->recvAck = hpriv->xmitSeq; /* pretend we got the ack */ 876177587Smav hpriv->xmitWin = (hpriv->xmitWin + 1) / 2; /* shrink transmit window */ 877177587Smav hpriv->winAck = hpriv->recvAck + hpriv->xmitWin; /* reset win expand time */ 87854331Sarchie} 87954331Sarchie 88054331Sarchie/* 88160009Sarchie * Start the send ack timer. This assumes the timer is not 88260009Sarchie * already running. 88360009Sarchie */ 88460009Sarchiestatic void 885177646Smavng_pptpgre_start_send_ack_timer(hpriv_p hpriv) 88660009Sarchie{ 887177646Smav int ackTimeout, ticks; 88860009Sarchie 889177646Smav /* Take 1/4 of the estimated round trip time */ 890177646Smav ackTimeout = (hpriv->rtt >> 2); 891177646Smav if (ackTimeout < PPTP_MIN_ACK_DELAY) 892177646Smav ackTimeout = PPTP_MIN_ACK_DELAY; 893177646Smav else if (ackTimeout > PPTP_MAX_ACK_DELAY) 894177646Smav ackTimeout = PPTP_MAX_ACK_DELAY; 895177646Smav 89694667Sarchie /* Be conservative: timeout can happen up to 1 tick early */ 89763822Sarchie ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE); 898177587Smav ng_callout(&hpriv->sackTimer, hpriv->node, hpriv->hook, 899177587Smav ticks, ng_pptpgre_send_ack_timeout, hpriv, 0); 90060009Sarchie} 90160009Sarchie 90260009Sarchie/* 90354331Sarchie * We've waited as long as we're willing to wait before sending an 90454331Sarchie * acknowledgement to the peer for received frames. We had hoped to 90554331Sarchie * be able to piggy back our acknowledgement on an outgoing data frame, 90654331Sarchie * but apparently there haven't been any since. So send the ack now. 90754331Sarchie */ 90854331Sarchiestatic void 909138618Sglebiusng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2) 91054331Sarchie{ 911177587Smav const hpriv_p hpriv = arg1; 912149880Sglebius 913177587Smav mtx_lock(&hpriv->mtx); 91454331Sarchie /* Send a frame with an ack but no payload */ 915177587Smav ng_pptpgre_xmit(hpriv, NULL); 916177587Smav mtx_assert(&hpriv->mtx, MA_NOTOWNED); 91754331Sarchie} 91854331Sarchie 91954331Sarchie/************************************************************************* 92054331Sarchie MISC FUNCTIONS 92154331Sarchie*************************************************************************/ 92254331Sarchie 92354331Sarchie/* 924177587Smav * Find the hook with a given session ID. 92554331Sarchie */ 926177587Smavstatic hpriv_p 927177587Smavng_pptpgre_find_session(priv_p privp, u_int16_t cid) 92854331Sarchie{ 929177587Smav uint16_t hash = SESSHASH(cid); 930177587Smav hpriv_p hpriv = NULL; 93154331Sarchie 932177587Smav LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) { 933177587Smav if (hpriv->conf.cid == cid) 934177587Smav break; 935177587Smav } 936149615Sglebius 937177587Smav return (hpriv); 938177587Smav} 939177587Smav 940177587Smav/* 941177587Smav * Reset state (must be called with lock held or from writer) 942177587Smav */ 943177587Smavstatic void 944177587Smavng_pptpgre_reset(hpriv_p hpriv) 945177587Smav{ 94654331Sarchie /* Reset adaptive timeout state */ 947177587Smav hpriv->ato = PPTP_MAX_TIMEOUT; 948177646Smav hpriv->rtt = PPTP_TIME_SCALE / 10; 949177646Smav if (hpriv->conf.peerPpd > 1) /* ppd = 0 treat as = 1 */ 950177646Smav hpriv->rtt *= hpriv->conf.peerPpd; 951177587Smav hpriv->dev = 0; 952177587Smav hpriv->xmitWin = (hpriv->conf.recvWin + 1) / 2; 953177587Smav if (hpriv->xmitWin < 2) /* often the first packet is lost */ 954177587Smav hpriv->xmitWin = 2; /* because the peer isn't ready */ 955177587Smav else if (hpriv->xmitWin > PPTP_XMIT_WIN) 956177587Smav hpriv->xmitWin = PPTP_XMIT_WIN; 957177587Smav hpriv->winAck = hpriv->xmitWin; 95854331Sarchie 95954331Sarchie /* Reset sequence numbers */ 960177587Smav hpriv->recvSeq = ~0; 961177587Smav hpriv->recvAck = ~0; 962177587Smav hpriv->xmitSeq = ~0; 963177587Smav hpriv->xmitAck = ~0; 96454331Sarchie 96594667Sarchie /* Stop timers */ 966177646Smav ng_uncallout(&hpriv->sackTimer, hpriv->node); 967177646Smav ng_uncallout(&hpriv->rackTimer, hpriv->node); 96854331Sarchie} 96954331Sarchie 97054331Sarchie/* 97154331Sarchie * Return the current time scaled & translated to our internally used format. 97254331Sarchie */ 97354331Sarchiestatic pptptime_t 974177587Smavng_pptpgre_time(void) 97554331Sarchie{ 97654331Sarchie struct timeval tv; 97763822Sarchie pptptime_t t; 97854331Sarchie 97963822Sarchie microuptime(&tv); 98063822Sarchie t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE; 981177646Smav t += tv.tv_usec / (1000000 / PPTP_TIME_SCALE); 98263822Sarchie return(t); 98354331Sarchie} 984