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


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

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

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

    1 
    2 /*
    3  * ng_pptpgre.c
    4  *
    5  * Copyright (c) 1996-1999 Whistle Communications, Inc.
    6  * All rights reserved.
    7  * 
    8  * Subject to the following obligations and disclaimer of warranty, use and
    9  * redistribution of this software, in source or object code forms, with or
   10  * without modifications are expressly permitted by Whistle Communications;
   11  * provided, however, that:
   12  * 1. Any and all reproductions of the source or object code must include the
   13  *    copyright notice above and the following disclaimer of warranties; and
   14  * 2. No rights are granted, in any manner or form, to use Whistle
   15  *    Communications, Inc. trademarks, including the mark "WHISTLE
   16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   17  *    such appears in the above copyright notice or in the software.
   18  * 
   19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   35  * OF SUCH DAMAGE.
   36  *
   37  * Author: Archie Cobbs <archie@freebsd.org>
   38  *
   39  * $FreeBSD: releng/5.2/sys/netgraph/ng_pptpgre.c 122890 2003-11-18 20:43:23Z archie $
   40  * $Whistle: ng_pptpgre.c,v 1.7 1999/12/08 00:10:06 archie Exp $
   41  */
   42 
   43 /*
   44  * PPTP/GRE netgraph node type.
   45  *
   46  * This node type does the GRE encapsulation as specified for the PPTP
   47  * protocol (RFC 2637, section 4).  This includes sequencing and
   48  * retransmission of frames, but not the actual packet delivery nor
   49  * any of the TCP control stream protocol.
   50  *
   51  * The "upper" hook of this node is suitable for attaching to a "ppp"
   52  * node link hook.  The "lower" hook of this node is suitable for attaching
   53  * to a "ksocket" node on hook "inet/raw/gre".
   54  */
   55 
   56 #include <sys/param.h>
   57 #include <sys/systm.h>
   58 #include <sys/kernel.h>
   59 #include <sys/time.h>
   60 #include <sys/mbuf.h>
   61 #include <sys/malloc.h>
   62 #include <sys/errno.h>
   63 
   64 #include <netinet/in.h>
   65 #include <netinet/in_systm.h>
   66 #include <netinet/ip.h>
   67 
   68 #include <netgraph/ng_message.h>
   69 #include <netgraph/netgraph.h>
   70 #include <netgraph/ng_parse.h>
   71 #include <netgraph/ng_pptpgre.h>
   72 
   73 /* GRE packet format, as used by PPTP */
   74 struct greheader {
   75 #if BYTE_ORDER == LITTLE_ENDIAN
   76         u_char          recursion:3;            /* recursion control */
   77         u_char          ssr:1;                  /* strict source route */
   78         u_char          hasSeq:1;               /* sequence number present */
   79         u_char          hasKey:1;               /* key present */
   80         u_char          hasRoute:1;             /* routing present */
   81         u_char          hasSum:1;               /* checksum present */
   82         u_char          vers:3;                 /* version */
   83         u_char          flags:4;                /* flags */
   84         u_char          hasAck:1;               /* acknowlege number present */
   85 #elif BYTE_ORDER == BIG_ENDIAN
   86         u_char          hasSum:1;               /* checksum present */
   87         u_char          hasRoute:1;             /* routing present */
   88         u_char          hasKey:1;               /* key present */
   89         u_char          hasSeq:1;               /* sequence number present */
   90         u_char          ssr:1;                  /* strict source route */
   91         u_char          recursion:3;            /* recursion control */
   92         u_char          hasAck:1;               /* acknowlege number present */
   93         u_char          flags:4;                /* flags */
   94         u_char          vers:3;                 /* version */
   95 #else
   96 #error BYTE_ORDER is not defined properly
   97 #endif
   98         u_int16_t       proto;                  /* protocol (ethertype) */
   99         u_int16_t       length;                 /* payload length */
  100         u_int16_t       cid;                    /* call id */
  101         u_int32_t       data[0];                /* opt. seq, ack, then data */
  102 };
  103 
  104 /* The PPTP protocol ID used in the GRE 'proto' field */
  105 #define PPTP_GRE_PROTO          0x880b
  106 
  107 /* Bits that must be set a certain way in all PPTP/GRE packets */
  108 #define PPTP_INIT_VALUE         ((0x2001 << 16) | PPTP_GRE_PROTO)
  109 #define PPTP_INIT_MASK          0xef7fffff
  110 
  111 /* Min and max packet length */
  112 #define PPTP_MAX_PAYLOAD        (0xffff - sizeof(struct greheader) - 8)
  113 
  114 /* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
  115 #define PPTP_TIME_SCALE         1000                    /* milliseconds */
  116 typedef u_int64_t               pptptime_t;
  117 
  118 /* Acknowledgment timeout parameters and functions */
  119 #define PPTP_XMIT_WIN           16                      /* max xmit window */
  120 #define PPTP_MIN_RTT            (PPTP_TIME_SCALE / 10)  /* 100 milliseconds */
  121 #define PPTP_MIN_TIMEOUT        (PPTP_TIME_SCALE / 83)  /* 12 milliseconds */
  122 #define PPTP_MAX_TIMEOUT        (1 * PPTP_TIME_SCALE)   /* 1 second */
  123 
  124 /* When we recieve a packet, we wait to see if there's an outgoing packet
  125    we can piggy-back the ACK off of. These parameters determine the mimimum
  126    and maxmimum length of time we're willing to wait in order to do that.
  127    These have no effect unless "enableDelayedAck" is turned on. */
  128 #define PPTP_MIN_ACK_DELAY      (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
  129 #define PPTP_MAX_ACK_DELAY      (PPTP_TIME_SCALE / 2)   /* 500 milliseconds */
  130 
  131 /* See RFC 2637 section 4.4 */
  132 #define PPTP_ACK_ALPHA(x)       ((x) >> 3)      /* alpha = 0.125 */
  133 #define PPTP_ACK_BETA(x)        ((x) >> 2)      /* beta = 0.25 */
  134 #define PPTP_ACK_CHI(x)         ((x) << 2)      /* chi = 4 */
  135 #define PPTP_ACK_DELTA(x)       ((x) << 1)      /* delta = 2 */
  136 
  137 #define PPTP_SEQ_DIFF(x,y)      ((int32_t)(x) - (int32_t)(y))
  138 
  139 /* We keep packet retransmit and acknowlegement state in this struct */
  140 struct ng_pptpgre_ackp {
  141         int32_t                 ato;            /* adaptive time-out value */
  142         int32_t                 rtt;            /* round trip time estimate */
  143         int32_t                 dev;            /* deviation estimate */
  144         u_int16_t               xmitWin;        /* size of xmit window */
  145         struct callout          sackTimer;      /* send ack timer */
  146         struct callout          rackTimer;      /* recv ack timer */
  147         node_p                  *sackTimerPtr;  /* send ack timer pointer */
  148         node_p                  *rackTimerPtr;  /* recv ack timer pointer */
  149         u_int32_t               winAck;         /* seq when xmitWin will grow */
  150         pptptime_t              timeSent[PPTP_XMIT_WIN];
  151 #ifdef DEBUG_RAT
  152         pptptime_t              timerStart;     /* when rackTimer started */
  153         pptptime_t              timerLength;    /* rackTimer duration */
  154 #endif
  155 };
  156 
  157 /* Node private data */
  158 struct ng_pptpgre_private {
  159         hook_p                  upper;          /* hook to upper layers */
  160         hook_p                  lower;          /* hook to lower layers */
  161         struct ng_pptpgre_conf  conf;           /* configuration info */
  162         struct ng_pptpgre_ackp  ackp;           /* packet transmit ack state */
  163         u_int32_t               recvSeq;        /* last seq # we rcv'd */
  164         u_int32_t               xmitSeq;        /* last seq # we sent */
  165         u_int32_t               recvAck;        /* last seq # peer ack'd */
  166         u_int32_t               xmitAck;        /* last seq # we ack'd */
  167         u_int                   timers;         /* number of pending timers */
  168         struct timeval          startTime;      /* time node was created */
  169         struct ng_pptpgre_stats stats;          /* node statistics */
  170 };
  171 typedef struct ng_pptpgre_private *priv_p;
  172 
  173 /* Netgraph node methods */
  174 static ng_constructor_t ng_pptpgre_constructor;
  175 static ng_rcvmsg_t      ng_pptpgre_rcvmsg;
  176 static ng_shutdown_t    ng_pptpgre_shutdown;
  177 static ng_newhook_t     ng_pptpgre_newhook;
  178 static ng_rcvdata_t     ng_pptpgre_rcvdata;
  179 static ng_disconnect_t  ng_pptpgre_disconnect;
  180 
  181 /* Helper functions */
  182 static int      ng_pptpgre_xmit(node_p node, item_p item);
  183 static int      ng_pptpgre_recv(node_p node, item_p item);
  184 static void     ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
  185 static void     ng_pptpgre_stop_send_ack_timer(node_p node);
  186 static void     ng_pptpgre_start_recv_ack_timer(node_p node);
  187 static void     ng_pptpgre_stop_recv_ack_timer(node_p node);
  188 static void     ng_pptpgre_recv_ack_timeout(void *arg);
  189 static void     ng_pptpgre_send_ack_timeout(void *arg);
  190 static void     ng_pptpgre_reset(node_p node);
  191 static pptptime_t ng_pptpgre_time(node_p node);
  192 
  193 /* Parse type for struct ng_pptpgre_conf */
  194 static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
  195         = NG_PPTPGRE_CONF_TYPE_INFO;
  196 static const struct ng_parse_type ng_pptpgre_conf_type = {
  197         &ng_parse_struct_type,
  198         &ng_pptpgre_conf_type_fields,
  199 };
  200 
  201 /* Parse type for struct ng_pptpgre_stats */
  202 static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
  203         = NG_PPTPGRE_STATS_TYPE_INFO;
  204 static const struct ng_parse_type ng_pptp_stats_type = {
  205         &ng_parse_struct_type,
  206         &ng_pptpgre_stats_type_fields
  207 };
  208 
  209 /* List of commands and how to convert arguments to/from ASCII */
  210 static const struct ng_cmdlist ng_pptpgre_cmdlist[] = {
  211         {
  212           NGM_PPTPGRE_COOKIE,
  213           NGM_PPTPGRE_SET_CONFIG,
  214           "setconfig",
  215           &ng_pptpgre_conf_type,
  216           NULL
  217         },
  218         {
  219           NGM_PPTPGRE_COOKIE,
  220           NGM_PPTPGRE_GET_CONFIG,
  221           "getconfig",
  222           NULL,
  223           &ng_pptpgre_conf_type
  224         },
  225         {
  226           NGM_PPTPGRE_COOKIE,
  227           NGM_PPTPGRE_GET_STATS,
  228           "getstats",
  229           NULL,
  230           &ng_pptp_stats_type
  231         },
  232         {
  233           NGM_PPTPGRE_COOKIE,
  234           NGM_PPTPGRE_CLR_STATS,
  235           "clrstats",
  236           NULL,
  237           NULL
  238         },
  239         {
  240           NGM_PPTPGRE_COOKIE,
  241           NGM_PPTPGRE_GETCLR_STATS,
  242           "getclrstats",
  243           NULL,
  244           &ng_pptp_stats_type
  245         },
  246         { 0 }
  247 };
  248 
  249 /* Node type descriptor */
  250 static struct ng_type ng_pptpgre_typestruct = {
  251         NG_ABI_VERSION,
  252         NG_PPTPGRE_NODE_TYPE,
  253         NULL,
  254         ng_pptpgre_constructor,
  255         ng_pptpgre_rcvmsg,
  256         ng_pptpgre_shutdown,
  257         ng_pptpgre_newhook,
  258         NULL,
  259         NULL,
  260         ng_pptpgre_rcvdata,
  261         ng_pptpgre_disconnect,
  262         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         callout_init(&priv->ackp.sackTimer, 0);
  289         callout_init(&priv->ackp.rackTimer, 0);
  290 
  291         /* Done */
  292         return (0);
  293 }
  294 
  295 /*
  296  * Give our OK for a hook to be added.
  297  */
  298 static int
  299 ng_pptpgre_newhook(node_p node, hook_p hook, const char *name)
  300 {
  301         const priv_p priv = NG_NODE_PRIVATE(node);
  302         hook_p *hookPtr;
  303 
  304         /* Check hook name */
  305         if (strcmp(name, NG_PPTPGRE_HOOK_UPPER) == 0)
  306                 hookPtr = &priv->upper;
  307         else if (strcmp(name, NG_PPTPGRE_HOOK_LOWER) == 0)
  308                 hookPtr = &priv->lower;
  309         else
  310                 return (EINVAL);
  311 
  312         /* See if already connected */
  313         if (*hookPtr != NULL)
  314                 return (EISCONN);
  315 
  316         /* OK */
  317         *hookPtr = hook;
  318         return (0);
  319 }
  320 
  321 /*
  322  * Receive a control message.
  323  */
  324 static int
  325 ng_pptpgre_rcvmsg(node_p node, item_p item, hook_p lasthook)
  326 {
  327         const priv_p priv = NG_NODE_PRIVATE(node);
  328         struct ng_mesg *resp = NULL;
  329         int error = 0;
  330         struct ng_mesg *msg;
  331 
  332         NGI_GET_MSG(item, msg);
  333         switch (msg->header.typecookie) {
  334         case NGM_PPTPGRE_COOKIE:
  335                 switch (msg->header.cmd) {
  336                 case NGM_PPTPGRE_SET_CONFIG:
  337                     {
  338                         struct ng_pptpgre_conf *const newConf =
  339                                 (struct ng_pptpgre_conf *) msg->data;
  340 
  341                         /* Check for invalid or illegal config */
  342                         if (msg->header.arglen != sizeof(*newConf))
  343                                 ERROUT(EINVAL);
  344                         ng_pptpgre_reset(node);         /* reset on configure */
  345                         priv->conf = *newConf;
  346                         break;
  347                     }
  348                 case NGM_PPTPGRE_GET_CONFIG:
  349                         NG_MKRESPONSE(resp, msg, sizeof(priv->conf), M_NOWAIT);
  350                         if (resp == NULL)
  351                                 ERROUT(ENOMEM);
  352                         bcopy(&priv->conf, resp->data, sizeof(priv->conf));
  353                         break;
  354                 case NGM_PPTPGRE_GET_STATS:
  355                 case NGM_PPTPGRE_CLR_STATS:
  356                 case NGM_PPTPGRE_GETCLR_STATS:
  357                     {
  358                         if (msg->header.cmd != NGM_PPTPGRE_CLR_STATS) {
  359                                 NG_MKRESPONSE(resp, msg,
  360                                     sizeof(priv->stats), M_NOWAIT);
  361                                 if (resp == NULL)
  362                                         ERROUT(ENOMEM);
  363                                 bcopy(&priv->stats,
  364                                     resp->data, sizeof(priv->stats));
  365                         }
  366                         if (msg->header.cmd != NGM_PPTPGRE_GET_STATS)
  367                                 bzero(&priv->stats, sizeof(priv->stats));
  368                         break;
  369                     }
  370                 default:
  371                         error = EINVAL;
  372                         break;
  373                 }
  374                 break;
  375         default:
  376                 error = EINVAL;
  377                 break;
  378         }
  379 done:
  380         NG_RESPOND_MSG(error, node, item, resp);
  381         NG_FREE_MSG(msg);
  382         return (error);
  383 }
  384 
  385 /*
  386  * Receive incoming data on a hook.
  387  */
  388 static int
  389 ng_pptpgre_rcvdata(hook_p hook, item_p item)
  390 {
  391         const node_p node = NG_HOOK_NODE(hook);
  392         const priv_p priv = NG_NODE_PRIVATE(node);
  393 
  394         /* If not configured, reject */
  395         if (!priv->conf.enabled) {
  396                 NG_FREE_ITEM(item);
  397                 return (ENXIO);
  398         }
  399 
  400         /* Treat as xmit or recv data */
  401         if (hook == priv->upper)
  402                 return ng_pptpgre_xmit(node, item);
  403         if (hook == priv->lower)
  404                 return ng_pptpgre_recv(node, item);
  405         panic("%s: weird hook", __func__);
  406 }
  407 
  408 /*
  409  * Destroy node
  410  */
  411 static int
  412 ng_pptpgre_shutdown(node_p node)
  413 {
  414         const priv_p priv = NG_NODE_PRIVATE(node);
  415 
  416         /* Reset node */
  417         ng_pptpgre_reset(node);
  418 
  419         /* If no timers remain, free private info as well */
  420         if (priv->timers == 0) {
  421                 bzero(priv, sizeof(*priv));
  422                 FREE(priv, M_NETGRAPH);
  423                 NG_NODE_SET_PRIVATE(node, NULL);
  424         }
  425 
  426         /* Decrement ref count */
  427         NG_NODE_UNREF(node);
  428         return (0);
  429 }
  430 
  431 /*
  432  * Hook disconnection
  433  */
  434 static int
  435 ng_pptpgre_disconnect(hook_p hook)
  436 {
  437         const node_p node = NG_HOOK_NODE(hook);
  438         const priv_p priv = NG_NODE_PRIVATE(node);
  439 
  440         /* Zero out hook pointer */
  441         if (hook == priv->upper)
  442                 priv->upper = NULL;
  443         else if (hook == priv->lower)
  444                 priv->lower = NULL;
  445         else
  446                 panic("%s: unknown hook", __func__);
  447 
  448         /* Go away if no longer connected to anything */
  449         if ((NG_NODE_NUMHOOKS(node) == 0)
  450         && (NG_NODE_IS_VALID(node)))
  451                 ng_rmnode_self(node);
  452         return (0);
  453 }
  454 
  455 /*************************************************************************
  456                     TRANSMIT AND RECEIVE FUNCTIONS
  457 *************************************************************************/
  458 
  459 /*
  460  * Transmit an outgoing frame, or just an ack if m is NULL.
  461  */
  462 static int
  463 ng_pptpgre_xmit(node_p node, item_p item)
  464 {
  465         const priv_p priv = NG_NODE_PRIVATE(node);
  466         struct ng_pptpgre_ackp *const a = &priv->ackp;
  467         u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)];
  468         struct greheader *const gre = (struct greheader *)buf;
  469         int grelen, error;
  470         struct mbuf *m;
  471 
  472         if (item) {
  473                 NGI_GET_M(item, m);
  474         } else {
  475                 m = NULL;
  476         }
  477         /* Check if there's data */
  478         if (m != NULL) {
  479 
  480                 /* Is our transmit window full? */
  481                 if ((u_int32_t)PPTP_SEQ_DIFF(priv->xmitSeq, priv->recvAck)
  482                       >= a->xmitWin) {
  483                         priv->stats.xmitDrops++;
  484                         NG_FREE_M(m);
  485                         NG_FREE_ITEM(item);
  486                         return (ENOBUFS);
  487                 }
  488 
  489                 /* Sanity check frame length */
  490                 if (m != NULL && m->m_pkthdr.len > PPTP_MAX_PAYLOAD) {
  491                         priv->stats.xmitTooBig++;
  492                         NG_FREE_M(m);
  493                         NG_FREE_ITEM(item);
  494                         return (EMSGSIZE);
  495                 }
  496         } else {
  497                 priv->stats.xmitLoneAcks++;
  498         }
  499 
  500         /* Build GRE header */
  501         ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
  502         gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
  503         gre->cid = htons(priv->conf.peerCid);
  504 
  505         /* Include sequence number if packet contains any data */
  506         if (m != NULL) {
  507                 gre->hasSeq = 1;
  508                 a->timeSent[priv->xmitSeq - priv->recvAck]
  509                     = ng_pptpgre_time(node);
  510                 priv->xmitSeq++;
  511                 gre->data[0] = htonl(priv->xmitSeq);
  512         }
  513 
  514         /* Include acknowledgement (and stop send ack timer) if needed */
  515         if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
  516                 gre->hasAck = 1;
  517                 gre->data[gre->hasSeq] = htonl(priv->recvSeq);
  518                 priv->xmitAck = priv->recvSeq;
  519                 ng_pptpgre_stop_send_ack_timer(node);
  520         }
  521 
  522         /* Prepend GRE header to outgoing frame */
  523         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  524         if (m == NULL) {
  525                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  526                 if (m == NULL) {
  527                         priv->stats.memoryFailures++;
  528                         if (item)
  529                                 NG_FREE_ITEM(item);
  530                         return (ENOBUFS);
  531                 }
  532                 m->m_len = m->m_pkthdr.len = grelen;
  533                 m->m_pkthdr.rcvif = NULL;
  534         } else {
  535                 M_PREPEND(m, grelen, M_DONTWAIT);
  536                 if (m == NULL || (m->m_len < grelen
  537                     && (m = m_pullup(m, grelen)) == NULL)) {
  538                         priv->stats.memoryFailures++;
  539                         if (item)
  540                                 NG_FREE_ITEM(item);
  541                         return (ENOBUFS);
  542                 }
  543         }
  544         bcopy(gre, mtod(m, u_char *), grelen);
  545 
  546         /* Update stats */
  547         priv->stats.xmitPackets++;
  548         priv->stats.xmitOctets += m->m_pkthdr.len;
  549 
  550         /* Deliver packet */
  551         if (item) {
  552                 NG_FWD_NEW_DATA(error, item, priv->lower, m);
  553         } else {
  554                 NG_SEND_DATA_ONLY(error, priv->lower, m);
  555         }
  556 
  557 
  558         /* Start receive ACK timer if data was sent and not already running */
  559         if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
  560                 ng_pptpgre_start_recv_ack_timer(node);
  561         return (error);
  562 }
  563 
  564 /*
  565  * Handle an incoming packet.  The packet includes the IP header.
  566  */
  567 static int
  568 ng_pptpgre_recv(node_p node, item_p item)
  569 {
  570         const priv_p priv = NG_NODE_PRIVATE(node);
  571         int iphlen, grelen, extralen;
  572         const struct greheader *gre;
  573         const struct ip *ip;
  574         int error = 0;
  575         struct mbuf *m;
  576 
  577         NGI_GET_M(item, m);
  578         /* Update stats */
  579         priv->stats.recvPackets++;
  580         priv->stats.recvOctets += m->m_pkthdr.len;
  581 
  582         /* Sanity check packet length */
  583         if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
  584                 priv->stats.recvRunts++;
  585 bad:
  586                 NG_FREE_M(m);
  587                 NG_FREE_ITEM(item);
  588                 return (EINVAL);
  589         }
  590 
  591         /* Safely pull up the complete IP+GRE headers */
  592         if (m->m_len < sizeof(*ip) + sizeof(*gre)
  593             && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
  594                 priv->stats.memoryFailures++;
  595                 NG_FREE_ITEM(item);
  596                 return (ENOBUFS);
  597         }
  598         ip = mtod(m, const struct ip *);
  599         iphlen = ip->ip_hl << 2;
  600         if (m->m_len < iphlen + sizeof(*gre)) {
  601                 if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
  602                         priv->stats.memoryFailures++;
  603                         NG_FREE_ITEM(item);
  604                         return (ENOBUFS);
  605                 }
  606                 ip = mtod(m, const struct ip *);
  607         }
  608         gre = (const struct greheader *)((const u_char *)ip + iphlen);
  609         grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
  610         if (m->m_pkthdr.len < iphlen + grelen) {
  611                 priv->stats.recvRunts++;
  612                 goto bad;
  613         }
  614         if (m->m_len < iphlen + grelen) {
  615                 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
  616                         priv->stats.memoryFailures++;
  617                         NG_FREE_ITEM(item);
  618                         return (ENOBUFS);
  619                 }
  620                 ip = mtod(m, const struct ip *);
  621                 gre = (const struct greheader *)((const u_char *)ip + iphlen);
  622         }
  623 
  624         /* Sanity check packet length and GRE header bits */
  625         extralen = m->m_pkthdr.len
  626             - (iphlen + grelen + gre->hasSeq * (u_int16_t)ntohs(gre->length));
  627         if (extralen < 0) {
  628                 priv->stats.recvBadGRE++;
  629                 goto bad;
  630         }
  631         if ((ntohl(*((const u_int32_t *)gre)) & PPTP_INIT_MASK)
  632             != PPTP_INIT_VALUE) {
  633                 priv->stats.recvBadGRE++;
  634                 goto bad;
  635         }
  636         if (ntohs(gre->cid) != priv->conf.cid) {
  637                 priv->stats.recvBadCID++;
  638                 goto bad;
  639         }
  640 
  641         /* Look for peer ack */
  642         if (gre->hasAck) {
  643                 struct ng_pptpgre_ackp *const a = &priv->ackp;
  644                 const u_int32_t ack = ntohl(gre->data[gre->hasSeq]);
  645                 const int index = ack - priv->recvAck - 1;
  646                 long sample;
  647                 long diff;
  648 
  649                 /* Sanity check ack value */
  650                 if (PPTP_SEQ_DIFF(ack, priv->xmitSeq) > 0) {
  651                         priv->stats.recvBadAcks++;
  652                         goto badAck;            /* we never sent it! */
  653                 }
  654                 if (PPTP_SEQ_DIFF(ack, priv->recvAck) <= 0)
  655                         goto badAck;            /* ack already timed out */
  656                 priv->recvAck = ack;
  657 
  658                 /* Update adaptive timeout stuff */
  659                 sample = ng_pptpgre_time(node) - a->timeSent[index];
  660                 diff = sample - a->rtt;
  661                 a->rtt += PPTP_ACK_ALPHA(diff);
  662                 if (diff < 0)
  663                         diff = -diff;
  664                 a->dev += PPTP_ACK_BETA(diff - a->dev);
  665                 a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  666                 if (a->ato > PPTP_MAX_TIMEOUT)
  667                         a->ato = PPTP_MAX_TIMEOUT;
  668                 if (a->ato < PPTP_MIN_TIMEOUT)
  669                         a->ato = PPTP_MIN_TIMEOUT;
  670 
  671                 /* Shift packet transmit times in our transmit window */
  672                 bcopy(a->timeSent + index + 1, a->timeSent,
  673                     sizeof(*a->timeSent) * (PPTP_XMIT_WIN - (index + 1)));
  674 
  675                 /* If we sent an entire window, increase window size by one */
  676                 if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
  677                     && a->xmitWin < PPTP_XMIT_WIN) {
  678                         a->xmitWin++;
  679                         a->winAck = ack + a->xmitWin;
  680                 }
  681 
  682                 /* Stop/(re)start receive ACK timer as necessary */
  683                 ng_pptpgre_stop_recv_ack_timer(node);
  684                 if (priv->recvAck != priv->xmitSeq)
  685                         ng_pptpgre_start_recv_ack_timer(node);
  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 (a->sackTimerPtr == NULL) {
  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         /* Compute how long until oldest unack'd packet times out,
  756            and reset the timer to that time. */
  757         KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __func__));
  758         remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
  759         if (remain < 0)
  760                 remain = 0;
  761 #ifdef DEBUG_RAT
  762         a->timerLength = remain;
  763         a->timerStart = ng_pptpgre_time(node);
  764 #endif
  765 
  766         /* Start new timer */
  767         MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
  768         if (a->rackTimerPtr == NULL) {
  769                 priv->stats.memoryFailures++;
  770                 return;                 /* XXX potential hang here */
  771         }
  772         *a->rackTimerPtr = node;        /* ensures the correct timeout event */
  773         NG_NODE_REF(node);
  774         priv->timers++;
  775 
  776         /* Be conservative: timeout can happen up to 1 tick early */
  777         ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
  778         callout_reset(&a->rackTimer, ticks,
  779             ng_pptpgre_recv_ack_timeout, a->rackTimerPtr);
  780 }
  781 
  782 /*
  783  * Stop receive ack timer.
  784  */
  785 static void
  786 ng_pptpgre_stop_recv_ack_timer(node_p node)
  787 {
  788         const priv_p priv = NG_NODE_PRIVATE(node);
  789         struct ng_pptpgre_ackp *const a = &priv->ackp;
  790 
  791         if (callout_stop(&a->rackTimer)) {
  792                 FREE(a->rackTimerPtr, M_NETGRAPH);
  793                 priv->timers--;
  794                 NG_NODE_UNREF(node);
  795         }
  796         a->rackTimerPtr = NULL;
  797 }
  798 
  799 /*
  800  * The peer has failed to acknowledge the oldest unacknowledged sequence
  801  * number within the time allotted.  Update our adaptive timeout parameters
  802  * and reset/restart the recv ack timer.
  803  */
  804 static void
  805 ng_pptpgre_recv_ack_timeout(void *arg)
  806 {
  807         int s = splnet();
  808         const node_p node = *((node_p *)arg);
  809         const priv_p priv = NG_NODE_PRIVATE(node);
  810         struct ng_pptpgre_ackp *const a = &priv->ackp;
  811 
  812         /* This complicated stuff is needed to avoid race conditions */
  813         FREE(arg, M_NETGRAPH);
  814         KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
  815         KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
  816         priv->timers--;
  817         if (NG_NODE_NOT_VALID(node)) {  /* shutdown race condition */
  818                 if (priv->timers == 0) {
  819                         FREE(priv, M_NETGRAPH);
  820                         NG_NODE_SET_PRIVATE(node, NULL);
  821                 }
  822                 NG_NODE_UNREF(node);
  823                 splx(s);
  824                 return;
  825         }
  826         if (arg != a->rackTimerPtr) {   /* timer stopped race condition */
  827                 NG_NODE_UNREF(node);
  828                 splx(s);
  829                 return;
  830         }
  831         a->rackTimerPtr = NULL;
  832 
  833         /* Update adaptive timeout stuff */
  834         priv->stats.recvAckTimeouts++;
  835         a->rtt = PPTP_ACK_DELTA(a->rtt);
  836         a->ato = a->rtt + PPTP_ACK_CHI(a->dev);
  837         if (a->ato > PPTP_MAX_TIMEOUT)
  838                 a->ato = PPTP_MAX_TIMEOUT;
  839         if (a->ato < PPTP_MIN_TIMEOUT)
  840                 a->ato = PPTP_MIN_TIMEOUT;
  841 
  842 #ifdef DEBUG_RAT
  843     log(LOG_DEBUG,
  844         "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
  845         (int)ng_pptpgre_time(node), priv->recvAck + 1,
  846         (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
  847 #endif
  848 
  849         /* Reset ack and sliding window */
  850         priv->recvAck = priv->xmitSeq;          /* pretend we got the ack */
  851         a->xmitWin = (a->xmitWin + 1) / 2;      /* shrink transmit window */
  852         a->winAck = priv->recvAck + a->xmitWin; /* reset win expand time */
  853         NG_NODE_UNREF(node);
  854         splx(s);
  855 }
  856 
  857 /*
  858  * Start the send ack timer. This assumes the timer is not
  859  * already running.
  860  */
  861 static void
  862 ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
  863 {
  864         const priv_p priv = NG_NODE_PRIVATE(node);
  865         struct ng_pptpgre_ackp *const a = &priv->ackp;
  866         int ticks;
  867 
  868         /* Start new timer */
  869         KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __func__));
  870         MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
  871         if (a->sackTimerPtr == NULL) {
  872                 priv->stats.memoryFailures++;
  873                 return;                 /* XXX potential hang here */
  874         }
  875         *a->sackTimerPtr = node;        /* ensures the correct timeout event */
  876         NG_NODE_REF(node);
  877         priv->timers++;
  878 
  879         /* Be conservative: timeout can happen up to 1 tick early */
  880         ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
  881         callout_reset(&a->sackTimer, ticks,
  882             ng_pptpgre_send_ack_timeout, a->sackTimerPtr);
  883 }
  884 
  885 /*
  886  * Stop send ack timer.
  887  */
  888 static void
  889 ng_pptpgre_stop_send_ack_timer(node_p node)
  890 {
  891         const priv_p priv = NG_NODE_PRIVATE(node);
  892         struct ng_pptpgre_ackp *const a = &priv->ackp;
  893 
  894         if (callout_stop(&a->sackTimer)) {
  895                 FREE(a->sackTimerPtr, M_NETGRAPH);
  896                 priv->timers--;
  897                 NG_NODE_UNREF(node);
  898         }
  899         a->sackTimerPtr = NULL;
  900 }
  901 
  902 /*
  903  * We've waited as long as we're willing to wait before sending an
  904  * acknowledgement to the peer for received frames. We had hoped to
  905  * be able to piggy back our acknowledgement on an outgoing data frame,
  906  * but apparently there haven't been any since. So send the ack now.
  907  */
  908 static void
  909 ng_pptpgre_send_ack_timeout(void *arg)
  910 {
  911         int s = splnet();
  912         const node_p node = *((node_p *)arg);
  913         const priv_p priv = NG_NODE_PRIVATE(node);
  914         struct ng_pptpgre_ackp *const a = &priv->ackp;
  915 
  916         /* This complicated stuff is needed to avoid race conditions */
  917         FREE(arg, M_NETGRAPH);
  918         KASSERT(node->nd_refs > 0, ("%s: no nd_refs", __func__));
  919         KASSERT(priv != NULL, ("%s: priv=NULL", __func__));
  920         priv->timers--;
  921         if (NG_NODE_NOT_VALID(node)) {  /* shutdown race condition */
  922                 if (priv->timers == 0) {
  923                         FREE(priv, M_NETGRAPH);
  924                         NG_NODE_SET_PRIVATE(node, NULL);
  925                 }
  926                 NG_NODE_UNREF(node);
  927                 splx(s);
  928                 return;
  929         }
  930         if (a->sackTimerPtr != arg) {   /* timer stopped race condition */
  931                 NG_NODE_UNREF(node);
  932                 splx(s);
  933                 return;
  934         }
  935         a->sackTimerPtr = NULL;
  936 
  937         /* Send a frame with an ack but no payload */
  938         ng_pptpgre_xmit(node, NULL);
  939         NG_NODE_UNREF(node);
  940         splx(s);
  941 }
  942 
  943 /*************************************************************************
  944                     MISC FUNCTIONS
  945 *************************************************************************/
  946 
  947 /*
  948  * Reset state
  949  */
  950 static void
  951 ng_pptpgre_reset(node_p node)
  952 {
  953         const priv_p priv = NG_NODE_PRIVATE(node);
  954         struct ng_pptpgre_ackp *const a = &priv->ackp;
  955 
  956         /* Reset adaptive timeout state */
  957         a->ato = PPTP_MAX_TIMEOUT;
  958         a->rtt = priv->conf.peerPpd * PPTP_TIME_SCALE / 10;  /* ppd in 10ths */
  959         if (a->rtt < PPTP_MIN_RTT)
  960                 a->rtt = PPTP_MIN_RTT;
  961         a->dev = 0;
  962         a->xmitWin = (priv->conf.recvWin + 1) / 2;
  963         if (a->xmitWin < 2)             /* often the first packet is lost */
  964                 a->xmitWin = 2;         /*   because the peer isn't ready */
  965         if (a->xmitWin > PPTP_XMIT_WIN)
  966                 a->xmitWin = PPTP_XMIT_WIN;
  967         a->winAck = a->xmitWin;
  968 
  969         /* Reset sequence numbers */
  970         priv->recvSeq = ~0;
  971         priv->recvAck = ~0;
  972         priv->xmitSeq = ~0;
  973         priv->xmitAck = ~0;
  974 
  975         /* Reset start time */
  976         getmicrouptime(&priv->startTime);
  977 
  978         /* Reset stats */
  979         bzero(&priv->stats, sizeof(priv->stats));
  980 
  981         /* Stop timers */
  982         ng_pptpgre_stop_send_ack_timer(node);
  983         ng_pptpgre_stop_recv_ack_timer(node);
  984 }
  985 
  986 /*
  987  * Return the current time scaled & translated to our internally used format.
  988  */
  989 static pptptime_t
  990 ng_pptpgre_time(node_p node)
  991 {
  992         const priv_p priv = NG_NODE_PRIVATE(node);
  993         struct timeval tv;
  994         pptptime_t t;
  995 
  996         microuptime(&tv);
  997         if (tv.tv_sec < priv->startTime.tv_sec
  998             || (tv.tv_sec == priv->startTime.tv_sec
  999               && tv.tv_usec < priv->startTime.tv_usec))
 1000                 return (0);
 1001         timevalsub(&tv, &priv->startTime);
 1002         t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
 1003         t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
 1004         return(t);
 1005 }
 1006 

Cache object: ae42d2554a9d3ce2ed2ebb3ea7476548


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