The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_pptpgre.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/5.3/sys/netgraph/ng_pptpgre.c 136588 2004-10-16 08:43:07Z cvs2svn $
   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 */
   74 struct 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 */
  116 typedef 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 / 83)  /* 12 milliseconds */
  122 #define PPTP_MAX_TIMEOUT        (3 * PPTP_TIME_SCALE)   /* 3 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 */
  140 struct 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          sackTimer;      /* send ack timer */
  146         struct callout          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 */
  158 struct 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         u_int                   timers;         /* number of pending timers */
  168         struct timeval          startTime;      /* time node was created */
  169         struct ng_pptpgre_stats stats;          /* node statistics */
  170 };
  171 typedef struct ng_pptpgre_private *priv_p;
  172 
  173 /* Netgraph node methods */
  174 static ng_constructor_t ng_pptpgre_constructor;
  175 static ng_rcvmsg_t      ng_pptpgre_rcvmsg;
  176 static ng_shutdown_t    ng_pptpgre_shutdown;
  177 static ng_newhook_t     ng_pptpgre_newhook;
  178 static ng_rcvdata_t     ng_pptpgre_rcvdata;
  179 static ng_disconnect_t  ng_pptpgre_disconnect;
  180 
  181 /* Helper functions */
  182 static int      ng_pptpgre_xmit(node_p node, item_p item);
  183 static int      ng_pptpgre_recv(node_p node, item_p item);
  184 static void     ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
  185 static void     ng_pptpgre_stop_send_ack_timer(node_p node);
  186 static void     ng_pptpgre_start_recv_ack_timer(node_p node);
  187 static void     ng_pptpgre_stop_recv_ack_timer(node_p node);
  188 static void     ng_pptpgre_recv_ack_timeout(void *arg);
  189 static void     ng_pptpgre_send_ack_timeout(void *arg);
  190 static void     ng_pptpgre_reset(node_p node);
  191 static pptptime_t ng_pptpgre_time(node_p node);
  192 
  193 /* Parse type for struct ng_pptpgre_conf */
  194 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
  195         = NG_PPTPGRE_CONF_TYPE_INFO;
  196 static const struct ng_parse_type ng_pptpgre_conf_type = {
  197         &ng_parse_struct_type,
  198         &ng_pptpgre_conf_type_fields,
  199 };
  200 
  201 /* Parse type for struct ng_pptpgre_stats */
  202 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
  203         = NG_PPTPGRE_STATS_TYPE_INFO;
  204 static const struct ng_parse_type ng_pptp_stats_type = {
  205         &ng_parse_struct_type,
  206         &ng_pptpgre_stats_type_fields
  207 };
  208 
  209 /* List of commands and how to convert arguments to/from ASCII */
  210 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
  211         {
  212           NGM_PPTPGRE_COOKIE,
  213           NGM_PPTPGRE_SET_CONFIG,
  214           "setconfig",
  215           &ng_pptpgre_conf_type,
  216           NULL
  217         },
  218         {
  219           NGM_PPTPGRE_COOKIE,
  220           NGM_PPTPGRE_GET_CONFIG,
  221           "getconfig",
  222           NULL,
  223           &ng_pptpgre_conf_type
  224         },
  225         {
  226           NGM_PPTPGRE_COOKIE,
  227           NGM_PPTPGRE_GET_STATS,
  228           "getstats",
  229           NULL,
  230           &ng_pptp_stats_type
  231         },
  232         {
  233           NGM_PPTPGRE_COOKIE,
  234           NGM_PPTPGRE_CLR_STATS,
  235           "clrstats",
  236           NULL,
  237           NULL
  238         },
  239         {
  240           NGM_PPTPGRE_COOKIE,
  241           NGM_PPTPGRE_GETCLR_STATS,
  242           "getclrstats",
  243           NULL,
  244           &ng_pptp_stats_type
  245         },
  246         { 0 }
  247 };
  248 
  249 /* Node type descriptor */
  250 static struct ng_type ng_pptpgre_typestruct = {
  251         .version =      NG_ABI_VERSION,
  252         .name =         NG_PPTPGRE_NODE_TYPE,
  253         .constructor =  ng_pptpgre_constructor,
  254         .rcvmsg =       ng_pptpgre_rcvmsg,
  255         .shutdown =     ng_pptpgre_shutdown,
  256         .newhook =      ng_pptpgre_newhook,
  257         .rcvdata =      ng_pptpgre_rcvdata,
  258         .disconnect =   ng_pptpgre_disconnect,
  259         .cmdlist =      ng_pptpgre_cmdlist,
  260 };
  261 NETGRAPH_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  */
  272 static int
  273 ng_pptpgre_constructor(node_p node)
  274 {
  275         priv_p priv;
  276 
  277         /* Allocate private structure */
  278         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
  279         if (priv == NULL)
  280                 return (ENOMEM);
  281 
  282         NG_NODE_SET_PRIVATE(node, priv);
  283 
  284         /* Initialize state */
  285         callout_init(&priv->ackp.sackTimer, 0);
  286         callout_init(&priv->ackp.rackTimer, 0);
  287 
  288         /* Done */
  289         return (0);
  290 }
  291 
  292 /*
  293  * Give our OK for a hook to be added.
  294  */
  295 static int
  296 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
  297 {
  298         const priv_p priv = NG_NODE_PRIVATE(node);
  299         hook_p *hookPtr;
  300 
  301         /* Check hook name */
  302         if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
  303                 hookPtr = &priv->upper;
  304         else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
  305                 hookPtr = &priv->lower;
  306         else
  307                 return (EINVAL);
  308 
  309         /* See if already connected */
  310         if (*hookPtr != NULL)
  311                 return (EISCONN);
  312 
  313         /* OK */
  314         *hookPtr = hook;
  315         return (0);
  316 }
  317 
  318 /*
  319  * Receive a control message.
  320  */
  321 static int
  322 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
  323 {
  324         const priv_p priv = NG_NODE_PRIVATE(node);
  325         struct ng_mesg *resp = NULL;
  326         int error = 0;
  327         struct ng_mesg *msg;
  328 
  329         NGI_GET_MSG(item, msg);
  330         switch (msg->header.typecookie) {
  331         case NGM_PPTPGRE_COOKIE:
  332                 switch (msg->header.cmd) {
  333                 case NGM_PPTPGRE_SET_CONFIG:
  334                     {
  335                         struct ng_pptpgre_conf *const newConf =
  336                                 (struct ng_pptpgre_conf *) msg->data;
  337 
  338                         /* Check for invalid or illegal config */
  339                         if (msg->header.arglen != sizeof(*newConf))
  340                                 ERROUT(EINVAL);
  341                         ng_pptpgre_reset(node);         /* reset on configure */
  342                         priv->conf = *newConf;
  343                         break;
  344                     }
  345                 case NGM_PPTPGRE_GET_CONFIG:
  346                         NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
  347                         if (resp == NULL)
  348                                 ERROUT(ENOMEM);
  349                         bcopy(&priv->conf, resp->data, sizeof(priv->conf));
  350                         break;
  351                 case NGM_PPTPGRE_GET_STATS:
  352                 case NGM_PPTPGRE_CLR_STATS:
  353                 case NGM_PPTPGRE_GETCLR_STATS:
  354                     {
  355                         if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
  356                                 NG_MKRESPONSE(resp, msg,
  357                                     sizeof(priv->stats), M_NOWAIT);
  358                                 if (resp == NULL)
  359                                         ERROUT(ENOMEM);
  360                                 bcopy(&priv->stats,
  361                                     resp->data, sizeof(priv->stats));
  362                         }
  363                         if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
  364                                 bzero(&priv->stats, sizeof(priv->stats));
  365                         break;
  366                     }
  367                 default:
  368                         error = EINVAL;
  369                         break;
  370                 }
  371                 break;
  372         default:
  373                 error = EINVAL;
  374                 break;
  375         }
  376 done:
  377         NG_RESPOND_MSG(error, node, item, resp);
  378         NG_FREE_MSG(msg);
  379         return (error);
  380 }
  381 
  382 /*
  383  * Receive incoming data on a hook.
  384  */
  385 static int
  386 ng_pptpgre_rcvdata(hook_p hook, item_p item)
  387 {
  388         const node_p node = NG_HOOK_NODE(hook);
  389         const priv_p priv = NG_NODE_PRIVATE(node);
  390 
  391         /* If not configured, reject */
  392         if (!priv->conf.enabled) {
  393                 NG_FREE_ITEM(item);
  394                 return (ENXIO);
  395         }
  396 
  397         /* Treat as xmit or recv data */
  398         if (hook == priv->upper)
  399                 return ng_pptpgre_xmit(node, item);
  400         if (hook == priv->lower)
  401                 return ng_pptpgre_recv(node, item);
  402         panic("%s: weird hook", __func__);
  403 }
  404 
  405 /*
  406  * Destroy node
  407  */
  408 static int
  409 ng_pptpgre_shutdown(node_p node)
  410 {
  411         const priv_p priv = NG_NODE_PRIVATE(node);
  412 
  413         /* Reset node */
  414         ng_pptpgre_reset(node);
  415 
  416         /* If no timers remain, free private info as well */
  417         if (priv->timers == 0) {
  418                 bzero(priv, sizeof(*priv));
  419                 FREE(priv, M_NETGRAPH);
  420                 NG_NODE_SET_PRIVATE(node, NULL);
  421         }
  422 
  423         /* Decrement ref count */
  424         NG_NODE_UNREF(node);
  425         return (0);
  426 }
  427 
  428 /*
  429  * Hook disconnection
  430  */
  431 static int
  432 ng_pptpgre_disconnect(hook_p hook)
  433 {
  434         const node_p node = NG_HOOK_NODE(hook);
  435         const priv_p priv = NG_NODE_PRIVATE(node);
  436 
  437         /* Zero out hook pointer */
  438         if (hook == priv->upper)
  439                 priv->upper = NULL;
  440         else if (hook == priv->lower)
  441                 priv->lower = NULL;
  442         else
  443                 panic("%s: unknown hook", __func__);
  444 
  445         /* Go away if no longer connected to anything */
  446         if ((NG_NODE_NUMHOOKS(node) == 0)
  447         && (NG_NODE_IS_VALID(node)))
  448                 ng_rmnode_self(node);
  449         return (0);
  450 }
  451 
  452 /*************************************************************************
  453                     TRANSMIT AND RECEIVE FUNCTIONS
  454 *************************************************************************/
  455 
  456 /*
  457  * Transmit an outgoing frame, or just an ack if m is NULL.
  458  */
  459 static int
  460 ng_pptpgre_xmit(node_p node, item_p item)
  461 {
  462         const priv_p priv = NG_NODE_PRIVATE(node);
  463         struct ng_pptpgre_ackp *const a = &priv->ackp;
  464         u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
  465         struct greheader *const gre = (struct greheader *)buf;
  466         int grelen, error;
  467         struct mbuf *m;
  468 
  469         if (item) {
  470                 NGI_GET_M(item, m);
  471         } else {
  472                 m = NULL;
  473         }
  474         /* Check if there's data */
  475         if (m != NULL) {
  476 
  477                 /* Check if windowing is enabled */
  478                 if (priv->conf.enableWindowing) {
  479                         /* Is our transmit window full? */
  480                         if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq,
  481                             priv->recvAck) >= a->xmitWin) {
  482                                 priv->stats.xmitDrops++;
  483                                 NG_FREE_M(m);
  484                                 NG_FREE_ITEM(item);
  485                                 return (ENOBUFS);
  486                         }
  487                 }
  488 
  489                 /* Sanity check frame length */
  490                 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
  491                         priv->stats.xmitTooBig++;
  492                         NG_FREE_M(m);
  493                         NG_FREE_ITEM(item);
  494                         return (EMSGSIZE);
  495                 }
  496         } else {
  497                 priv->stats.xmitLoneAcks++;
  498         }
  499 
  500         /* Build GRE header */
  501         ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
  502         gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
  503         gre->cid = htons(priv->conf.peerCid);
  504 
  505         /* Include sequence number if packet contains any data */
  506         if (m != NULL) {
  507                 gre->hasSeq = 1;
  508                 if (priv->conf.enableWindowing) {
  509                         a->timeSent[priv->xmitSeq - priv->recvAck]
  510                             = ng_pptpgre_time(node);
  511                 }
  512                 priv->xmitSeq++;
  513                 gre->data[0] = htonl(priv->xmitSeq);
  514         }
  515 
  516         /* Include acknowledgement (and stop send ack timer) if needed */
  517         if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
  518                 gre->hasAck = 1;
  519                 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
  520                 priv->xmitAck = priv->recvSeq;
  521                 ng_pptpgre_stop_send_ack_timer(node);
  522         }
  523 
  524         /* Prepend GRE header to outgoing frame */
  525         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  526         if (m == NULL) {
  527                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  528                 if (m == NULL) {
  529                         priv->stats.memoryFailures++;
  530                         if (item)
  531                                 NG_FREE_ITEM(item);
  532                         return (ENOBUFS);
  533                 }
  534                 m->m_len = m->m_pkthdr.len = grelen;
  535                 m->m_pkthdr.rcvif = NULL;
  536         } else {
  537                 M_PREPEND(m, grelen, M_DONTWAIT);
  538                 if (m == NULL || (m->m_len < grelen
  539                     && (m = m_pullup(m, grelen)) == NULL)) {
  540                         priv->stats.memoryFailures++;
  541                         if (item)
  542                                 NG_FREE_ITEM(item);
  543                         return (ENOBUFS);
  544                 }
  545         }
  546         bcopy(gre, mtod(m, u_char *), grelen);
  547 
  548         /* Update stats */
  549         priv->stats.xmitPackets++;
  550         priv->stats.xmitOctets += m->m_pkthdr.len;
  551 
  552         /* Deliver packet */
  553         if (item) {
  554                 NG_FWD_NEW_DATA(error, item, priv->lower, m);
  555         } else {
  556                 NG_SEND_DATA_ONLY(error, priv->lower, m);
  557         }
  558 
  559 
  560         /* Start receive ACK timer if data was sent and not already running */
  561         if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
  562                 ng_pptpgre_start_recv_ack_timer(node);
  563         return (error);
  564 }
  565 
  566 /*
  567  * Handle an incoming packet.  The packet includes the IP header.
  568  */
  569 static int
  570 ng_pptpgre_recv(node_p node, item_p item)
  571 {
  572         const priv_p priv = NG_NODE_PRIVATE(node);
  573         int iphlen, grelen, extralen;
  574         const struct greheader *gre;
  575         const struct ip *ip;
  576         int error = 0;
  577         struct mbuf *m;
  578 
  579         NGI_GET_M(item, m);
  580         /* Update stats */
  581         priv->stats.recvPackets++;
  582         priv->stats.recvOctets += m->m_pkthdr.len;
  583 
  584         /* Sanity check packet length */
  585         if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
  586                 priv->stats.recvRunts++;
  587 bad:
  588                 NG_FREE_M(m);
  589                 NG_FREE_ITEM(item);
  590                 return (EINVAL);
  591         }
  592 
  593         /* Safely pull up the complete IP+GRE headers */
  594         if (m->m_len < sizeof(*ip) + sizeof(*gre)
  595             && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
  596                 priv->stats.memoryFailures++;
  597                 NG_FREE_ITEM(item);
  598                 return (ENOBUFS);
  599         }
  600         ip = mtod(m, const struct ip *);
  601         iphlen = ip->ip_hl << 2;
  602         if (m->m_len < iphlen + sizeof(*gre)) {
  603                 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
  604                         priv->stats.memoryFailures++;
  605                         NG_FREE_ITEM(item);
  606                         return (ENOBUFS);
  607                 }
  608                 ip = mtod(m, const struct ip *);
  609         }
  610         gre = (const struct greheader *)((const u_char *)ip + iphlen);
  611         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  612         if (m->m_pkthdr.len < iphlen + grelen) {
  613                 priv->stats.recvRunts++;
  614                 goto bad;
  615         }
  616         if (m->m_len < iphlen + grelen) {
  617                 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
  618                         priv->stats.memoryFailures++;
  619                         NG_FREE_ITEM(item);
  620                         return (ENOBUFS);
  621                 }
  622                 ip = mtod(m, const struct ip *);
  623                 gre = (const struct greheader *)((const u_char *)ip + iphlen);
  624         }
  625 
  626         /* Sanity check packet length and GRE header bits */
  627         extralen = m->m_pkthdr.len
  628             - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
  629         if (extralen < 0) {
  630                 priv->stats.recvBadGRE++;
  631                 goto bad;
  632         }
  633         if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
  634             != PPTP_INIT_VALUE) {
  635                 priv->stats.recvBadGRE++;
  636                 goto bad;
  637         }
  638         if (ntohs(gre->cid) != priv->conf.cid) {
  639                 priv->stats.recvBadCID++;
  640                 goto bad;
  641         }
  642 
  643         /* Look for peer ack */
  644         if (gre->hasAck) {
  645                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  646                 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
  647                 const int index = ack - priv->recvAck - 1;
  648                 long sample;
  649                 long diff;
  650 
  651                 /* Sanity check ack value */
  652                 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
  653                         priv->stats.recvBadAcks++;
  654                         goto badAck;            /* we never sent it! */
  655                 }
  656                 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
  657                         goto badAck;            /* ack already timed out */
  658                 priv->recvAck = ack;
  659 
  660                 /* Update adaptive timeout stuff */
  661                 if (priv->conf.enableWindowing) {
  662                         sample = ng_pptpgre_time(node) - a->timeSent[index];
  663                         diff = sample - a->rtt;
  664                         a->rtt += PPTP_ACK_ALPHA(diff);
  665                         if (diff < 0)
  666                                 diff = -diff;
  667                         a->dev += PPTP_ACK_BETA(diff - a->dev);
  668                         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  669                         if (a->ato > PPTP_MAX_TIMEOUT)
  670                                 a->ato = PPTP_MAX_TIMEOUT;
  671                         if (a->ato < PPTP_MIN_TIMEOUT)
  672                                 a->ato = PPTP_MIN_TIMEOUT;
  673 
  674                         /* Shift packet transmit times in our transmit window */
  675                         bcopy(a->timeSent + index + 1, a->timeSent,
  676                             sizeof(*a->timeSent)
  677                               * (PPTP_XMIT_WIN - (index + 1)));
  678 
  679                         /* If we sent an entire window, increase window size */
  680                         if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
  681                             && a->xmitWin < PPTP_XMIT_WIN) {
  682                                 a->xmitWin++;
  683                                 a->winAck = ack + a->xmitWin;
  684                         }
  685 
  686                         /* Stop/(re)start receive ACK timer as necessary */
  687                         ng_pptpgre_stop_recv_ack_timer(node);
  688                         if (priv->recvAck != priv->xmitSeq)
  689                                 ng_pptpgre_start_recv_ack_timer(node);
  690                 }
  691         }
  692 badAck:
  693 
  694         /* See if frame contains any data */
  695         if (gre->hasSeq) {
  696                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  697                 const u_int32_t seq = ntohl(gre->data[0]);
  698 
  699                 /* Sanity check sequence number */
  700                 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
  701                         if (seq == priv->recvSeq)
  702                                 priv->stats.recvDuplicates++;
  703                         else
  704                                 priv->stats.recvOutOfOrder++;
  705                         goto bad;               /* out-of-order or dup */
  706                 }
  707                 priv->recvSeq = seq;
  708 
  709                 /* We need to acknowledge this packet; do it soon... */
  710                 if (a->sackTimerPtr == NULL) {
  711                         int maxWait;
  712 
  713                         /* Take 1/4 of the estimated round trip time */
  714                         maxWait = (a->rtt >> 2);
  715 
  716                         /* If delayed ACK is disabled, send it now */
  717                         if (!priv->conf.enableDelayedAck)       /* ack now */
  718                                 ng_pptpgre_xmit(node, NULL);
  719                         else {                                  /* ack later */
  720                                 if (maxWait < PPTP_MIN_ACK_DELAY)
  721                                         maxWait = PPTP_MIN_ACK_DELAY;
  722                                 if (maxWait > PPTP_MAX_ACK_DELAY)
  723                                         maxWait = PPTP_MAX_ACK_DELAY;
  724                                 ng_pptpgre_start_send_ack_timer(node, maxWait);
  725                         }
  726                 }
  727 
  728                 /* Trim mbuf down to internal payload */
  729                 m_adj(m, iphlen + grelen);
  730                 if (extralen > 0)
  731                         m_adj(m, -extralen);
  732 
  733                 /* Deliver frame to upper layers */
  734                 NG_FWD_NEW_DATA(error, item, priv->upper, m);
  735         } else {
  736                 priv->stats.recvLoneAcks++;
  737                 NG_FREE_ITEM(item);
  738                 NG_FREE_M(m);           /* no data to deliver */
  739         }
  740         return (error);
  741 }
  742 
  743 /*************************************************************************
  744                     TIMER RELATED FUNCTIONS
  745 *************************************************************************/
  746 
  747 /*
  748  * Start a timer for the peer's acknowledging our oldest unacknowledged
  749  * sequence number.  If we get an ack for this sequence number before
  750  * the timer goes off, we cancel the timer.  Resets currently running
  751  * recv ack timer, if any.
  752  */
  753 static void
  754 ng_pptpgre_start_recv_ack_timer(node_p node)
  755 {
  756         const priv_p priv = NG_NODE_PRIVATE(node);
  757         struct ng_pptpgre_ackp *const a = &priv->ackp;
  758         int remain, ticks;
  759 
  760         if (!priv->conf.enableWindowing)
  761                 return;
  762 
  763         /* Compute how long until oldest unack'd packet times out,
  764            and reset the timer to that time. */
  765         KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__));
  766         remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
  767         if (remain < 0)
  768                 remain = 0;
  769 #ifdef DEBUG_RAT
  770         a->timerLength = remain;
  771         a->timerStart = ng_pptpgre_time(node);
  772 #endif
  773 
  774         /* Start new timer */
  775         MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
  776         if (a->rackTimerPtr == NULL) {
  777                 priv->stats.memoryFailures++;
  778                 return;                 /* XXX potential hang here */
  779         }
  780         *a->rackTimerPtr = node;        /* ensures the correct timeout event */
  781         NG_NODE_REF(node);
  782         priv->timers++;
  783 
  784         /* Be conservative: timeout can happen up to 1 tick early */
  785         ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
  786         callout_reset(&a->rackTimer, ticks,
  787             ng_pptpgre_recv_ack_timeout, a->rackTimerPtr);
  788 }
  789 
  790 /*
  791  * Stop receive ack timer.
  792  */
  793 static void
  794 ng_pptpgre_stop_recv_ack_timer(node_p node)
  795 {
  796         const priv_p priv = NG_NODE_PRIVATE(node);
  797         struct ng_pptpgre_ackp *const a = &priv->ackp;
  798 
  799         if (!priv->conf.enableWindowing)
  800                 return;
  801 
  802         if (callout_stop(&a->rackTimer)) {
  803                 FREE(a->rackTimerPtr, M_NETGRAPH);
  804                 priv->timers--;
  805                 NG_NODE_UNREF(node);
  806         }
  807         a->rackTimerPtr = NULL;
  808 }
  809 
  810 /*
  811  * The peer has failed to acknowledge the oldest unacknowledged sequence
  812  * number within the time allotted.  Update our adaptive timeout parameters
  813  * and reset/restart the recv ack timer.
  814  */
  815 static void
  816 ng_pptpgre_recv_ack_timeout(void *arg)
  817 {
  818         int s = splnet();
  819         const node_p node = *((node_p *)arg);
  820         const priv_p priv = NG_NODE_PRIVATE(node);
  821         struct ng_pptpgre_ackp *const a = &priv->ackp;
  822 
  823         /* This complicated stuff is needed to avoid race conditions */
  824         FREE(arg, M_NETGRAPH);
  825         KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
  826         KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
  827         priv->timers--;
  828         if (NG_NODE_NOT_VALID(node)) {  /* shutdown race condition */
  829                 if (priv->timers == 0) {
  830                         FREE(priv, M_NETGRAPH);
  831                         NG_NODE_SET_PRIVATE(node, NULL);
  832                 }
  833                 NG_NODE_UNREF(node);
  834                 splx(s);
  835                 return;
  836         }
  837         if (arg != a->rackTimerPtr) {   /* timer stopped race condition */
  838                 NG_NODE_UNREF(node);
  839                 splx(s);
  840                 return;
  841         }
  842         a->rackTimerPtr = NULL;
  843 
  844         /* Update adaptive timeout stuff */
  845         priv->stats.recvAckTimeouts++;
  846         a->rtt = PPTP_ACK_DELTA(a->rtt);
  847         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  848         if (a->ato > PPTP_MAX_TIMEOUT)
  849                 a->ato = PPTP_MAX_TIMEOUT;
  850         if (a->ato < PPTP_MIN_TIMEOUT)
  851                 a->ato = PPTP_MIN_TIMEOUT;
  852 
  853 #ifdef DEBUG_RAT
  854     log(LOG_DEBUG,
  855         "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
  856         (int)ng_pptpgre_time(node), priv->recvAck + 1,
  857         (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
  858 #endif
  859 
  860         /* Reset ack and sliding window */
  861         priv->recvAck = priv->xmitSeq;          /* pretend we got the ack */
  862         a->xmitWin = (a->xmitWin + 1) / 2;      /* shrink transmit window */
  863         a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */
  864         NG_NODE_UNREF(node);
  865         splx(s);
  866 }
  867 
  868 /*
  869  * Start the send ack timer. This assumes the timer is not
  870  * already running.
  871  */
  872 static void
  873 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
  874 {
  875         const priv_p priv = NG_NODE_PRIVATE(node);
  876         struct ng_pptpgre_ackp *const a = &priv->ackp;
  877         int ticks;
  878 
  879         /* Start new timer */
  880         KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__));
  881         MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
  882         if (a->sackTimerPtr == NULL) {
  883                 priv->stats.memoryFailures++;
  884                 return;                 /* XXX potential hang here */
  885         }
  886         *a->sackTimerPtr = node;        /* ensures the correct timeout event */
  887         NG_NODE_REF(node);
  888         priv->timers++;
  889 
  890         /* Be conservative: timeout can happen up to 1 tick early */
  891         ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
  892         callout_reset(&a->sackTimer, ticks,
  893             ng_pptpgre_send_ack_timeout, a->sackTimerPtr);
  894 }
  895 
  896 /*
  897  * Stop send ack timer.
  898  */
  899 static void
  900 ng_pptpgre_stop_send_ack_timer(node_p node)
  901 {
  902         const priv_p priv = NG_NODE_PRIVATE(node);
  903         struct ng_pptpgre_ackp *const a = &priv->ackp;
  904 
  905         if (callout_stop(&a->sackTimer)) {
  906                 FREE(a->sackTimerPtr, M_NETGRAPH);
  907                 priv->timers--;
  908                 NG_NODE_UNREF(node);
  909         }
  910         a->sackTimerPtr = NULL;
  911 }
  912 
  913 /*
  914  * We've waited as long as we're willing to wait before sending an
  915  * acknowledgement to the peer for received frames. We had hoped to
  916  * be able to piggy back our acknowledgement on an outgoing data frame,
  917  * but apparently there haven't been any since. So send the ack now.
  918  */
  919 static void
  920 ng_pptpgre_send_ack_timeout(void *arg)
  921 {
  922         int s = splnet();
  923         const node_p node = *((node_p *)arg);
  924         const priv_p priv = NG_NODE_PRIVATE(node);
  925         struct ng_pptpgre_ackp *const a = &priv->ackp;
  926 
  927         /* This complicated stuff is needed to avoid race conditions */
  928         FREE(arg, M_NETGRAPH);
  929         KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
  930         KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
  931         priv->timers--;
  932         if (NG_NODE_NOT_VALID(node)) {  /* shutdown race condition */
  933                 if (priv->timers == 0) {
  934                         FREE(priv, M_NETGRAPH);
  935                         NG_NODE_SET_PRIVATE(node, NULL);
  936                 }
  937                 NG_NODE_UNREF(node);
  938                 splx(s);
  939                 return;
  940         }
  941         if (a->sackTimerPtr != arg) {   /* timer stopped race condition */
  942                 NG_NODE_UNREF(node);
  943                 splx(s);
  944                 return;
  945         }
  946         a->sackTimerPtr = NULL;
  947 
  948         /* Send a frame with an ack but no payload */
  949         ng_pptpgre_xmit(node, NULL);
  950         NG_NODE_UNREF(node);
  951         splx(s);
  952 }
  953 
  954 /*************************************************************************
  955                     MISC FUNCTIONS
  956 *************************************************************************/
  957 
  958 /*
  959  * Reset state
  960  */
  961 static void
  962 ng_pptpgre_reset(node_p node)
  963 {
  964         const priv_p priv = NG_NODE_PRIVATE(node);
  965         struct ng_pptpgre_ackp *const a = &priv->ackp;
  966 
  967         /* Reset adaptive timeout state */
  968         a->ato = PPTP_MAX_TIMEOUT;
  969         a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
  970         if (a->rtt < PPTP_MIN_RTT)
  971                 a->rtt = PPTP_MIN_RTT;
  972         a->dev = 0;
  973         a->xmitWin = (priv->conf.recvWin + 1) / 2;
  974         if (a->xmitWin < 2)             /* often the first packet is lost */
  975                 a->xmitWin = 2;         /*   because the peer isn't ready */
  976         if (a->xmitWin > PPTP_XMIT_WIN)
  977                 a->xmitWin = PPTP_XMIT_WIN;
  978         a->winAck = a->xmitWin;
  979 
  980         /* Reset sequence numbers */
  981         priv->recvSeq = ~0;
  982         priv->recvAck = ~0;
  983         priv->xmitSeq = ~0;
  984         priv->xmitAck = ~0;
  985 
  986         /* Reset start time */
  987         getmicrouptime(&priv->startTime);
  988 
  989         /* Reset stats */
  990         bzero(&priv->stats, sizeof(priv->stats));
  991 
  992         /* Stop timers */
  993         ng_pptpgre_stop_send_ack_timer(node);
  994         ng_pptpgre_stop_recv_ack_timer(node);
  995 }
  996 
  997 /*
  998  * Return the current time scaled & translated to our internally used format.
  999  */
 1000 static pptptime_t
 1001 ng_pptpgre_time(node_p node)
 1002 {
 1003         const priv_p priv = NG_NODE_PRIVATE(node);
 1004         struct timeval tv;
 1005         pptptime_t t;
 1006 
 1007         microuptime(&tv);
 1008         if (tv.tv_sec < priv->startTime.tv_sec
 1009             || (tv.tv_sec == priv->startTime.tv_sec
 1010               && tv.tv_usec < priv->startTime.tv_usec))
 1011                 return (0);
 1012         timevalsub(&tv, &priv->startTime);
 1013         t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
 1014         t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
 1015         return(t);
 1016 }
 1017 

Cache object: bbaa86f2f2877698b8e0e75ca75fe984


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.