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

Cache object: 1ccd89765387914c1eee00b403355179


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