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  * ng_pptpgre.c
    3  */
    4 
    5 /*-
    6  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    7  * All rights reserved.
    8  * 
    9  * Subject to the following obligations and disclaimer of warranty, use and
   10  * redistribution of this software, in source or object code forms, with or
   11  * without modifications are expressly permitted by Whistle Communications;
   12  * provided, however, that:
   13  * 1. Any and all reproductions of the source or object code must include the
   14  *    copyright notice above and the following disclaimer of warranties; and
   15  * 2. No rights are granted, in any manner or form, to use Whistle
   16  *    Communications, Inc. trademarks, including the mark "WHISTLE
   17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   18  *    such appears in the above copyright notice or in the software.
   19  * 
   20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   36  * OF SUCH DAMAGE.
   37  *
   38  * Author: Archie Cobbs <archie@freebsd.org>
   39  *
   40  * $FreeBSD$
   41  * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $
   42  */
   43 
   44 /*
   45  * PPTP/GRE netgraph node type.
   46  *
   47  * This node type does the GRE encapsulation as specified for the PPTP
   48  * protocol (RFC 2637, section 4).  This includes sequencing and
   49  * retransmission of frames, but not the actual packet delivery nor
   50  * any of the TCP control stream protocol.
   51  *
   52  * The "upper" hook of this node is suitable for attaching to a "ppp"
   53  * node link hook.  The "lower" hook of this node is suitable for attaching
   54  * to a "ksocket" node on hook "inet/raw/gre".
   55  */
   56 
   57 #include <sys/param.h>
   58 #include <sys/systm.h>
   59 #include <sys/kernel.h>
   60 #include <sys/time.h>
   61 #include <sys/mbuf.h>
   62 #include <sys/malloc.h>
   63 #include <sys/errno.h>
   64 
   65 #include <netinet/in.h>
   66 #include <netinet/in_systm.h>
   67 #include <netinet/ip.h>
   68 
   69 #include <netgraph/ng_message.h>
   70 #include <netgraph/netgraph.h>
   71 #include <netgraph/ng_parse.h>
   72 #include <netgraph/ng_pptpgre.h>
   73 
   74 /* GRE packet format, as used by PPTP */
   75 struct greheader {
   76 #if BYTE_ORDER == LITTLE_ENDIAN
   77         u_char          recursion:3;            /* recursion control */
   78         u_char          ssr:1;                  /* strict source route */
   79         u_char          hasSeq:1;               /* sequence number present */
   80         u_char          hasKey:1;               /* key present */
   81         u_char          hasRoute:1;             /* routing present */
   82         u_char          hasSum:1;               /* checksum present */
   83         u_char          vers:3;                 /* version */
   84         u_char          flags:4;                /* flags */
   85         u_char          hasAck:1;               /* acknowlege number present */
   86 #elif BYTE_ORDER == BIG_ENDIAN
   87         u_char          hasSum:1;               /* checksum present */
   88         u_char          hasRoute:1;             /* routing present */
   89         u_char          hasKey:1;               /* key present */
   90         u_char          hasSeq:1;               /* sequence number present */
   91         u_char          ssr:1;                  /* strict source route */
   92         u_char          recursion:3;            /* recursion control */
   93         u_char          hasAck:1;               /* acknowlege number present */
   94         u_char          flags:4;                /* flags */
   95         u_char          vers:3;                 /* version */
   96 #else
   97 #error BYTE_ORDER is not defined properly
   98 #endif
   99         u_int16_t       proto;                  /* protocol (ethertype) */
  100         u_int16_t       length;                 /* payload length */
  101         u_int16_t       cid;                    /* call id */
  102         u_int32_t       data[0];                /* opt. seq, ack, then data */
  103 };
  104 
  105 /* The PPTP protocol ID used in the GRE 'proto' field */
  106 #define PPTP_GRE_PROTO          0x880b
  107 
  108 /* Bits that must be set a certain way in all PPTP/GRE packets */
  109 #define PPTP_INIT_VALUE         ((0x2001 << 16) | PPTP_GRE_PROTO)
  110 #define PPTP_INIT_MASK          0xef7fffff
  111 
  112 /* Min and max packet length */
  113 #define PPTP_MAX_PAYLOAD        (0xffff - sizeof(struct greheader) - 8)
  114 
  115 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
  116 #define PPTP_TIME_SCALE         1000                    /* milliseconds */
  117 typedef u_int64_t               pptptime_t;
  118 
  119 /* Acknowledgment timeout parameters and functions */
  120 #define PPTP_XMIT_WIN           16                      /* max xmit window */
  121 #define PPTP_MIN_RTT            (PPTP_TIME_SCALE / 10)  /* 100 milliseconds */
  122 #define PPTP_MIN_TIMEOUT        (PPTP_TIME_SCALE / 83)  /* 12 milliseconds */
  123 #define PPTP_MAX_TIMEOUT        (3 * PPTP_TIME_SCALE)   /* 3 seconds */
  124 
  125 /* When we recieve a packet, we wait to see if there's an outgoing packet
  126    we can piggy-back the ACK off of. These parameters determine the mimimum
  127    and maxmimum length of time we're willing to wait in order to do that.
  128    These have no effect unless "enableDelayedAck" is turned on. */
  129 #define PPTP_MIN_ACK_DELAY      (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
  130 #define PPTP_MAX_ACK_DELAY      (PPTP_TIME_SCALE / 2)   /* 500 milliseconds */
  131 
  132 /* See RFC 2637 section 4.4 */
  133 #define PPTP_ACK_ALPHA(x)       ((x) >> 3)      /* alpha = 0.125 */
  134 #define PPTP_ACK_BETA(x)        ((x) >> 2)      /* beta = 0.25 */
  135 #define PPTP_ACK_CHI(x)         ((x) << 2)      /* chi = 4 */
  136 #define PPTP_ACK_DELTA(x)       ((x) << 1)      /* delta = 2 */
  137 
  138 #define PPTP_SEQ_DIFF(x,y)      ((int32_t)(x) - (int32_t)(y))
  139 
  140 /* We keep packet retransmit and acknowlegement state in this struct */
  141 struct ng_pptpgre_ackp {
  142         int32_t                 ato;            /* adaptive time-out value */
  143         int32_t                 rtt;            /* round trip time estimate */
  144         int32_t                 dev;            /* deviation estimate */
  145         u_int16_t               xmitWin;        /* size of xmit window */
  146         struct callout          sackTimer;      /* send ack timer */
  147         struct callout          rackTimer;      /* recv ack timer */
  148         u_int32_t               winAck;         /* seq when xmitWin will grow */
  149         pptptime_t              timeSent[PPTP_XMIT_WIN];
  150 #ifdef DEBUG_RAT
  151         pptptime_t              timerStart;     /* when rackTimer started */
  152         pptptime_t              timerLength;    /* rackTimer duration */
  153 #endif
  154 };
  155 
  156 /* Node private data */
  157 struct ng_pptpgre_private {
  158         hook_p                  upper;          /* hook to upper layers */
  159         hook_p                  lower;          /* hook to lower layers */
  160         struct ng_pptpgre_conf  conf;           /* configuration info */
  161         struct ng_pptpgre_ackp  ackp;           /* packet transmit ack state */
  162         u_int32_t               recvSeq;        /* last seq # we rcv'd */
  163         u_int32_t               xmitSeq;        /* last seq # we sent */
  164         u_int32_t               recvAck;        /* last seq # peer ack'd */
  165         u_int32_t               xmitAck;        /* last seq # we ack'd */
  166         struct timeval          startTime;      /* time node was created */
  167         struct ng_pptpgre_stats stats;          /* node statistics */
  168 };
  169 typedef struct ng_pptpgre_private *priv_p;
  170 
  171 /* Netgraph node methods */
  172 static ng_constructor_t ng_pptpgre_constructor;
  173 static ng_rcvmsg_t      ng_pptpgre_rcvmsg;
  174 static ng_shutdown_t    ng_pptpgre_shutdown;
  175 static ng_newhook_t     ng_pptpgre_newhook;
  176 static ng_rcvdata_t     ng_pptpgre_rcvdata;
  177 static ng_disconnect_t  ng_pptpgre_disconnect;
  178 
  179 /* Helper functions */
  180 static int      ng_pptpgre_xmit(node_p node, item_p item);
  181 static int      ng_pptpgre_recv(node_p node, item_p item);
  182 static void     ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
  183 static void     ng_pptpgre_stop_send_ack_timer(node_p node);
  184 static void     ng_pptpgre_start_recv_ack_timer(node_p node);
  185 static void     ng_pptpgre_stop_recv_ack_timer(node_p node);
  186 static void     ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook,
  187                     void *arg1, int arg2);
  188 static void     ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
  189                     void *arg1, int arg2);
  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         ng_callout_init(&priv->ackp.sackTimer);
  286         ng_callout_init(&priv->ackp.rackTimer);
  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 (stops timers) */
  414         ng_pptpgre_reset(node);
  415 
  416         FREE(priv, M_NETGRAPH);
  417 
  418         /* Decrement ref count */
  419         NG_NODE_UNREF(node);
  420         return (0);
  421 }
  422 
  423 /*
  424  * Hook disconnection
  425  */
  426 static int
  427 ng_pptpgre_disconnect(hook_p hook)
  428 {
  429         const node_p node = NG_HOOK_NODE(hook);
  430         const priv_p priv = NG_NODE_PRIVATE(node);
  431 
  432         /* Zero out hook pointer */
  433         if (hook == priv->upper)
  434                 priv->upper = NULL;
  435         else if (hook == priv->lower)
  436                 priv->lower = NULL;
  437         else
  438                 panic("%s: unknown hook", __func__);
  439 
  440         /* Go away if no longer connected to anything */
  441         if ((NG_NODE_NUMHOOKS(node) == 0)
  442         && (NG_NODE_IS_VALID(node)))
  443                 ng_rmnode_self(node);
  444         return (0);
  445 }
  446 
  447 /*************************************************************************
  448                     TRANSMIT AND RECEIVE FUNCTIONS
  449 *************************************************************************/
  450 
  451 /*
  452  * Transmit an outgoing frame, or just an ack if m is NULL.
  453  */
  454 static int
  455 ng_pptpgre_xmit(node_p node, item_p item)
  456 {
  457         const priv_p priv = NG_NODE_PRIVATE(node);
  458         struct ng_pptpgre_ackp *const a = &priv->ackp;
  459         u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
  460         struct greheader *const gre = (struct greheader *)buf;
  461         int grelen, error;
  462         struct mbuf *m;
  463 
  464         if (item) {
  465                 NGI_GET_M(item, m);
  466         } else {
  467                 m = NULL;
  468         }
  469         /* Check if there's data */
  470         if (m != NULL) {
  471 
  472                 /* Check if windowing is enabled */
  473                 if (priv->conf.enableWindowing) {
  474                         /* Is our transmit window full? */
  475                         if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq,
  476                             priv->recvAck) >= a->xmitWin) {
  477                                 priv->stats.xmitDrops++;
  478                                 NG_FREE_M(m);
  479                                 NG_FREE_ITEM(item);
  480                                 return (ENOBUFS);
  481                         }
  482                 }
  483 
  484                 /* Sanity check frame length */
  485                 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
  486                         priv->stats.xmitTooBig++;
  487                         NG_FREE_M(m);
  488                         NG_FREE_ITEM(item);
  489                         return (EMSGSIZE);
  490                 }
  491         } else {
  492                 priv->stats.xmitLoneAcks++;
  493         }
  494 
  495         /* Build GRE header */
  496         ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
  497         gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
  498         gre->cid = htons(priv->conf.peerCid);
  499 
  500         /* Include sequence number if packet contains any data */
  501         if (m != NULL) {
  502                 gre->hasSeq = 1;
  503                 if (priv->conf.enableWindowing) {
  504                         a->timeSent[priv->xmitSeq - priv->recvAck]
  505                             = ng_pptpgre_time(node);
  506                 }
  507                 priv->xmitSeq++;
  508                 gre->data[0] = htonl(priv->xmitSeq);
  509         }
  510 
  511         /* Include acknowledgement (and stop send ack timer) if needed */
  512         if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
  513                 gre->hasAck = 1;
  514                 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
  515                 priv->xmitAck = priv->recvSeq;
  516                 ng_pptpgre_stop_send_ack_timer(node);
  517         }
  518 
  519         /* Prepend GRE header to outgoing frame */
  520         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  521         if (m == NULL) {
  522                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  523                 if (m == NULL) {
  524                         priv->stats.memoryFailures++;
  525                         if (item)
  526                                 NG_FREE_ITEM(item);
  527                         return (ENOBUFS);
  528                 }
  529                 m->m_len = m->m_pkthdr.len = grelen;
  530                 m->m_pkthdr.rcvif = NULL;
  531         } else {
  532                 M_PREPEND(m, grelen, M_DONTWAIT);
  533                 if (m == NULL || (m->m_len < grelen
  534                     && (m = m_pullup(m, grelen)) == NULL)) {
  535                         priv->stats.memoryFailures++;
  536                         if (item)
  537                                 NG_FREE_ITEM(item);
  538                         return (ENOBUFS);
  539                 }
  540         }
  541         bcopy(gre, mtod(m, u_char *), grelen);
  542 
  543         /* Update stats */
  544         priv->stats.xmitPackets++;
  545         priv->stats.xmitOctets += m->m_pkthdr.len;
  546 
  547         /* Deliver packet */
  548         if (item) {
  549                 NG_FWD_NEW_DATA(error, item, priv->lower, m);
  550         } else {
  551                 NG_SEND_DATA_ONLY(error, priv->lower, m);
  552         }
  553 
  554 
  555         /* Start receive ACK timer if data was sent and not already running */
  556         if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
  557                 ng_pptpgre_start_recv_ack_timer(node);
  558         return (error);
  559 }
  560 
  561 /*
  562  * Handle an incoming packet.  The packet includes the IP header.
  563  */
  564 static int
  565 ng_pptpgre_recv(node_p node, item_p item)
  566 {
  567         const priv_p priv = NG_NODE_PRIVATE(node);
  568         int iphlen, grelen, extralen;
  569         const struct greheader *gre;
  570         const struct ip *ip;
  571         int error = 0;
  572         struct mbuf *m;
  573 
  574         NGI_GET_M(item, m);
  575         /* Update stats */
  576         priv->stats.recvPackets++;
  577         priv->stats.recvOctets += m->m_pkthdr.len;
  578 
  579         /* Sanity check packet length */
  580         if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
  581                 priv->stats.recvRunts++;
  582 bad:
  583                 NG_FREE_M(m);
  584                 NG_FREE_ITEM(item);
  585                 return (EINVAL);
  586         }
  587 
  588         /* Safely pull up the complete IP+GRE headers */
  589         if (m->m_len < sizeof(*ip) + sizeof(*gre)
  590             && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
  591                 priv->stats.memoryFailures++;
  592                 NG_FREE_ITEM(item);
  593                 return (ENOBUFS);
  594         }
  595         ip = mtod(m, const struct ip *);
  596         iphlen = ip->ip_hl << 2;
  597         if (m->m_len < iphlen + sizeof(*gre)) {
  598                 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
  599                         priv->stats.memoryFailures++;
  600                         NG_FREE_ITEM(item);
  601                         return (ENOBUFS);
  602                 }
  603                 ip = mtod(m, const struct ip *);
  604         }
  605         gre = (const struct greheader *)((const u_char *)ip + iphlen);
  606         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  607         if (m->m_pkthdr.len < iphlen + grelen) {
  608                 priv->stats.recvRunts++;
  609                 goto bad;
  610         }
  611         if (m->m_len < iphlen + grelen) {
  612                 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
  613                         priv->stats.memoryFailures++;
  614                         NG_FREE_ITEM(item);
  615                         return (ENOBUFS);
  616                 }
  617                 ip = mtod(m, const struct ip *);
  618                 gre = (const struct greheader *)((const u_char *)ip + iphlen);
  619         }
  620 
  621         /* Sanity check packet length and GRE header bits */
  622         extralen = m->m_pkthdr.len
  623             - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
  624         if (extralen < 0) {
  625                 priv->stats.recvBadGRE++;
  626                 goto bad;
  627         }
  628         if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
  629             != PPTP_INIT_VALUE) {
  630                 priv->stats.recvBadGRE++;
  631                 goto bad;
  632         }
  633         if (ntohs(gre->cid) != priv->conf.cid) {
  634                 priv->stats.recvBadCID++;
  635                 goto bad;
  636         }
  637 
  638         /* Look for peer ack */
  639         if (gre->hasAck) {
  640                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  641                 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
  642                 const int index = ack - priv->recvAck - 1;
  643                 long sample;
  644                 long diff;
  645 
  646                 /* Sanity check ack value */
  647                 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
  648                         priv->stats.recvBadAcks++;
  649                         goto badAck;            /* we never sent it! */
  650                 }
  651                 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
  652                         goto badAck;            /* ack already timed out */
  653                 priv->recvAck = ack;
  654 
  655                 /* Update adaptive timeout stuff */
  656                 if (priv->conf.enableWindowing) {
  657                         sample = ng_pptpgre_time(node) - a->timeSent[index];
  658                         diff = sample - a->rtt;
  659                         a->rtt += PPTP_ACK_ALPHA(diff);
  660                         if (diff < 0)
  661                                 diff = -diff;
  662                         a->dev += PPTP_ACK_BETA(diff - a->dev);
  663                         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  664                         if (a->ato > PPTP_MAX_TIMEOUT)
  665                                 a->ato = PPTP_MAX_TIMEOUT;
  666                         if (a->ato < PPTP_MIN_TIMEOUT)
  667                                 a->ato = PPTP_MIN_TIMEOUT;
  668 
  669                         /* Shift packet transmit times in our transmit window */
  670                         bcopy(a->timeSent + index + 1, a->timeSent,
  671                             sizeof(*a->timeSent)
  672                               * (PPTP_XMIT_WIN - (index + 1)));
  673 
  674                         /* If we sent an entire window, increase window size */
  675                         if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
  676                             && a->xmitWin < PPTP_XMIT_WIN) {
  677                                 a->xmitWin++;
  678                                 a->winAck = ack + a->xmitWin;
  679                         }
  680 
  681                         /* Stop/(re)start receive ACK timer as necessary */
  682                         ng_pptpgre_stop_recv_ack_timer(node);
  683                         if (priv->recvAck != priv->xmitSeq)
  684                                 ng_pptpgre_start_recv_ack_timer(node);
  685                 }
  686         }
  687 badAck:
  688 
  689         /* See if frame contains any data */
  690         if (gre->hasSeq) {
  691                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  692                 const u_int32_t seq = ntohl(gre->data[0]);
  693 
  694                 /* Sanity check sequence number */
  695                 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
  696                         if (seq == priv->recvSeq)
  697                                 priv->stats.recvDuplicates++;
  698                         else
  699                                 priv->stats.recvOutOfOrder++;
  700                         goto bad;               /* out-of-order or dup */
  701                 }
  702                 priv->recvSeq = seq;
  703 
  704                 /* We need to acknowledge this packet; do it soon... */
  705                 if (!(callout_pending(&a->sackTimer))) {
  706                         int maxWait;
  707 
  708                         /* Take 1/4 of the estimated round trip time */
  709                         maxWait = (a->rtt >> 2);
  710 
  711                         /* If delayed ACK is disabled, send it now */
  712                         if (!priv->conf.enableDelayedAck)       /* ack now */
  713                                 ng_pptpgre_xmit(node, NULL);
  714                         else {                                  /* ack later */
  715                                 if (maxWait < PPTP_MIN_ACK_DELAY)
  716                                         maxWait = PPTP_MIN_ACK_DELAY;
  717                                 if (maxWait > PPTP_MAX_ACK_DELAY)
  718                                         maxWait = PPTP_MAX_ACK_DELAY;
  719                                 ng_pptpgre_start_send_ack_timer(node, maxWait);
  720                         }
  721                 }
  722 
  723                 /* Trim mbuf down to internal payload */
  724                 m_adj(m, iphlen + grelen);
  725                 if (extralen > 0)
  726                         m_adj(m, -extralen);
  727 
  728                 /* Deliver frame to upper layers */
  729                 NG_FWD_NEW_DATA(error, item, priv->upper, m);
  730         } else {
  731                 priv->stats.recvLoneAcks++;
  732                 NG_FREE_ITEM(item);
  733                 NG_FREE_M(m);           /* no data to deliver */
  734         }
  735         return (error);
  736 }
  737 
  738 /*************************************************************************
  739                     TIMER RELATED FUNCTIONS
  740 *************************************************************************/
  741 
  742 /*
  743  * Start a timer for the peer's acknowledging our oldest unacknowledged
  744  * sequence number.  If we get an ack for this sequence number before
  745  * the timer goes off, we cancel the timer.  Resets currently running
  746  * recv ack timer, if any.
  747  */
  748 static void
  749 ng_pptpgre_start_recv_ack_timer(node_p node)
  750 {
  751         const priv_p priv = NG_NODE_PRIVATE(node);
  752         struct ng_pptpgre_ackp *const a = &priv->ackp;
  753         int remain, ticks;
  754 
  755         if (!priv->conf.enableWindowing)
  756                 return;
  757 
  758         /* Compute how long until oldest unack'd packet times out,
  759            and reset the timer to that time. */
  760         remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
  761         if (remain < 0)
  762                 remain = 0;
  763 #ifdef DEBUG_RAT
  764         a->timerLength = remain;
  765         a->timerStart = ng_pptpgre_time(node);
  766 #endif
  767 
  768         /* Be conservative: timeout can happen up to 1 tick early */
  769         ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
  770         ng_callout(&a->rackTimer, node, NULL, ticks,
  771             ng_pptpgre_recv_ack_timeout, NULL, 0);
  772 }
  773 
  774 /*
  775  * Stop receive ack timer.
  776  */
  777 static void
  778 ng_pptpgre_stop_recv_ack_timer(node_p node)
  779 {
  780         const priv_p priv = NG_NODE_PRIVATE(node);
  781         struct ng_pptpgre_ackp *const a = &priv->ackp;
  782 
  783         if (!priv->conf.enableWindowing)
  784                 return;
  785 
  786         ng_uncallout(&a->rackTimer, node);
  787 }
  788 
  789 /*
  790  * The peer has failed to acknowledge the oldest unacknowledged sequence
  791  * number within the time allotted.  Update our adaptive timeout parameters
  792  * and reset/restart the recv ack timer.
  793  */
  794 static void
  795 ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
  796 {
  797         const priv_p priv = NG_NODE_PRIVATE(node);
  798         struct ng_pptpgre_ackp *const a = &priv->ackp;
  799 
  800 
  801         /* Update adaptive timeout stuff */
  802         priv->stats.recvAckTimeouts++;
  803         a->rtt = PPTP_ACK_DELTA(a->rtt);
  804         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  805         if (a->ato > PPTP_MAX_TIMEOUT)
  806                 a->ato = PPTP_MAX_TIMEOUT;
  807         if (a->ato < PPTP_MIN_TIMEOUT)
  808                 a->ato = PPTP_MIN_TIMEOUT;
  809 
  810 #ifdef DEBUG_RAT
  811     log(LOG_DEBUG,
  812         "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
  813         (int)ng_pptpgre_time(node), priv->recvAck + 1,
  814         (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
  815 #endif
  816 
  817         /* Reset ack and sliding window */
  818         priv->recvAck = priv->xmitSeq;          /* pretend we got the ack */
  819         a->xmitWin = (a->xmitWin + 1) / 2;      /* shrink transmit window */
  820         a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */
  821 }
  822 
  823 /*
  824  * Start the send ack timer. This assumes the timer is not
  825  * already running.
  826  */
  827 static void
  828 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
  829 {
  830         const priv_p priv = NG_NODE_PRIVATE(node);
  831         struct ng_pptpgre_ackp *const a = &priv->ackp;
  832         int ticks;
  833 
  834         /* Be conservative: timeout can happen up to 1 tick early */
  835         ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
  836         ng_callout(&a->sackTimer, node, NULL, ticks,
  837             ng_pptpgre_send_ack_timeout, NULL, 0);
  838 }
  839 
  840 /*
  841  * Stop send ack timer.
  842  */
  843 static void
  844 ng_pptpgre_stop_send_ack_timer(node_p node)
  845 {
  846         const priv_p priv = NG_NODE_PRIVATE(node);
  847         struct ng_pptpgre_ackp *const a = &priv->ackp;
  848 
  849         ng_uncallout(&a->sackTimer, node);
  850 }
  851 
  852 /*
  853  * We've waited as long as we're willing to wait before sending an
  854  * acknowledgement to the peer for received frames. We had hoped to
  855  * be able to piggy back our acknowledgement on an outgoing data frame,
  856  * but apparently there haven't been any since. So send the ack now.
  857  */
  858 static void
  859 ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
  860 {
  861         /* Send a frame with an ack but no payload */
  862         ng_pptpgre_xmit(node, NULL);
  863 }
  864 
  865 /*************************************************************************
  866                     MISC FUNCTIONS
  867 *************************************************************************/
  868 
  869 /*
  870  * Reset state
  871  */
  872 static void
  873 ng_pptpgre_reset(node_p node)
  874 {
  875         const priv_p priv = NG_NODE_PRIVATE(node);
  876         struct ng_pptpgre_ackp *const a = &priv->ackp;
  877 
  878         /* Reset adaptive timeout state */
  879         a->ato = PPTP_MAX_TIMEOUT;
  880         a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
  881         if (a->rtt < PPTP_MIN_RTT)
  882                 a->rtt = PPTP_MIN_RTT;
  883         a->dev = 0;
  884         a->xmitWin = (priv->conf.recvWin + 1) / 2;
  885         if (a->xmitWin < 2)             /* often the first packet is lost */
  886                 a->xmitWin = 2;         /*   because the peer isn't ready */
  887         if (a->xmitWin > PPTP_XMIT_WIN)
  888                 a->xmitWin = PPTP_XMIT_WIN;
  889         a->winAck = a->xmitWin;
  890 
  891         /* Reset sequence numbers */
  892         priv->recvSeq = ~0;
  893         priv->recvAck = ~0;
  894         priv->xmitSeq = ~0;
  895         priv->xmitAck = ~0;
  896 
  897         /* Reset start time */
  898         getmicrouptime(&priv->startTime);
  899 
  900         /* Reset stats */
  901         bzero(&priv->stats, sizeof(priv->stats));
  902 
  903         /* Stop timers */
  904         ng_pptpgre_stop_send_ack_timer(node);
  905         ng_pptpgre_stop_recv_ack_timer(node);
  906 }
  907 
  908 /*
  909  * Return the current time scaled & translated to our internally used format.
  910  */
  911 static pptptime_t
  912 ng_pptpgre_time(node_p node)
  913 {
  914         const priv_p priv = NG_NODE_PRIVATE(node);
  915         struct timeval tv;
  916         pptptime_t t;
  917 
  918         microuptime(&tv);
  919         if (tv.tv_sec < priv->startTime.tv_sec
  920             || (tv.tv_sec == priv->startTime.tv_sec
  921               && tv.tv_usec < priv->startTime.tv_usec))
  922                 return (0);
  923         timevalsub(&tv, &priv->startTime);
  924         t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
  925         t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
  926         return(t);
  927 }

Cache object: 33a928ebab4d3cd1a967761e11f091c8


[ 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.