[ 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  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  cheribsd  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD8-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
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: src/sys/netgraph/ng_pptpgre.c,v 1.37.2.1 2005/09/20 13:40:55 glebius Exp $
   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/lock.h>
   62 #include <sys/malloc.h>
   63 #include <sys/mbuf.h>
   64 #include <sys/mutex.h>
   65 #include <sys/errno.h>
   66 
   67 #include <netinet/in.h>
   68 #include <netinet/in_systm.h>
   69 #include <netinet/ip.h>
   70 
   71 #include <netgraph/ng_message.h>
   72 #include <netgraph/netgraph.h>
   73 #include <netgraph/ng_parse.h>
   74 #include <netgraph/ng_pptpgre.h>
   75 
   76 /* GRE packet format, as used by PPTP */
   77 struct greheader {
   78 #if BYTE_ORDER == LITTLE_ENDIAN
   79         u_char          recursion:3;            /* recursion control */
   80         u_char          ssr:1;                  /* strict source route */
   81         u_char          hasSeq:1;               /* sequence number present */
   82         u_char          hasKey:1;               /* key present */
   83         u_char          hasRoute:1;             /* routing present */
   84         u_char          hasSum:1;               /* checksum present */
   85         u_char          vers:3;                 /* version */
   86         u_char          flags:4;                /* flags */
   87         u_char          hasAck:1;               /* acknowlege number present */
   88 #elif BYTE_ORDER == BIG_ENDIAN
   89         u_char          hasSum:1;               /* checksum present */
   90         u_char          hasRoute:1;             /* routing present */
   91         u_char          hasKey:1;               /* key present */
   92         u_char          hasSeq:1;               /* sequence number present */
   93         u_char          ssr:1;                  /* strict source route */
   94         u_char          recursion:3;            /* recursion control */
   95         u_char          hasAck:1;               /* acknowlege number present */
   96         u_char          flags:4;                /* flags */
   97         u_char          vers:3;                 /* version */
   98 #else
   99 #error BYTE_ORDER is not defined properly
  100 #endif
  101         u_int16_t       proto;                  /* protocol (ethertype) */
  102         u_int16_t       length;                 /* payload length */
  103         u_int16_t       cid;                    /* call id */
  104         u_int32_t       data[0];                /* opt. seq, ack, then data */
  105 };
  106 
  107 /* The PPTP protocol ID used in the GRE 'proto' field */
  108 #define PPTP_GRE_PROTO          0x880b
  109 
  110 /* Bits that must be set a certain way in all PPTP/GRE packets */
  111 #define PPTP_INIT_VALUE         ((0x2001 << 16) | PPTP_GRE_PROTO)
  112 #define PPTP_INIT_MASK          0xef7fffff
  113 
  114 /* Min and max packet length */
  115 #define PPTP_MAX_PAYLOAD        (0xffff - sizeof(struct greheader) - 8)
  116 
  117 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
  118 #define PPTP_TIME_SCALE         1000                    /* milliseconds */
  119 typedef u_int64_t               pptptime_t;
  120 
  121 /* Acknowledgment timeout parameters and functions */
  122 #define PPTP_XMIT_WIN           16                      /* max xmit window */
  123 #define PPTP_MIN_RTT            (PPTP_TIME_SCALE / 10)  /* 100 milliseconds */
  124 #define PPTP_MIN_TIMEOUT        (PPTP_TIME_SCALE / 83)  /* 12 milliseconds */
  125 #define PPTP_MAX_TIMEOUT        (3 * PPTP_TIME_SCALE)   /* 3 seconds */
  126 
  127 /* When we recieve a packet, we wait to see if there's an outgoing packet
  128    we can piggy-back the ACK off of. These parameters determine the mimimum
  129    and maxmimum length of time we're willing to wait in order to do that.
  130    These have no effect unless "enableDelayedAck" is turned on. */
  131 #define PPTP_MIN_ACK_DELAY      (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
  132 #define PPTP_MAX_ACK_DELAY      (PPTP_TIME_SCALE / 2)   /* 500 milliseconds */
  133 
  134 /* See RFC 2637 section 4.4 */
  135 #define PPTP_ACK_ALPHA(x)       ((x) >> 3)      /* alpha = 0.125 */
  136 #define PPTP_ACK_BETA(x)        ((x) >> 2)      /* beta = 0.25 */
  137 #define PPTP_ACK_CHI(x)         ((x) << 2)      /* chi = 4 */
  138 #define PPTP_ACK_DELTA(x)       ((x) << 1)      /* delta = 2 */
  139 
  140 #define PPTP_SEQ_DIFF(x,y)      ((int32_t)(x) - (int32_t)(y))
  141 
  142 /* We keep packet retransmit and acknowlegement state in this struct */
  143 struct ng_pptpgre_ackp {
  144         int32_t                 ato;            /* adaptive time-out value */
  145         int32_t                 rtt;            /* round trip time estimate */
  146         int32_t                 dev;            /* deviation estimate */
  147         u_int16_t               xmitWin;        /* size of xmit window */
  148         struct callout          sackTimer;      /* send ack timer */
  149         struct callout          rackTimer;      /* recv ack timer */
  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         struct timeval          startTime;      /* time node was created */
  169         struct ng_pptpgre_stats stats;          /* node statistics */
  170         struct mtx              mtx;            /* node mutex */
  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_shutdown;
  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, item_p item);
  184 static int      ng_pptpgre_recv(node_p node, item_p item);
  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(node_p node, hook_p hook,
  190                     void *arg1, int arg2);
  191 static void     ng_pptpgre_send_ack_timeout(node_p node, hook_p hook,
  192                     void *arg1, int arg2);
  193 static void     ng_pptpgre_reset(node_p node);
  194 static pptptime_t ng_pptpgre_time(node_p node);
  195 
  196 /* Parse type for struct ng_pptpgre_conf */
  197 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
  198         = NG_PPTPGRE_CONF_TYPE_INFO;
  199 static const struct ng_parse_type ng_pptpgre_conf_type = {
  200         &ng_parse_struct_type,
  201         &ng_pptpgre_conf_type_fields,
  202 };
  203 
  204 /* Parse type for struct ng_pptpgre_stats */
  205 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
  206         = NG_PPTPGRE_STATS_TYPE_INFO;
  207 static const struct ng_parse_type ng_pptp_stats_type = {
  208         &ng_parse_struct_type,
  209         &ng_pptpgre_stats_type_fields
  210 };
  211 
  212 /* List of commands and how to convert arguments to/from ASCII */
  213 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
  214         {
  215           NGM_PPTPGRE_COOKIE,
  216           NGM_PPTPGRE_SET_CONFIG,
  217           "setconfig",
  218           &ng_pptpgre_conf_type,
  219           NULL
  220         },
  221         {
  222           NGM_PPTPGRE_COOKIE,
  223           NGM_PPTPGRE_GET_CONFIG,
  224           "getconfig",
  225           NULL,
  226           &ng_pptpgre_conf_type
  227         },
  228         {
  229           NGM_PPTPGRE_COOKIE,
  230           NGM_PPTPGRE_GET_STATS,
  231           "getstats",
  232           NULL,
  233           &ng_pptp_stats_type
  234         },
  235         {
  236           NGM_PPTPGRE_COOKIE,
  237           NGM_PPTPGRE_CLR_STATS,
  238           "clrstats",
  239           NULL,
  240           NULL
  241         },
  242         {
  243           NGM_PPTPGRE_COOKIE,
  244           NGM_PPTPGRE_GETCLR_STATS,
  245           "getclrstats",
  246           NULL,
  247           &ng_pptp_stats_type
  248         },
  249         { 0 }
  250 };
  251 
  252 /* Node type descriptor */
  253 static struct ng_type ng_pptpgre_typestruct = {
  254         .version =      NG_ABI_VERSION,
  255         .name =         NG_PPTPGRE_NODE_TYPE,
  256         .constructor =  ng_pptpgre_constructor,
  257         .rcvmsg =       ng_pptpgre_rcvmsg,
  258         .shutdown =     ng_pptpgre_shutdown,
  259         .newhook =      ng_pptpgre_newhook,
  260         .rcvdata =      ng_pptpgre_rcvdata,
  261         .disconnect =   ng_pptpgre_disconnect,
  262         .cmdlist =      ng_pptpgre_cmdlist,
  263 };
  264 NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct);
  265 
  266 #define ERROUT(x)       do { error = (x); goto done; } while (0)
  267 
  268 /************************************************************************
  269                         NETGRAPH NODE STUFF
  270  ************************************************************************/
  271 
  272 /*
  273  * Node type constructor
  274  */
  275 static int
  276 ng_pptpgre_constructor(node_p node)
  277 {
  278         priv_p priv;
  279 
  280         /* Allocate private structure */
  281         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
  282         if (priv == NULL)
  283                 return (ENOMEM);
  284 
  285         NG_NODE_SET_PRIVATE(node, priv);
  286 
  287         /* Initialize state */
  288         mtx_init(&priv->mtx, "ng_pptp", NULL, MTX_DEF);
  289         ng_callout_init(&priv->ackp.sackTimer);
  290         ng_callout_init(&priv->ackp.rackTimer);
  291 
  292         /* Done */
  293         return (0);
  294 }
  295 
  296 /*
  297  * Give our OK for a hook to be added.
  298  */
  299 static int
  300 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
  301 {
  302         const priv_p priv = NG_NODE_PRIVATE(node);
  303         hook_p *hookPtr;
  304 
  305         /* Check hook name */
  306         if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
  307                 hookPtr = &priv->upper;
  308         else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
  309                 hookPtr = &priv->lower;
  310         else
  311                 return (EINVAL);
  312 
  313         /* See if already connected */
  314         if (*hookPtr != NULL)
  315                 return (EISCONN);
  316 
  317         /* OK */
  318         *hookPtr = hook;
  319         return (0);
  320 }
  321 
  322 /*
  323  * Receive a control message.
  324  */
  325 static int
  326 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
  327 {
  328         const priv_p priv = NG_NODE_PRIVATE(node);
  329         struct ng_mesg *resp = NULL;
  330         int error = 0;
  331         struct ng_mesg *msg;
  332 
  333         NGI_GET_MSG(item, msg);
  334         switch (msg->header.typecookie) {
  335         case NGM_PPTPGRE_COOKIE:
  336                 switch (msg->header.cmd) {
  337                 case NGM_PPTPGRE_SET_CONFIG:
  338                     {
  339                         struct ng_pptpgre_conf *const newConf =
  340                                 (struct ng_pptpgre_conf *) msg->data;
  341 
  342                         /* Check for invalid or illegal config */
  343                         if (msg->header.arglen != sizeof(*newConf))
  344                                 ERROUT(EINVAL);
  345                         ng_pptpgre_reset(node);         /* reset on configure */
  346                         priv->conf = *newConf;
  347                         break;
  348                     }
  349                 case NGM_PPTPGRE_GET_CONFIG:
  350                         NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
  351                         if (resp == NULL)
  352                                 ERROUT(ENOMEM);
  353                         bcopy(&priv->conf, resp->data, sizeof(priv->conf));
  354                         break;
  355                 case NGM_PPTPGRE_GET_STATS:
  356                 case NGM_PPTPGRE_CLR_STATS:
  357                 case NGM_PPTPGRE_GETCLR_STATS:
  358                     {
  359                         if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
  360                                 NG_MKRESPONSE(resp, msg,
  361                                     sizeof(priv->stats), M_NOWAIT);
  362                                 if (resp == NULL)
  363                                         ERROUT(ENOMEM);
  364                                 bcopy(&priv->stats,
  365                                     resp->data, sizeof(priv->stats));
  366                         }
  367                         if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
  368                                 bzero(&priv->stats, sizeof(priv->stats));
  369                         break;
  370                     }
  371                 default:
  372                         error = EINVAL;
  373                         break;
  374                 }
  375                 break;
  376         default:
  377                 error = EINVAL;
  378                 break;
  379         }
  380 done:
  381         NG_RESPOND_MSG(error, node, item, resp);
  382         NG_FREE_MSG(msg);
  383         return (error);
  384 }
  385 
  386 /*
  387  * Receive incoming data on a hook.
  388  */
  389 static int
  390 ng_pptpgre_rcvdata(hook_p hook, item_p item)
  391 {
  392         const node_p node = NG_HOOK_NODE(hook);
  393         const priv_p priv = NG_NODE_PRIVATE(node);
  394         int rval;
  395 
  396         /* If not configured, reject */
  397         if (!priv->conf.enabled) {
  398                 NG_FREE_ITEM(item);
  399                 return (ENXIO);
  400         }
  401 
  402         mtx_lock(&priv->mtx);
  403 
  404         /* Treat as xmit or recv data */
  405         if (hook == priv->upper)
  406                 rval = ng_pptpgre_xmit(node, item);
  407         else if (hook == priv->lower)
  408                 rval = ng_pptpgre_recv(node, item);
  409         else
  410                 panic("%s: weird hook", __func__);
  411 
  412         mtx_assert(&priv->mtx, MA_NOTOWNED);
  413 
  414         return (rval);
  415 }
  416 
  417 /*
  418  * Destroy node
  419  */
  420 static int
  421 ng_pptpgre_shutdown(node_p node)
  422 {
  423         const priv_p priv = NG_NODE_PRIVATE(node);
  424 
  425         /* Reset node (stops timers) */
  426         ng_pptpgre_reset(node);
  427 
  428         mtx_destroy(&priv->mtx);
  429 
  430         FREE(priv, M_NETGRAPH);
  431 
  432         /* Decrement ref count */
  433         NG_NODE_UNREF(node);
  434         return (0);
  435 }
  436 
  437 /*
  438  * Hook disconnection
  439  */
  440 static int
  441 ng_pptpgre_disconnect(hook_p hook)
  442 {
  443         const node_p node = NG_HOOK_NODE(hook);
  444         const priv_p priv = NG_NODE_PRIVATE(node);
  445 
  446         /* Zero out hook pointer */
  447         if (hook == priv->upper)
  448                 priv->upper = NULL;
  449         else if (hook == priv->lower)
  450                 priv->lower = NULL;
  451         else
  452                 panic("%s: unknown hook", __func__);
  453 
  454         /* Go away if no longer connected to anything */
  455         if ((NG_NODE_NUMHOOKS(node) == 0)
  456         && (NG_NODE_IS_VALID(node)))
  457                 ng_rmnode_self(node);
  458         return (0);
  459 }
  460 
  461 /*************************************************************************
  462                     TRANSMIT AND RECEIVE FUNCTIONS
  463 *************************************************************************/
  464 
  465 /*
  466  * Transmit an outgoing frame, or just an ack if m is NULL.
  467  */
  468 static int
  469 ng_pptpgre_xmit(node_p node, item_p item)
  470 {
  471         const priv_p priv = NG_NODE_PRIVATE(node);
  472         struct ng_pptpgre_ackp *const a = &priv->ackp;
  473         u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
  474         struct greheader *const gre = (struct greheader *)buf;
  475         int grelen, error;
  476         struct mbuf *m;
  477 
  478         mtx_assert(&priv->mtx, MA_OWNED);
  479 
  480         if (item) {
  481                 NGI_GET_M(item, m);
  482         } else {
  483                 m = NULL;
  484         }
  485         /* Check if there's data */
  486         if (m != NULL) {
  487 
  488                 /* Check if windowing is enabled */
  489                 if (priv->conf.enableWindowing) {
  490                         /* Is our transmit window full? */
  491                         if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq,
  492                             priv->recvAck) >= a->xmitWin) {
  493                                 priv->stats.xmitDrops++;
  494                                 ERROUT(ENOBUFS);
  495                         }
  496                 }
  497 
  498                 /* Sanity check frame length */
  499                 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
  500                         priv->stats.xmitTooBig++;
  501                         ERROUT(EMSGSIZE);
  502                 }
  503         } else {
  504                 priv->stats.xmitLoneAcks++;
  505         }
  506 
  507         /* Build GRE header */
  508         ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
  509         gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
  510         gre->cid = htons(priv->conf.peerCid);
  511 
  512         /* Include sequence number if packet contains any data */
  513         if (m != NULL) {
  514                 gre->hasSeq = 1;
  515                 if (priv->conf.enableWindowing) {
  516                         a->timeSent[priv->xmitSeq - priv->recvAck]
  517                             = ng_pptpgre_time(node);
  518                 }
  519                 priv->xmitSeq++;
  520                 gre->data[0] = htonl(priv->xmitSeq);
  521         }
  522 
  523         /* Include acknowledgement (and stop send ack timer) if needed */
  524         if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
  525                 gre->hasAck = 1;
  526                 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
  527                 priv->xmitAck = priv->recvSeq;
  528                 ng_pptpgre_stop_send_ack_timer(node);
  529         }
  530 
  531         /* Prepend GRE header to outgoing frame */
  532         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  533         if (m == NULL) {
  534                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  535                 if (m == NULL) {
  536                         priv->stats.memoryFailures++;
  537                         ERROUT(ENOBUFS);
  538                 }
  539                 m->m_len = m->m_pkthdr.len = grelen;
  540                 m->m_pkthdr.rcvif = NULL;
  541         } else {
  542                 M_PREPEND(m, grelen, M_DONTWAIT);
  543                 if (m == NULL || (m->m_len < grelen
  544                     && (m = m_pullup(m, grelen)) == NULL)) {
  545                         priv->stats.memoryFailures++;
  546                         ERROUT(ENOBUFS);
  547                 }
  548         }
  549         bcopy(gre, mtod(m, u_char *), grelen);
  550 
  551         /* Update stats */
  552         priv->stats.xmitPackets++;
  553         priv->stats.xmitOctets += m->m_pkthdr.len;
  554 
  555         /*
  556          * XXX: we should reset timer only after an item has been sent
  557          * successfully.
  558          */
  559         if (gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
  560                 ng_pptpgre_start_recv_ack_timer(node);
  561 
  562         mtx_unlock(&priv->mtx);
  563 
  564         /* Deliver packet */
  565         if (item) {
  566                 NG_FWD_NEW_DATA(error, item, priv->lower, m);
  567         } else {
  568                 NG_SEND_DATA_ONLY(error, priv->lower, m);
  569         }
  570 
  571         return (error);
  572 
  573 done:
  574         mtx_unlock(&priv->mtx);
  575         NG_FREE_M(m);
  576         if (item)
  577                 NG_FREE_ITEM(item);
  578         return (error);
  579 }
  580 
  581 /*
  582  * Handle an incoming packet.  The packet includes the IP header.
  583  */
  584 static int
  585 ng_pptpgre_recv(node_p node, item_p item)
  586 {
  587         const priv_p priv = NG_NODE_PRIVATE(node);
  588         int iphlen, grelen, extralen;
  589         const struct greheader *gre;
  590         const struct ip *ip;
  591         int error = 0;
  592         struct mbuf *m;
  593 
  594         mtx_assert(&priv->mtx, MA_OWNED);
  595 
  596         NGI_GET_M(item, m);
  597         /* Update stats */
  598         priv->stats.recvPackets++;
  599         priv->stats.recvOctets += m->m_pkthdr.len;
  600 
  601         /* Sanity check packet length */
  602         if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
  603                 priv->stats.recvRunts++;
  604                 ERROUT(EINVAL);
  605         }
  606 
  607         /* Safely pull up the complete IP+GRE headers */
  608         if (m->m_len < sizeof(*ip) + sizeof(*gre)
  609             && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
  610                 priv->stats.memoryFailures++;
  611                 ERROUT(ENOBUFS);
  612         }
  613         ip = mtod(m, const struct ip *);
  614         iphlen = ip->ip_hl << 2;
  615         if (m->m_len < iphlen + sizeof(*gre)) {
  616                 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
  617                         priv->stats.memoryFailures++;
  618                         ERROUT(ENOBUFS);
  619                 }
  620                 ip = mtod(m, const struct ip *);
  621         }
  622         gre = (const struct greheader *)((const u_char *)ip + iphlen);
  623         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  624         if (m->m_pkthdr.len < iphlen + grelen) {
  625                 priv->stats.recvRunts++;
  626                 ERROUT(EINVAL);
  627         }
  628         if (m->m_len < iphlen + grelen) {
  629                 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
  630                         priv->stats.memoryFailures++;
  631                         ERROUT(ENOBUFS);
  632                 }
  633                 ip = mtod(m, const struct ip *);
  634                 gre = (const struct greheader *)((const u_char *)ip + iphlen);
  635         }
  636 
  637         /* Sanity check packet length and GRE header bits */
  638         extralen = m->m_pkthdr.len
  639             - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
  640         if (extralen < 0) {
  641                 priv->stats.recvBadGRE++;
  642                 ERROUT(EINVAL);
  643         }
  644         if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
  645             != PPTP_INIT_VALUE) {
  646                 priv->stats.recvBadGRE++;
  647                 ERROUT(EINVAL);
  648         }
  649         if (ntohs(gre->cid) != priv->conf.cid) {
  650                 priv->stats.recvBadCID++;
  651                 ERROUT(EINVAL);
  652         }
  653 
  654         /* Look for peer ack */
  655         if (gre->hasAck) {
  656                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  657                 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
  658                 const int index = ack - priv->recvAck - 1;
  659                 long sample;
  660                 long diff;
  661 
  662                 /* Sanity check ack value */
  663                 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
  664                         priv->stats.recvBadAcks++;
  665                         goto badAck;            /* we never sent it! */
  666                 }
  667                 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
  668                         goto badAck;            /* ack already timed out */
  669                 priv->recvAck = ack;
  670 
  671                 /* Update adaptive timeout stuff */
  672                 if (priv->conf.enableWindowing) {
  673                         sample = ng_pptpgre_time(node) - a->timeSent[index];
  674                         diff = sample - a->rtt;
  675                         a->rtt += PPTP_ACK_ALPHA(diff);
  676                         if (diff < 0)
  677                                 diff = -diff;
  678                         a->dev += PPTP_ACK_BETA(diff - a->dev);
  679                         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  680                         if (a->ato > PPTP_MAX_TIMEOUT)
  681                                 a->ato = PPTP_MAX_TIMEOUT;
  682                         if (a->ato < PPTP_MIN_TIMEOUT)
  683                                 a->ato = PPTP_MIN_TIMEOUT;
  684 
  685                         /* Shift packet transmit times in our transmit window */
  686                         bcopy(a->timeSent + index + 1, a->timeSent,
  687                             sizeof(*a->timeSent)
  688                               * (PPTP_XMIT_WIN - (index + 1)));
  689 
  690                         /* If we sent an entire window, increase window size */
  691                         if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
  692                             && a->xmitWin < PPTP_XMIT_WIN) {
  693                                 a->xmitWin++;
  694                                 a->winAck = ack + a->xmitWin;
  695                         }
  696 
  697                         /* Stop/(re)start receive ACK timer as necessary */
  698                         ng_pptpgre_stop_recv_ack_timer(node);
  699                         if (priv->recvAck != priv->xmitSeq)
  700                                 ng_pptpgre_start_recv_ack_timer(node);
  701                 }
  702         }
  703 badAck:
  704 
  705         /* See if frame contains any data */
  706         if (gre->hasSeq) {
  707                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  708                 const u_int32_t seq = ntohl(gre->data[0]);
  709 
  710                 /* Sanity check sequence number */
  711                 if (PPTP_SEQ_DIFF(seq, priv->recvSeq) <= 0) {
  712                         if (seq == priv->recvSeq)
  713                                 priv->stats.recvDuplicates++;
  714                         else
  715                                 priv->stats.recvOutOfOrder++;
  716                         ERROUT(EINVAL);
  717                 }
  718                 priv->recvSeq = seq;
  719 
  720                 /* We need to acknowledge this packet; do it soon... */
  721                 if (!(callout_pending(&a->sackTimer))) {
  722                         int maxWait;
  723 
  724                         /* Take 1/4 of the estimated round trip time */
  725                         maxWait = (a->rtt >> 2);
  726 
  727                         /* If delayed ACK is disabled, send it now */
  728                         if (!priv->conf.enableDelayedAck) {     /* ack now */
  729                                 ng_pptpgre_xmit(node, NULL);
  730                                 mtx_lock(&priv->mtx);
  731                         } else {                                /* ack later */
  732                                 if (maxWait < PPTP_MIN_ACK_DELAY)
  733                                         maxWait = PPTP_MIN_ACK_DELAY;
  734                                 if (maxWait > PPTP_MAX_ACK_DELAY)
  735                                         maxWait = PPTP_MAX_ACK_DELAY;
  736                                 ng_pptpgre_start_send_ack_timer(node, maxWait);
  737                         }
  738                 }
  739 
  740                 /* Trim mbuf down to internal payload */
  741                 m_adj(m, iphlen + grelen);
  742                 if (extralen > 0)
  743                         m_adj(m, -extralen);
  744 
  745                 mtx_unlock(&priv->mtx);
  746                 /* Deliver frame to upper layers */
  747                 NG_FWD_NEW_DATA(error, item, priv->upper, m);
  748         } else {
  749                 priv->stats.recvLoneAcks++;
  750                 mtx_unlock(&priv->mtx);
  751                 NG_FREE_ITEM(item);
  752                 NG_FREE_M(m);           /* no data to deliver */
  753         }
  754 
  755         return (error);
  756 
  757 done:
  758         mtx_unlock(&priv->mtx);
  759         NG_FREE_ITEM(item);
  760         NG_FREE_M(m);
  761         return (error);
  762 }
  763 
  764 /*************************************************************************
  765                     TIMER RELATED FUNCTIONS
  766 *************************************************************************/
  767 
  768 /*
  769  * Start a timer for the peer's acknowledging our oldest unacknowledged
  770  * sequence number.  If we get an ack for this sequence number before
  771  * the timer goes off, we cancel the timer.  Resets currently running
  772  * recv ack timer, if any.
  773  */
  774 static void
  775 ng_pptpgre_start_recv_ack_timer(node_p node)
  776 {
  777         const priv_p priv = NG_NODE_PRIVATE(node);
  778         struct ng_pptpgre_ackp *const a = &priv->ackp;
  779         int remain, ticks;
  780 
  781         if (!priv->conf.enableWindowing)
  782                 return;
  783 
  784         /* Compute how long until oldest unack'd packet times out,
  785            and reset the timer to that time. */
  786         remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
  787         if (remain < 0)
  788                 remain = 0;
  789 #ifdef DEBUG_RAT
  790         a->timerLength = remain;
  791         a->timerStart = ng_pptpgre_time(node);
  792 #endif
  793 
  794         /* Be conservative: timeout can happen up to 1 tick early */
  795         ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
  796         ng_callout(&a->rackTimer, node, NULL, ticks,
  797             ng_pptpgre_recv_ack_timeout, NULL, 0);
  798 }
  799 
  800 /*
  801  * Stop receive ack timer.
  802  */
  803 static void
  804 ng_pptpgre_stop_recv_ack_timer(node_p node)
  805 {
  806         const priv_p priv = NG_NODE_PRIVATE(node);
  807         struct ng_pptpgre_ackp *const a = &priv->ackp;
  808 
  809         if (!priv->conf.enableWindowing)
  810                 return;
  811 
  812         ng_uncallout(&a->rackTimer, node);
  813 }
  814 
  815 /*
  816  * The peer has failed to acknowledge the oldest unacknowledged sequence
  817  * number within the time allotted.  Update our adaptive timeout parameters
  818  * and reset/restart the recv ack timer.
  819  */
  820 static void
  821 ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
  822 {
  823         const priv_p priv = NG_NODE_PRIVATE(node);
  824         struct ng_pptpgre_ackp *const a = &priv->ackp;
  825 
  826         mtx_lock(&priv->mtx);
  827 
  828         /* Update adaptive timeout stuff */
  829         priv->stats.recvAckTimeouts++;
  830         a->rtt = PPTP_ACK_DELTA(a->rtt);
  831         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  832         if (a->ato > PPTP_MAX_TIMEOUT)
  833                 a->ato = PPTP_MAX_TIMEOUT;
  834         if (a->ato < PPTP_MIN_TIMEOUT)
  835                 a->ato = PPTP_MIN_TIMEOUT;
  836 
  837 #ifdef DEBUG_RAT
  838     log(LOG_DEBUG,
  839         "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
  840         (int)ng_pptpgre_time(node), priv->recvAck + 1,
  841         (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
  842 #endif
  843 
  844         /* Reset ack and sliding window */
  845         priv->recvAck = priv->xmitSeq;          /* pretend we got the ack */
  846         a->xmitWin = (a->xmitWin + 1) / 2;      /* shrink transmit window */
  847         a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */
  848 
  849         mtx_unlock(&priv->mtx);
  850 }
  851 
  852 /*
  853  * Start the send ack timer. This assumes the timer is not
  854  * already running.
  855  */
  856 static void
  857 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
  858 {
  859         const priv_p priv = NG_NODE_PRIVATE(node);
  860         struct ng_pptpgre_ackp *const a = &priv->ackp;
  861         int ticks;
  862 
  863         /* Be conservative: timeout can happen up to 1 tick early */
  864         ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
  865         ng_callout(&a->sackTimer, node, NULL, ticks,
  866             ng_pptpgre_send_ack_timeout, NULL, 0);
  867 }
  868 
  869 /*
  870  * Stop send ack timer.
  871  */
  872 static void
  873 ng_pptpgre_stop_send_ack_timer(node_p node)
  874 {
  875         const priv_p priv = NG_NODE_PRIVATE(node);
  876         struct ng_pptpgre_ackp *const a = &priv->ackp;
  877 
  878         ng_uncallout(&a->sackTimer, node);
  879 }
  880 
  881 /*
  882  * We've waited as long as we're willing to wait before sending an
  883  * acknowledgement to the peer for received frames. We had hoped to
  884  * be able to piggy back our acknowledgement on an outgoing data frame,
  885  * but apparently there haven't been any since. So send the ack now.
  886  */
  887 static void
  888 ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
  889 {
  890         const priv_p priv = NG_NODE_PRIVATE(node);
  891 
  892         mtx_lock(&priv->mtx);
  893         /* Send a frame with an ack but no payload */
  894         ng_pptpgre_xmit(node, NULL);
  895         mtx_assert(&priv->mtx, MA_NOTOWNED);
  896 }
  897 
  898 /*************************************************************************
  899                     MISC FUNCTIONS
  900 *************************************************************************/
  901 
  902 /*
  903  * Reset state
  904  */
  905 static void
  906 ng_pptpgre_reset(node_p node)
  907 {
  908         const priv_p priv = NG_NODE_PRIVATE(node);
  909         struct ng_pptpgre_ackp *const a = &priv->ackp;
  910 
  911         mtx_lock(&priv->mtx);
  912 
  913         /* Reset adaptive timeout state */
  914         a->ato = PPTP_MAX_TIMEOUT;
  915         a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
  916         if (a->rtt < PPTP_MIN_RTT)
  917                 a->rtt = PPTP_MIN_RTT;
  918         a->dev = 0;
  919         a->xmitWin = (priv->conf.recvWin + 1) / 2;
  920         if (a->xmitWin < 2)             /* often the first packet is lost */
  921                 a->xmitWin = 2;         /*   because the peer isn't ready */
  922         if (a->xmitWin > PPTP_XMIT_WIN)
  923                 a->xmitWin = PPTP_XMIT_WIN;
  924         a->winAck = a->xmitWin;
  925 
  926         /* Reset sequence numbers */
  927         priv->recvSeq = ~0;
  928         priv->recvAck = ~0;
  929         priv->xmitSeq = ~0;
  930         priv->xmitAck = ~0;
  931 
  932         /* Reset start time */
  933         getmicrouptime(&priv->startTime);
  934 
  935         /* Reset stats */
  936         bzero(&priv->stats, sizeof(priv->stats));
  937 
  938         /* Stop timers */
  939         ng_pptpgre_stop_send_ack_timer(node);
  940         ng_pptpgre_stop_recv_ack_timer(node);
  941 
  942         mtx_unlock(&priv->mtx);
  943 }
  944 
  945 /*
  946  * Return the current time scaled & translated to our internally used format.
  947  */
  948 static pptptime_t
  949 ng_pptpgre_time(node_p node)
  950 {
  951         const priv_p priv = NG_NODE_PRIVATE(node);
  952         struct timeval tv;
  953         pptptime_t t;
  954 
  955         microuptime(&tv);
  956         if (tv.tv_sec < priv->startTime.tv_sec
  957             || (tv.tv_sec == priv->startTime.tv_sec
  958               && tv.tv_usec < priv->startTime.tv_usec))
  959                 return (0);
  960         timevalsub(&tv, &priv->startTime);
  961         t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
  962         t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
  963         return(t);
  964 }

Cache object: 69b0a72d74d2a0c7798adcabd66a0337


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