1add85a1dSArchie Cobbs 2add85a1dSArchie Cobbs /* 3add85a1dSArchie Cobbs * ng_pptpgre.c 4add85a1dSArchie Cobbs * 5add85a1dSArchie Cobbs * Copyright (c) 1996-1999 Whistle Communications, Inc. 6add85a1dSArchie Cobbs * All rights reserved. 7add85a1dSArchie Cobbs * 8add85a1dSArchie Cobbs * Subject to the following obligations and disclaimer of warranty, use and 9add85a1dSArchie Cobbs * redistribution of this software, in source or object code forms, with or 10add85a1dSArchie Cobbs * without modifications are expressly permitted by Whistle Communications; 11add85a1dSArchie Cobbs * provided, however, that: 12add85a1dSArchie Cobbs * 1. Any and all reproductions of the source or object code must include the 13add85a1dSArchie Cobbs * copyright notice above and the following disclaimer of warranties; and 14add85a1dSArchie Cobbs * 2. No rights are granted, in any manner or form, to use Whistle 15add85a1dSArchie Cobbs * Communications, Inc. trademarks, including the mark "WHISTLE 16add85a1dSArchie Cobbs * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17add85a1dSArchie Cobbs * such appears in the above copyright notice or in the software. 18add85a1dSArchie Cobbs * 19add85a1dSArchie Cobbs * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20add85a1dSArchie Cobbs * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21add85a1dSArchie Cobbs * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22add85a1dSArchie Cobbs * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23add85a1dSArchie Cobbs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24add85a1dSArchie Cobbs * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25add85a1dSArchie Cobbs * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26add85a1dSArchie Cobbs * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27add85a1dSArchie Cobbs * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28add85a1dSArchie Cobbs * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29add85a1dSArchie Cobbs * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30add85a1dSArchie Cobbs * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31add85a1dSArchie Cobbs * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32add85a1dSArchie Cobbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33add85a1dSArchie Cobbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34add85a1dSArchie Cobbs * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35add85a1dSArchie Cobbs * OF SUCH DAMAGE. 36add85a1dSArchie Cobbs * 37add85a1dSArchie Cobbs * Author: Archie Cobbs <archie@whistle.com> 38add85a1dSArchie Cobbs * 39add85a1dSArchie Cobbs * $FreeBSD$ 40add85a1dSArchie Cobbs * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $ 41add85a1dSArchie Cobbs */ 42add85a1dSArchie Cobbs 43add85a1dSArchie Cobbs /* 44add85a1dSArchie Cobbs * PPTP/GRE netgraph node type. 45add85a1dSArchie Cobbs * 46add85a1dSArchie Cobbs * This node type does the GRE encapsulation as specified for the PPTP 47add85a1dSArchie Cobbs * protocol (RFC 2637, section 4). This includes sequencing and 48add85a1dSArchie Cobbs * retransmission of frames, but not the actual packet delivery nor 49add85a1dSArchie Cobbs * any of the TCP control stream protocol. 50add85a1dSArchie Cobbs * 51add85a1dSArchie Cobbs * The "upper" hook of this node is suitable for attaching to a "ppp" 52add85a1dSArchie Cobbs * node link hook. The "lower" hook of this node is suitable for attaching 53add85a1dSArchie Cobbs * to a "ksocket" node on hook "inet/raw/gre". 54add85a1dSArchie Cobbs */ 55add85a1dSArchie Cobbs 56add85a1dSArchie Cobbs #include <sys/param.h> 57add85a1dSArchie Cobbs #include <sys/systm.h> 58add85a1dSArchie Cobbs #include <sys/kernel.h> 59add85a1dSArchie Cobbs #include <sys/time.h> 60add85a1dSArchie Cobbs #include <sys/conf.h> 61add85a1dSArchie Cobbs #include <sys/mbuf.h> 62add85a1dSArchie Cobbs #include <sys/malloc.h> 63add85a1dSArchie Cobbs #include <sys/errno.h> 64add85a1dSArchie Cobbs #include <sys/socket.h> 65add85a1dSArchie Cobbs #include <sys/syslog.h> 66add85a1dSArchie Cobbs #include <sys/ctype.h> 67add85a1dSArchie Cobbs 68add85a1dSArchie Cobbs #include <netinet/in.h> 69add85a1dSArchie Cobbs #include <netinet/in_systm.h> 70add85a1dSArchie Cobbs #include <netinet/ip.h> 71add85a1dSArchie Cobbs 72add85a1dSArchie Cobbs #include <netgraph/ng_message.h> 73add85a1dSArchie Cobbs #include <netgraph/netgraph.h> 74add85a1dSArchie Cobbs #include <netgraph/ng_parse.h> 75add85a1dSArchie Cobbs #include <netgraph/ng_pptpgre.h> 76add85a1dSArchie Cobbs 77add85a1dSArchie Cobbs /* GRE packet format, as used by PPTP */ 78add85a1dSArchie Cobbs struct greheader { 79add85a1dSArchie Cobbs #if BYTE_ORDER == LITTLE_ENDIAN 80add85a1dSArchie Cobbs u_char recursion:3; /* recursion control */ 81add85a1dSArchie Cobbs u_char ssr:1; /* strict source route */ 82add85a1dSArchie Cobbs u_char hasSeq:1; /* sequence number present */ 83add85a1dSArchie Cobbs u_char hasKey:1; /* key present */ 84add85a1dSArchie Cobbs u_char hasRoute:1; /* routing present */ 85add85a1dSArchie Cobbs u_char hasSum:1; /* checksum present */ 86add85a1dSArchie Cobbs u_char vers:3; /* version */ 87add85a1dSArchie Cobbs u_char flags:4; /* flags */ 88add85a1dSArchie Cobbs u_char hasAck:1; /* acknowlege number present */ 89add85a1dSArchie Cobbs #elif BYTE_ORDER == BIG_ENDIAN 90add85a1dSArchie Cobbs u_char hasSum:1; /* checksum present */ 91add85a1dSArchie Cobbs u_char hasRoute:1; /* routing present */ 92add85a1dSArchie Cobbs u_char hasKey:1; /* key present */ 93add85a1dSArchie Cobbs u_char hasSeq:1; /* sequence number present */ 94add85a1dSArchie Cobbs u_char ssr:1; /* strict source route */ 95add85a1dSArchie Cobbs u_char recursion:3; /* recursion control */ 96add85a1dSArchie Cobbs u_char hasAck:1; /* acknowlege number present */ 97add85a1dSArchie Cobbs u_char flags:4; /* flags */ 98add85a1dSArchie Cobbs u_char vers:3; /* version */ 99add85a1dSArchie Cobbs #else 100add85a1dSArchie Cobbs #error BYTE_ORDER is not defined properly 101add85a1dSArchie Cobbs #endif 102add85a1dSArchie Cobbs u_int16_t proto; /* protocol (ethertype) */ 103add85a1dSArchie Cobbs u_int16_t length; /* payload length */ 104add85a1dSArchie Cobbs u_int16_t cid; /* call id */ 105add85a1dSArchie Cobbs u_int32_t data[0]; /* opt. seq, ack, then data */ 106add85a1dSArchie Cobbs }; 107add85a1dSArchie Cobbs 108add85a1dSArchie Cobbs /* The PPTP protocol ID used in the GRE 'proto' field */ 109add85a1dSArchie Cobbs #define PPTP_GRE_PROTO 0x880b 110add85a1dSArchie Cobbs 111add85a1dSArchie Cobbs /* Bits that must be set a certain way in all PPTP/GRE packets */ 112add85a1dSArchie Cobbs #define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO) 113add85a1dSArchie Cobbs #define PPTP_INIT_MASK 0xef7fffff 114add85a1dSArchie Cobbs 115add85a1dSArchie Cobbs /* Min and max packet length */ 116add85a1dSArchie Cobbs #define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8) 117add85a1dSArchie Cobbs 118add85a1dSArchie Cobbs /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */ 119add85a1dSArchie Cobbs #define PPTP_TIME_SCALE 1000 120add85a1dSArchie Cobbs typedef u_int32_t pptptime_t; 121add85a1dSArchie Cobbs 122add85a1dSArchie Cobbs /* Acknowledgment timeout parameters and functions */ 123add85a1dSArchie Cobbs #define PPTP_XMIT_WIN 8 /* max xmit window */ 124add85a1dSArchie Cobbs #define PPTP_MIN_RTT (PPTP_TIME_SCALE / 10) /* 1/10 second */ 125add85a1dSArchie Cobbs #define PPTP_MAX_TIMEOUT (10 * PPTP_TIME_SCALE) /* 10 seconds */ 126add85a1dSArchie Cobbs 127add85a1dSArchie Cobbs #define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */ 128add85a1dSArchie Cobbs #define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */ 129add85a1dSArchie Cobbs #define PPTP_ACK_CHI(x) ((x) << 2) /* chi = 4 */ 130add85a1dSArchie Cobbs #define PPTP_ACK_DELTA(x) ((x) << 1) /* delta = 2 */ 131add85a1dSArchie Cobbs 132add85a1dSArchie Cobbs /* We keep packet retransmit and acknowlegement state in this struct */ 133add85a1dSArchie Cobbs struct ng_pptpgre_ackp { 134add85a1dSArchie Cobbs int32_t ato; /* adaptive time-out value */ 135add85a1dSArchie Cobbs int32_t rtt; /* round trip time estimate */ 136add85a1dSArchie Cobbs int32_t dev; /* deviation estimate */ 137add85a1dSArchie Cobbs u_int16_t xmitWin; /* size of xmit window */ 138add85a1dSArchie Cobbs u_char sackTimerRunning;/* send ack timer is running */ 139add85a1dSArchie Cobbs u_int32_t winAck; /* seq when xmitWin will grow */ 140add85a1dSArchie Cobbs struct callout_handle sackTimer; /* send ack timer */ 141add85a1dSArchie Cobbs struct callout_handle rackTimer; /* recv ack timer */ 142add85a1dSArchie Cobbs pptptime_t timeSent[PPTP_XMIT_WIN]; 143add85a1dSArchie Cobbs }; 144add85a1dSArchie Cobbs 145add85a1dSArchie Cobbs /* When we recieve a packet, we wait to see if there's an outgoing packet 146add85a1dSArchie Cobbs we can piggy-back the ACK off of. These parameters determine the mimimum 147add85a1dSArchie Cobbs and maxmimum length of time we're willing to wait in order to do that. */ 148add85a1dSArchie Cobbs #define PPTP_MAX_ACK_DELAY ((int) (0.25 * PPTP_TIME_SCALE)) 149add85a1dSArchie Cobbs 150add85a1dSArchie Cobbs /* Node private data */ 151add85a1dSArchie Cobbs struct ng_pptpgre_private { 152add85a1dSArchie Cobbs hook_p upper; /* hook to upper layers */ 153add85a1dSArchie Cobbs hook_p lower; /* hook to lower layers */ 154add85a1dSArchie Cobbs struct ng_pptpgre_conf conf; /* configuration info */ 155add85a1dSArchie Cobbs struct ng_pptpgre_ackp ackp; /* packet transmit ack state */ 156add85a1dSArchie Cobbs u_int32_t recvSeq; /* last seq # we rcv'd */ 157add85a1dSArchie Cobbs u_int32_t xmitSeq; /* last seq # we sent */ 158add85a1dSArchie Cobbs u_int32_t recvAck; /* last seq # peer ack'd */ 159add85a1dSArchie Cobbs u_int32_t xmitAck; /* last seq # we ack'd */ 160add85a1dSArchie Cobbs struct timeval startTime; /* time node was created */ 161add85a1dSArchie Cobbs }; 162add85a1dSArchie Cobbs typedef struct ng_pptpgre_private *priv_p; 163add85a1dSArchie Cobbs 164add85a1dSArchie Cobbs /* Netgraph node methods */ 165add85a1dSArchie Cobbs static ng_constructor_t ng_pptpgre_constructor; 166add85a1dSArchie Cobbs static ng_rcvmsg_t ng_pptpgre_rcvmsg; 167add85a1dSArchie Cobbs static ng_shutdown_t ng_pptpgre_rmnode; 168add85a1dSArchie Cobbs static ng_newhook_t ng_pptpgre_newhook; 169add85a1dSArchie Cobbs static ng_rcvdata_t ng_pptpgre_rcvdata; 170add85a1dSArchie Cobbs static ng_disconnect_t ng_pptpgre_disconnect; 171add85a1dSArchie Cobbs 172add85a1dSArchie Cobbs /* Helper functions */ 173add85a1dSArchie Cobbs static int ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta); 174add85a1dSArchie Cobbs static int ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta); 175add85a1dSArchie Cobbs static void ng_pptpgre_start_recv_ack_timer(node_p node); 176add85a1dSArchie Cobbs static void ng_pptpgre_recv_ack_timeout(void *arg); 177add85a1dSArchie Cobbs static void ng_pptpgre_send_ack_timeout(void *arg); 178add85a1dSArchie Cobbs static void ng_pptpgre_reset(node_p node); 179add85a1dSArchie Cobbs static pptptime_t ng_pptpgre_time(node_p node); 180add85a1dSArchie Cobbs 181add85a1dSArchie Cobbs /* Parse type for struct ng_pptpgre_conf */ 182add85a1dSArchie Cobbs static const struct ng_parse_struct_info 183add85a1dSArchie Cobbs ng_pptpgre_conf_type_info = NG_PPTPGRE_CONF_TYPE_INFO; 184add85a1dSArchie Cobbs static const struct ng_parse_type ng_pptpgre_conf_type = { 185add85a1dSArchie Cobbs &ng_parse_struct_type, 186add85a1dSArchie Cobbs &ng_pptpgre_conf_type_info, 187add85a1dSArchie Cobbs }; 188add85a1dSArchie Cobbs 189add85a1dSArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 190add85a1dSArchie Cobbs static const struct ng_cmdlist ng_pptpgre_cmdlist[] = { 191add85a1dSArchie Cobbs { 192add85a1dSArchie Cobbs NGM_PPTPGRE_COOKIE, 193add85a1dSArchie Cobbs NGM_PPTPGRE_SET_CONFIG, 194add85a1dSArchie Cobbs "setconfig", 195add85a1dSArchie Cobbs &ng_pptpgre_conf_type, 196add85a1dSArchie Cobbs NULL 197add85a1dSArchie Cobbs }, 198add85a1dSArchie Cobbs { 199add85a1dSArchie Cobbs NGM_PPTPGRE_COOKIE, 200add85a1dSArchie Cobbs NGM_PPTPGRE_GET_CONFIG, 201add85a1dSArchie Cobbs "getconfig", 202add85a1dSArchie Cobbs NULL, 203add85a1dSArchie Cobbs &ng_pptpgre_conf_type 204add85a1dSArchie Cobbs }, 205add85a1dSArchie Cobbs { 0 } 206add85a1dSArchie Cobbs }; 207add85a1dSArchie Cobbs 208add85a1dSArchie Cobbs /* Node type descriptor */ 209add85a1dSArchie Cobbs static struct ng_type ng_pptpgre_typestruct = { 210add85a1dSArchie Cobbs NG_VERSION, 211add85a1dSArchie Cobbs NG_PPTPGRE_NODE_TYPE, 212add85a1dSArchie Cobbs NULL, 213add85a1dSArchie Cobbs ng_pptpgre_constructor, 214add85a1dSArchie Cobbs ng_pptpgre_rcvmsg, 215add85a1dSArchie Cobbs ng_pptpgre_rmnode, 216add85a1dSArchie Cobbs ng_pptpgre_newhook, 217add85a1dSArchie Cobbs NULL, 218add85a1dSArchie Cobbs NULL, 219add85a1dSArchie Cobbs ng_pptpgre_rcvdata, 220add85a1dSArchie Cobbs ng_pptpgre_rcvdata, 221add85a1dSArchie Cobbs ng_pptpgre_disconnect, 222add85a1dSArchie Cobbs ng_pptpgre_cmdlist 223add85a1dSArchie Cobbs }; 224add85a1dSArchie Cobbs NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct); 225add85a1dSArchie Cobbs 226add85a1dSArchie Cobbs #define ERROUT(x) do { error = (x); goto done; } while (0) 227add85a1dSArchie Cobbs 228add85a1dSArchie Cobbs /************************************************************************ 229add85a1dSArchie Cobbs NETGRAPH NODE STUFF 230add85a1dSArchie Cobbs ************************************************************************/ 231add85a1dSArchie Cobbs 232add85a1dSArchie Cobbs /* 233add85a1dSArchie Cobbs * Node type constructor 234add85a1dSArchie Cobbs */ 235add85a1dSArchie Cobbs static int 236add85a1dSArchie Cobbs ng_pptpgre_constructor(node_p *nodep) 237add85a1dSArchie Cobbs { 238add85a1dSArchie Cobbs priv_p priv; 239add85a1dSArchie Cobbs int error; 240add85a1dSArchie Cobbs 241add85a1dSArchie Cobbs /* Allocate private structure */ 242add85a1dSArchie Cobbs MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 243add85a1dSArchie Cobbs if (priv == NULL) 244add85a1dSArchie Cobbs return (ENOMEM); 245add85a1dSArchie Cobbs bzero(priv, sizeof(*priv)); 246add85a1dSArchie Cobbs 247add85a1dSArchie Cobbs /* Call generic node constructor */ 248add85a1dSArchie Cobbs if ((error = ng_make_node_common(&ng_pptpgre_typestruct, nodep))) { 249add85a1dSArchie Cobbs FREE(priv, M_NETGRAPH); 250add85a1dSArchie Cobbs return (error); 251add85a1dSArchie Cobbs } 252add85a1dSArchie Cobbs (*nodep)->private = priv; 253add85a1dSArchie Cobbs 254add85a1dSArchie Cobbs /* Initialize state */ 255add85a1dSArchie Cobbs callout_handle_init(&priv->ackp.sackTimer); 256add85a1dSArchie Cobbs callout_handle_init(&priv->ackp.rackTimer); 257add85a1dSArchie Cobbs 258add85a1dSArchie Cobbs /* Done */ 259add85a1dSArchie Cobbs return (0); 260add85a1dSArchie Cobbs } 261add85a1dSArchie Cobbs 262add85a1dSArchie Cobbs /* 263add85a1dSArchie Cobbs * Give our OK for a hook to be added. 264add85a1dSArchie Cobbs */ 265add85a1dSArchie Cobbs static int 266add85a1dSArchie Cobbs ng_pptpgre_newhook(node_p node, hook_p hook, const char *name) 267add85a1dSArchie Cobbs { 268add85a1dSArchie Cobbs const priv_p priv = node->private; 269add85a1dSArchie Cobbs hook_p *hookPtr; 270add85a1dSArchie Cobbs 271add85a1dSArchie Cobbs /* Check hook name */ 272add85a1dSArchie Cobbs if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0) 273add85a1dSArchie Cobbs hookPtr = &priv->upper; 274add85a1dSArchie Cobbs else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0) 275add85a1dSArchie Cobbs hookPtr = &priv->lower; 276add85a1dSArchie Cobbs else 277add85a1dSArchie Cobbs return (EINVAL); 278add85a1dSArchie Cobbs 279add85a1dSArchie Cobbs /* See if already connected */ 280add85a1dSArchie Cobbs if (*hookPtr != NULL) 281add85a1dSArchie Cobbs return (EISCONN); 282add85a1dSArchie Cobbs 283add85a1dSArchie Cobbs /* OK */ 284add85a1dSArchie Cobbs *hookPtr = hook; 285add85a1dSArchie Cobbs return (0); 286add85a1dSArchie Cobbs } 287add85a1dSArchie Cobbs 288add85a1dSArchie Cobbs /* 289add85a1dSArchie Cobbs * Receive a control message. 290add85a1dSArchie Cobbs */ 291add85a1dSArchie Cobbs static int 292add85a1dSArchie Cobbs ng_pptpgre_rcvmsg(node_p node, struct ng_mesg *msg, 293add85a1dSArchie Cobbs const char *raddr, struct ng_mesg **rptr) 294add85a1dSArchie Cobbs { 295add85a1dSArchie Cobbs const priv_p priv = node->private; 296add85a1dSArchie Cobbs struct ng_mesg *resp = NULL; 297add85a1dSArchie Cobbs int error = 0; 298add85a1dSArchie Cobbs 299add85a1dSArchie Cobbs switch (msg->header.typecookie) { 300add85a1dSArchie Cobbs case NGM_PPTPGRE_COOKIE: 301add85a1dSArchie Cobbs switch (msg->header.cmd) { 302add85a1dSArchie Cobbs case NGM_PPTPGRE_SET_CONFIG: 303add85a1dSArchie Cobbs { 304add85a1dSArchie Cobbs struct ng_pptpgre_conf *const newConf = 305add85a1dSArchie Cobbs (struct ng_pptpgre_conf *) msg->data; 306add85a1dSArchie Cobbs 307add85a1dSArchie Cobbs /* Check for invalid or illegal config */ 308add85a1dSArchie Cobbs if (msg->header.arglen != sizeof(*newConf)) 309add85a1dSArchie Cobbs ERROUT(EINVAL); 310add85a1dSArchie Cobbs ng_pptpgre_reset(node); /* reset on configure */ 311add85a1dSArchie Cobbs priv->conf = *newConf; 312add85a1dSArchie Cobbs break; 313add85a1dSArchie Cobbs } 314add85a1dSArchie Cobbs case NGM_PPTPGRE_GET_CONFIG: 315add85a1dSArchie Cobbs NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT); 316add85a1dSArchie Cobbs if (resp == NULL) 317add85a1dSArchie Cobbs ERROUT(ENOMEM); 318add85a1dSArchie Cobbs bcopy(&priv->conf, resp->data, sizeof(priv->conf)); 319add85a1dSArchie Cobbs break; 320add85a1dSArchie Cobbs default: 321add85a1dSArchie Cobbs error = EINVAL; 322add85a1dSArchie Cobbs break; 323add85a1dSArchie Cobbs } 324add85a1dSArchie Cobbs break; 325add85a1dSArchie Cobbs default: 326add85a1dSArchie Cobbs error = EINVAL; 327add85a1dSArchie Cobbs break; 328add85a1dSArchie Cobbs } 329add85a1dSArchie Cobbs if (rptr) 330add85a1dSArchie Cobbs *rptr = resp; 331add85a1dSArchie Cobbs else if (resp) 332add85a1dSArchie Cobbs FREE(resp, M_NETGRAPH); 333add85a1dSArchie Cobbs 334add85a1dSArchie Cobbs done: 335add85a1dSArchie Cobbs FREE(msg, M_NETGRAPH); 336add85a1dSArchie Cobbs return (error); 337add85a1dSArchie Cobbs } 338add85a1dSArchie Cobbs 339add85a1dSArchie Cobbs /* 340add85a1dSArchie Cobbs * Receive incoming data on a hook. 341add85a1dSArchie Cobbs */ 342add85a1dSArchie Cobbs static int 343add85a1dSArchie Cobbs ng_pptpgre_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 344add85a1dSArchie Cobbs { 345add85a1dSArchie Cobbs const node_p node = hook->node; 346add85a1dSArchie Cobbs const priv_p priv = node->private; 347add85a1dSArchie Cobbs 348add85a1dSArchie Cobbs /* If not configured, reject */ 349add85a1dSArchie Cobbs if (!priv->conf.enabled) { 350add85a1dSArchie Cobbs NG_FREE_DATA(m, meta); 351add85a1dSArchie Cobbs return (ENXIO); 352add85a1dSArchie Cobbs } 353add85a1dSArchie Cobbs 354add85a1dSArchie Cobbs /* Treat as xmit or recv data */ 355add85a1dSArchie Cobbs if (hook == priv->upper) 356add85a1dSArchie Cobbs return ng_pptpgre_xmit(node, m, meta); 357add85a1dSArchie Cobbs if (hook == priv->lower) 358add85a1dSArchie Cobbs return ng_pptpgre_recv(node, m, meta); 359add85a1dSArchie Cobbs panic("%s: weird hook", __FUNCTION__); 360add85a1dSArchie Cobbs } 361add85a1dSArchie Cobbs 362add85a1dSArchie Cobbs /* 363add85a1dSArchie Cobbs * Destroy node 364add85a1dSArchie Cobbs */ 365add85a1dSArchie Cobbs static int 366add85a1dSArchie Cobbs ng_pptpgre_rmnode(node_p node) 367add85a1dSArchie Cobbs { 368add85a1dSArchie Cobbs const priv_p priv = node->private; 369add85a1dSArchie Cobbs 370add85a1dSArchie Cobbs /* Cancel timers */ 371add85a1dSArchie Cobbs ng_pptpgre_reset(node); 372add85a1dSArchie Cobbs 373add85a1dSArchie Cobbs /* Take down netgraph node */ 374add85a1dSArchie Cobbs node->flags |= NG_INVALID; 375add85a1dSArchie Cobbs ng_cutlinks(node); 376add85a1dSArchie Cobbs ng_unname(node); 377add85a1dSArchie Cobbs bzero(priv, sizeof(*priv)); 378add85a1dSArchie Cobbs FREE(priv, M_NETGRAPH); 379add85a1dSArchie Cobbs node->private = NULL; 380add85a1dSArchie Cobbs ng_unref(node); 381add85a1dSArchie Cobbs return (0); 382add85a1dSArchie Cobbs } 383add85a1dSArchie Cobbs 384add85a1dSArchie Cobbs /* 385add85a1dSArchie Cobbs * Hook disconnection 386add85a1dSArchie Cobbs */ 387add85a1dSArchie Cobbs static int 388add85a1dSArchie Cobbs ng_pptpgre_disconnect(hook_p hook) 389add85a1dSArchie Cobbs { 390add85a1dSArchie Cobbs const node_p node = hook->node; 391add85a1dSArchie Cobbs const priv_p priv = node->private; 392add85a1dSArchie Cobbs 393add85a1dSArchie Cobbs /* Zero out hook pointer */ 394add85a1dSArchie Cobbs if (hook == priv->upper) 395add85a1dSArchie Cobbs priv->upper = NULL; 396add85a1dSArchie Cobbs else if (hook == priv->lower) 397add85a1dSArchie Cobbs priv->lower = NULL; 398add85a1dSArchie Cobbs else 399add85a1dSArchie Cobbs panic("%s: unknown hook", __FUNCTION__); 400add85a1dSArchie Cobbs 401add85a1dSArchie Cobbs /* Go away if no longer connected to anything */ 402add85a1dSArchie Cobbs if (node->numhooks == 0) 403add85a1dSArchie Cobbs ng_rmnode(node); 404add85a1dSArchie Cobbs return (0); 405add85a1dSArchie Cobbs } 406add85a1dSArchie Cobbs 407add85a1dSArchie Cobbs /************************************************************************* 408add85a1dSArchie Cobbs TRANSMIT AND RECEIVE FUNCTIONS 409add85a1dSArchie Cobbs *************************************************************************/ 410add85a1dSArchie Cobbs 411add85a1dSArchie Cobbs /* 412add85a1dSArchie Cobbs * Transmit an outgoing frame, or just an ack if m is NULL. 413add85a1dSArchie Cobbs */ 414add85a1dSArchie Cobbs static int 415add85a1dSArchie Cobbs ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta) 416add85a1dSArchie Cobbs { 417add85a1dSArchie Cobbs const priv_p priv = node->private; 418add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 419add85a1dSArchie Cobbs u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; 420add85a1dSArchie Cobbs struct greheader *const gre = (struct greheader *)buf; 421add85a1dSArchie Cobbs int grelen, error; 422add85a1dSArchie Cobbs 423add85a1dSArchie Cobbs /* Is our transmit window full? */ 424add85a1dSArchie Cobbs if (m != NULL && priv->xmitSeq - priv->recvAck >= a->xmitWin) { 425add85a1dSArchie Cobbs NG_FREE_DATA(m, meta); 426add85a1dSArchie Cobbs return (ENOBUFS); 427add85a1dSArchie Cobbs } 428add85a1dSArchie Cobbs 429add85a1dSArchie Cobbs /* Sanity check frame length */ 430add85a1dSArchie Cobbs if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { 431add85a1dSArchie Cobbs NG_FREE_DATA(m, meta); 432add85a1dSArchie Cobbs return (EMSGSIZE); 433add85a1dSArchie Cobbs } 434add85a1dSArchie Cobbs 435add85a1dSArchie Cobbs /* Build GRE header */ 436add85a1dSArchie Cobbs ((u_int32_t *) gre)[0] = htonl(PPTP_INIT_VALUE); 437add85a1dSArchie Cobbs gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0; 438add85a1dSArchie Cobbs gre->cid = htons(priv->conf.peerCid); 439add85a1dSArchie Cobbs 440add85a1dSArchie Cobbs /* Include sequence number if packet contains any data */ 441add85a1dSArchie Cobbs if (m != NULL) { 442add85a1dSArchie Cobbs gre->hasSeq = 1; 443add85a1dSArchie Cobbs a->timeSent[priv->xmitSeq - priv->recvAck] 444add85a1dSArchie Cobbs = ng_pptpgre_time(node); 445add85a1dSArchie Cobbs priv->xmitSeq++; 446add85a1dSArchie Cobbs gre->data[0] = htonl(priv->xmitSeq); 447add85a1dSArchie Cobbs if (priv->xmitSeq == priv->recvAck + 1) 448add85a1dSArchie Cobbs ng_pptpgre_start_recv_ack_timer(node); 449add85a1dSArchie Cobbs } 450add85a1dSArchie Cobbs 451add85a1dSArchie Cobbs /* Include acknowledgement (and stop send ack timer) if needed */ 452add85a1dSArchie Cobbs if (priv->xmitAck < priv->recvSeq) { 453add85a1dSArchie Cobbs gre->hasAck = 1; 454add85a1dSArchie Cobbs priv->xmitAck = priv->recvSeq; 455add85a1dSArchie Cobbs gre->data[gre->hasSeq] = htonl(priv->xmitAck); 456add85a1dSArchie Cobbs if (a->sackTimerRunning) { 457add85a1dSArchie Cobbs untimeout(ng_pptpgre_send_ack_timeout, 458add85a1dSArchie Cobbs node, a->sackTimer); 459add85a1dSArchie Cobbs a->sackTimerRunning = 0; 460add85a1dSArchie Cobbs } 461add85a1dSArchie Cobbs } 462add85a1dSArchie Cobbs 463add85a1dSArchie Cobbs /* Prepend GRE header to outgoing frame */ 464add85a1dSArchie Cobbs grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 465add85a1dSArchie Cobbs if (m == NULL) { 466add85a1dSArchie Cobbs MGETHDR(m, M_DONTWAIT, MT_DATA); 467add85a1dSArchie Cobbs if (m == NULL) { 468add85a1dSArchie Cobbs NG_FREE_META(meta); 469add85a1dSArchie Cobbs return (ENOBUFS); 470add85a1dSArchie Cobbs } 471add85a1dSArchie Cobbs m->m_len = m->m_pkthdr.len = grelen; 472add85a1dSArchie Cobbs m->m_pkthdr.rcvif = NULL; 473add85a1dSArchie Cobbs } else { 474add85a1dSArchie Cobbs M_PREPEND(m, grelen, M_NOWAIT); 475add85a1dSArchie Cobbs if (m == NULL || (m->m_len < grelen 476add85a1dSArchie Cobbs && (m = m_pullup(m, grelen)) == NULL)) { 477add85a1dSArchie Cobbs NG_FREE_META(meta); 478add85a1dSArchie Cobbs return (ENOBUFS); 479add85a1dSArchie Cobbs } 480add85a1dSArchie Cobbs } 481add85a1dSArchie Cobbs bcopy(gre, mtod(m, u_char *), grelen); 482add85a1dSArchie Cobbs 483add85a1dSArchie Cobbs /* Deliver packet */ 484add85a1dSArchie Cobbs NG_SEND_DATA(error, priv->lower, m, meta); 485add85a1dSArchie Cobbs return (error); 486add85a1dSArchie Cobbs } 487add85a1dSArchie Cobbs 488add85a1dSArchie Cobbs /* 489add85a1dSArchie Cobbs * Handle an incoming packet. The packet includes the IP header. 490add85a1dSArchie Cobbs */ 491add85a1dSArchie Cobbs static int 492add85a1dSArchie Cobbs ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta) 493add85a1dSArchie Cobbs { 494add85a1dSArchie Cobbs const priv_p priv = node->private; 495add85a1dSArchie Cobbs int iphlen, grelen, extralen; 496add85a1dSArchie Cobbs struct greheader *gre; 497add85a1dSArchie Cobbs struct ip *ip; 498add85a1dSArchie Cobbs int error = 0; 499add85a1dSArchie Cobbs 500add85a1dSArchie Cobbs /* Sanity check packet length */ 501add85a1dSArchie Cobbs if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) { 502add85a1dSArchie Cobbs bad: 503add85a1dSArchie Cobbs NG_FREE_DATA(m, meta); 504add85a1dSArchie Cobbs return (EINVAL); 505add85a1dSArchie Cobbs } 506add85a1dSArchie Cobbs 507add85a1dSArchie Cobbs /* Safely pull up the complete IP+GRE headers */ 508add85a1dSArchie Cobbs if (m->m_len < sizeof(*ip) + sizeof(*gre) 509add85a1dSArchie Cobbs && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) { 510add85a1dSArchie Cobbs NG_FREE_META(meta); 511add85a1dSArchie Cobbs return (ENOBUFS); 512add85a1dSArchie Cobbs } 513add85a1dSArchie Cobbs ip = mtod(m, struct ip *); 514add85a1dSArchie Cobbs iphlen = ip->ip_hl << 2; 515add85a1dSArchie Cobbs if (m->m_len < iphlen + sizeof(*gre)) { 516add85a1dSArchie Cobbs if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) { 517add85a1dSArchie Cobbs NG_FREE_META(meta); 518add85a1dSArchie Cobbs return (ENOBUFS); 519add85a1dSArchie Cobbs } 520add85a1dSArchie Cobbs ip = mtod(m, struct ip *); 521add85a1dSArchie Cobbs } 522add85a1dSArchie Cobbs gre = (struct greheader *)((u_char *)ip + iphlen); 523add85a1dSArchie Cobbs grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck); 524add85a1dSArchie Cobbs if (m->m_pkthdr.len < iphlen + grelen) 525add85a1dSArchie Cobbs goto bad; 526add85a1dSArchie Cobbs if (m->m_len < iphlen + grelen) { 527add85a1dSArchie Cobbs if ((m = m_pullup(m, iphlen + grelen)) == NULL) { 528add85a1dSArchie Cobbs NG_FREE_META(meta); 529add85a1dSArchie Cobbs return (ENOBUFS); 530add85a1dSArchie Cobbs } 531add85a1dSArchie Cobbs ip = mtod(m, struct ip *); 532add85a1dSArchie Cobbs gre = (struct greheader *)((u_char *)ip + iphlen); 533add85a1dSArchie Cobbs } 534add85a1dSArchie Cobbs 535add85a1dSArchie Cobbs /* Sanity check packet length and GRE header bits */ 536add85a1dSArchie Cobbs extralen = m->m_pkthdr.len 537add85a1dSArchie Cobbs - (iphlen + grelen + (u_int16_t)ntohs(gre->length)); 538add85a1dSArchie Cobbs if (extralen < 0) 539add85a1dSArchie Cobbs goto bad; 540add85a1dSArchie Cobbs if ((ntohl(*((u_int32_t *)gre)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) 541add85a1dSArchie Cobbs goto bad; 542add85a1dSArchie Cobbs if (ntohs(gre->cid) != priv->conf.cid) 543add85a1dSArchie Cobbs goto bad; 544add85a1dSArchie Cobbs 545add85a1dSArchie Cobbs /* Look for peer ack */ 546add85a1dSArchie Cobbs if (gre->hasAck) { 547add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 548add85a1dSArchie Cobbs const u_int32_t ack = ntohl(gre->data[gre->hasSeq]); 549add85a1dSArchie Cobbs const int index = ack - priv->recvAck - 1; 550add85a1dSArchie Cobbs const long sample = ng_pptpgre_time(node) - a->timeSent[index]; 551add85a1dSArchie Cobbs long diff; 552add85a1dSArchie Cobbs 553add85a1dSArchie Cobbs /* Sanity check ack value */ 554add85a1dSArchie Cobbs if (ack <= priv->recvAck) /* ack already timed out */ 555add85a1dSArchie Cobbs goto bad; 556add85a1dSArchie Cobbs if (ack > priv->xmitSeq) /* we never sent it! */ 557add85a1dSArchie Cobbs goto bad; 558add85a1dSArchie Cobbs priv->recvAck = ack; 559add85a1dSArchie Cobbs 560add85a1dSArchie Cobbs /* Update adaptive timeout stuff */ 561add85a1dSArchie Cobbs diff = sample - a->rtt; 562add85a1dSArchie Cobbs a->rtt += PPTP_ACK_ALPHA(diff); 563add85a1dSArchie Cobbs if (diff < 0) 564add85a1dSArchie Cobbs diff = -diff; 565add85a1dSArchie Cobbs a->dev += PPTP_ACK_BETA(diff - a->dev); 566add85a1dSArchie Cobbs a->ato = a->rtt + (u_int) (PPTP_ACK_CHI(a->dev)); 567add85a1dSArchie Cobbs if (a->ato > PPTP_MAX_TIMEOUT) 568add85a1dSArchie Cobbs a->ato = PPTP_MAX_TIMEOUT; 569add85a1dSArchie Cobbs ovbcopy(a->timeSent + index + 1, a->timeSent, 570add85a1dSArchie Cobbs sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1))); 571add85a1dSArchie Cobbs if (ack >= a->winAck && a->xmitWin < PPTP_XMIT_WIN) { 572add85a1dSArchie Cobbs a->xmitWin++; 573add85a1dSArchie Cobbs a->winAck = ack + a->xmitWin; 574add85a1dSArchie Cobbs } 575add85a1dSArchie Cobbs 576add85a1dSArchie Cobbs /* (Re)start receive ACK timer as necessary */ 577add85a1dSArchie Cobbs ng_pptpgre_start_recv_ack_timer(node); 578add85a1dSArchie Cobbs } 579add85a1dSArchie Cobbs 580add85a1dSArchie Cobbs /* See if frame contains any data */ 581add85a1dSArchie Cobbs if (gre->hasSeq) { 582add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 583add85a1dSArchie Cobbs const u_int32_t seq = ntohl(gre->data[0]); 584add85a1dSArchie Cobbs 585add85a1dSArchie Cobbs /* Sanity check sequence number */ 586add85a1dSArchie Cobbs if (seq <= priv->recvSeq) /* out-of-order or dup */ 587add85a1dSArchie Cobbs goto bad; 588add85a1dSArchie Cobbs priv->recvSeq = seq; 589add85a1dSArchie Cobbs 590add85a1dSArchie Cobbs /* We need to acknowledge this packet; do it soon... */ 591add85a1dSArchie Cobbs if (!a->sackTimerRunning) { 592add85a1dSArchie Cobbs long ackTimeout; 593add85a1dSArchie Cobbs 594add85a1dSArchie Cobbs /* Take half of the estimated round trip time */ 595add85a1dSArchie Cobbs ackTimeout = (a->rtt >> 1); 596add85a1dSArchie Cobbs 597add85a1dSArchie Cobbs /* If too soon, just send one right now */ 598add85a1dSArchie Cobbs if (!priv->conf.enableDelayedAck) 599add85a1dSArchie Cobbs ng_pptpgre_xmit(node, NULL, NULL); 600add85a1dSArchie Cobbs else { /* send the ack later */ 601add85a1dSArchie Cobbs if (ackTimeout > PPTP_MAX_ACK_DELAY) 602add85a1dSArchie Cobbs ackTimeout = PPTP_MAX_ACK_DELAY; 603add85a1dSArchie Cobbs a->sackTimer = timeout( 604add85a1dSArchie Cobbs ng_pptpgre_send_ack_timeout, node, 605add85a1dSArchie Cobbs ackTimeout * hz / PPTP_TIME_SCALE); 606add85a1dSArchie Cobbs a->sackTimerRunning = 1; 607add85a1dSArchie Cobbs } 608add85a1dSArchie Cobbs } 609add85a1dSArchie Cobbs 610add85a1dSArchie Cobbs /* Trim mbuf down to internal payload */ 611add85a1dSArchie Cobbs m_adj(m, iphlen + grelen); 612add85a1dSArchie Cobbs if (extralen > 0) 613add85a1dSArchie Cobbs m_adj(m, -extralen); 614add85a1dSArchie Cobbs 615add85a1dSArchie Cobbs /* Deliver frame to upper layers */ 616add85a1dSArchie Cobbs NG_SEND_DATA(error, priv->upper, m, meta); 617add85a1dSArchie Cobbs } else 618add85a1dSArchie Cobbs NG_FREE_DATA(m, meta); /* no data to deliver */ 619add85a1dSArchie Cobbs return (error); 620add85a1dSArchie Cobbs } 621add85a1dSArchie Cobbs 622add85a1dSArchie Cobbs /************************************************************************* 623add85a1dSArchie Cobbs TIMER RELATED FUNCTIONS 624add85a1dSArchie Cobbs *************************************************************************/ 625add85a1dSArchie Cobbs 626add85a1dSArchie Cobbs /* 627add85a1dSArchie Cobbs * Set a timer for the peer's acknowledging our oldest unacknowledged 628add85a1dSArchie Cobbs * sequence number. If we get an ack for this sequence number before 629add85a1dSArchie Cobbs * the timer goes off, we cancel the timer. Resets currently running 630add85a1dSArchie Cobbs * recv ack timer, if any. 631add85a1dSArchie Cobbs */ 632add85a1dSArchie Cobbs static void 633add85a1dSArchie Cobbs ng_pptpgre_start_recv_ack_timer(node_p node) 634add85a1dSArchie Cobbs { 635add85a1dSArchie Cobbs const priv_p priv = node->private; 636add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 637add85a1dSArchie Cobbs int remain; 638add85a1dSArchie Cobbs 639add85a1dSArchie Cobbs /* Stop current recv ack timer, if any */ 640add85a1dSArchie Cobbs untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer); 641add85a1dSArchie Cobbs if (priv->recvAck == priv->xmitSeq) 642add85a1dSArchie Cobbs return; 643add85a1dSArchie Cobbs 644add85a1dSArchie Cobbs /* Compute how long until oldest unack'd packet times out, 645add85a1dSArchie Cobbs and reset the timer to that time. */ 646add85a1dSArchie Cobbs remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node); 647add85a1dSArchie Cobbs if (remain < 0) 648add85a1dSArchie Cobbs remain = 0; 649add85a1dSArchie Cobbs a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout, 650add85a1dSArchie Cobbs node, remain * hz / PPTP_TIME_SCALE); 651add85a1dSArchie Cobbs } 652add85a1dSArchie Cobbs 653add85a1dSArchie Cobbs /* 654add85a1dSArchie Cobbs * The peer has failed to acknowledge the oldest unacknowledged sequence 655add85a1dSArchie Cobbs * number within the time allotted. Update our adaptive timeout parameters 656add85a1dSArchie Cobbs * and reset/restart the recv ack timer. 657add85a1dSArchie Cobbs */ 658add85a1dSArchie Cobbs static void 659add85a1dSArchie Cobbs ng_pptpgre_recv_ack_timeout(void *arg) 660add85a1dSArchie Cobbs { 661add85a1dSArchie Cobbs const node_p node = arg; 662add85a1dSArchie Cobbs const priv_p priv = node->private; 663add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 664add85a1dSArchie Cobbs 665add85a1dSArchie Cobbs /* Update adaptive timeout stuff */ 666add85a1dSArchie Cobbs a->rtt = PPTP_ACK_DELTA(a->rtt); 667add85a1dSArchie Cobbs a->ato = a->rtt + PPTP_ACK_CHI(a->dev); 668add85a1dSArchie Cobbs if (a->ato > PPTP_MAX_TIMEOUT) 669add85a1dSArchie Cobbs a->ato = PPTP_MAX_TIMEOUT; 670add85a1dSArchie Cobbs priv->recvAck++; /* assume packet was lost */ 671add85a1dSArchie Cobbs a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */ 672add85a1dSArchie Cobbs ovbcopy(a->timeSent + 1, a->timeSent, /* shift xmit window times */ 673add85a1dSArchie Cobbs sizeof(*a->timeSent) * (PPTP_XMIT_WIN - 1)); 674add85a1dSArchie Cobbs a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */ 675add85a1dSArchie Cobbs 676add85a1dSArchie Cobbs /* Restart timer if there are any more outstanding frames */ 677add85a1dSArchie Cobbs if (priv->recvAck != priv->xmitSeq) 678add85a1dSArchie Cobbs ng_pptpgre_start_recv_ack_timer(node); 679add85a1dSArchie Cobbs } 680add85a1dSArchie Cobbs 681add85a1dSArchie Cobbs /* 682add85a1dSArchie Cobbs * We've waited as long as we're willing to wait before sending an 683add85a1dSArchie Cobbs * acknowledgement to the peer for received frames. We had hoped to 684add85a1dSArchie Cobbs * be able to piggy back our acknowledgement on an outgoing data frame, 685add85a1dSArchie Cobbs * but apparently there haven't been any since. So send the ack now. 686add85a1dSArchie Cobbs */ 687add85a1dSArchie Cobbs static void 688add85a1dSArchie Cobbs ng_pptpgre_send_ack_timeout(void *arg) 689add85a1dSArchie Cobbs { 690add85a1dSArchie Cobbs const node_p node = arg; 691add85a1dSArchie Cobbs const priv_p priv = node->private; 692add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 693add85a1dSArchie Cobbs 694add85a1dSArchie Cobbs /* Send a frame with an ack but no payload */ 695add85a1dSArchie Cobbs a->sackTimerRunning = 0; 696add85a1dSArchie Cobbs ng_pptpgre_xmit(node, NULL, NULL); 697add85a1dSArchie Cobbs } 698add85a1dSArchie Cobbs 699add85a1dSArchie Cobbs /************************************************************************* 700add85a1dSArchie Cobbs MISC FUNCTIONS 701add85a1dSArchie Cobbs *************************************************************************/ 702add85a1dSArchie Cobbs 703add85a1dSArchie Cobbs /* 704add85a1dSArchie Cobbs * Reset state 705add85a1dSArchie Cobbs */ 706add85a1dSArchie Cobbs static void 707add85a1dSArchie Cobbs ng_pptpgre_reset(node_p node) 708add85a1dSArchie Cobbs { 709add85a1dSArchie Cobbs const priv_p priv = node->private; 710add85a1dSArchie Cobbs struct ng_pptpgre_ackp *const a = &priv->ackp; 711add85a1dSArchie Cobbs 712add85a1dSArchie Cobbs /* Reset adaptive timeout state */ 713add85a1dSArchie Cobbs a->ato = PPTP_MAX_TIMEOUT; 714add85a1dSArchie Cobbs a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10; /* ppd in 10ths */ 715add85a1dSArchie Cobbs if (a->rtt < PPTP_MIN_RTT) 716add85a1dSArchie Cobbs a->rtt = PPTP_MIN_RTT; 717add85a1dSArchie Cobbs a->dev = 0; 718add85a1dSArchie Cobbs a->xmitWin = (priv->conf.recvWin + 1) / 2; 719add85a1dSArchie Cobbs if (a->xmitWin < 1) 720add85a1dSArchie Cobbs a->xmitWin = 1; 721add85a1dSArchie Cobbs if (a->xmitWin > PPTP_XMIT_WIN) 722add85a1dSArchie Cobbs a->xmitWin = PPTP_XMIT_WIN; 723add85a1dSArchie Cobbs a->winAck = a->xmitWin; 724add85a1dSArchie Cobbs 725add85a1dSArchie Cobbs /* Reset sequence numbers */ 726add85a1dSArchie Cobbs priv->recvSeq = 0; 727add85a1dSArchie Cobbs priv->recvAck = 0; 728add85a1dSArchie Cobbs priv->xmitSeq = 0; 729add85a1dSArchie Cobbs priv->xmitAck = 0; 730add85a1dSArchie Cobbs 731add85a1dSArchie Cobbs /* Reset start time */ 732add85a1dSArchie Cobbs getmicrotime(&priv->startTime); 733add85a1dSArchie Cobbs 734add85a1dSArchie Cobbs /* Stop timers */ 735add85a1dSArchie Cobbs untimeout(ng_pptpgre_send_ack_timeout, node, a->sackTimer); 736add85a1dSArchie Cobbs untimeout(ng_pptpgre_recv_ack_timeout, node, a->rackTimer); 737add85a1dSArchie Cobbs a->sackTimerRunning = 0; 738add85a1dSArchie Cobbs } 739add85a1dSArchie Cobbs 740add85a1dSArchie Cobbs /* 741add85a1dSArchie Cobbs * Return the current time scaled & translated to our internally used format. 742add85a1dSArchie Cobbs */ 743add85a1dSArchie Cobbs static pptptime_t 744add85a1dSArchie Cobbs ng_pptpgre_time(node_p node) 745add85a1dSArchie Cobbs { 746add85a1dSArchie Cobbs const priv_p priv = node->private; 747add85a1dSArchie Cobbs struct timeval tv; 748add85a1dSArchie Cobbs 749add85a1dSArchie Cobbs getmicrotime(&tv); 750add85a1dSArchie Cobbs if (tv.tv_sec < priv->startTime.tv_sec 751add85a1dSArchie Cobbs || (tv.tv_sec == priv->startTime.tv_sec 752add85a1dSArchie Cobbs && tv.tv_usec < priv->startTime.tv_usec)) 753add85a1dSArchie Cobbs return (0); 754add85a1dSArchie Cobbs timevalsub(&tv, &priv->startTime); 755add85a1dSArchie Cobbs tv.tv_sec *= PPTP_TIME_SCALE; 756add85a1dSArchie Cobbs tv.tv_usec /= 1000000 / PPTP_TIME_SCALE; 757add85a1dSArchie Cobbs return(tv.tv_sec + tv.tv_usec); 758add85a1dSArchie Cobbs } 759add85a1dSArchie Cobbs 760