Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 1998 Brian Somers <brian (at) Awfulhak.org>
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     24  * SUCH DAMAGE.
     25  *
     26  * $FreeBSD: src/usr.sbin/ppp/link.c,v 1.21.26.1 2010/12/21 17:10:29 kensmith Exp $
     27  *
     28  */
     29 
     30 #include <sys/types.h>
     31 #include <netinet/in_systm.h>
     32 #include <sys/socket.h>
     33 #include <sys/un.h>
     34 #include <netinet/in.h>
     35 #include <netinet/ip.h>
     36 
     37 #include <stdarg.h>
     38 #include <stdio.h>
     39 #include <string.h>
     40 #include <termios.h>
     41 
     42 #include "defs.h"
     43 #include "layer.h"
     44 #include "mbuf.h"
     45 #include "log.h"
     46 #include "timer.h"
     47 #include "lqr.h"
     48 #include "hdlc.h"
     49 #include "throughput.h"
     50 #include "proto.h"
     51 #include "fsm.h"
     52 #include "descriptor.h"
     53 #include "lcp.h"
     54 #include "ccp.h"
     55 #include "link.h"
     56 #include "prompt.h"
     57 #include "async.h"
     58 #include "physical.h"
     59 #include "mp.h"
     60 #include "iplist.h"
     61 #include "slcompress.h"
     62 #include "ncpaddr.h"
     63 #include "ip.h"
     64 #include "ipcp.h"
     65 #include "ipv6cp.h"
     66 #include "auth.h"
     67 #include "pap.h"
     68 #include "chap.h"
     69 #include "cbcp.h"
     70 #include "command.h"
     71 
     72 static void Despatch(struct bundle *, struct link *, struct mbuf *, u_short);
     73 
     74 static inline void
     75 link_AddInOctets(struct link *l, int n)
     76 {
     77   if (l->stats.gather) {
     78     throughput_addin(&l->stats.total, n);
     79     if (l->stats.parent)
     80       throughput_addin(l->stats.parent, n);
     81   }
     82 }
     83 
     84 static inline void
     85 link_AddOutOctets(struct link *l, int n)
     86 {
     87   if (l->stats.gather) {
     88     throughput_addout(&l->stats.total, n);
     89     if (l->stats.parent)
     90       throughput_addout(l->stats.parent, n);
     91   }
     92 }
     93 
     94 void
     95 link_SequenceQueue(struct link *l)
     96 {
     97   struct mqueue *queue, *highest;
     98 
     99   log_Printf(LogDEBUG, "link_SequenceQueue\n");
    100 
    101   highest = LINK_HIGHQ(l);
    102   for (queue = l->Queue; queue < highest; queue++)
    103     while (queue->len)
    104       m_enqueue(highest, m_dequeue(queue));
    105 }
    106 
    107 void
    108 link_DeleteQueue(struct link *l)
    109 {
    110   struct mqueue *queue, *highest;
    111 
    112   highest = LINK_HIGHQ(l);
    113   for (queue = l->Queue; queue <= highest; queue++)
    114     while (queue->top)
    115       m_freem(m_dequeue(queue));
    116 }
    117 
    118 size_t
    119 link_QueueLen(struct link *l)
    120 {
    121   unsigned i;
    122   size_t len;
    123 
    124   for (i = 0, len = 0; i < LINK_QUEUES(l); i++)
    125     len += l->Queue[i].len;
    126 
    127   return len;
    128 }
    129 
    130 size_t
    131 link_QueueBytes(struct link *l)
    132 {
    133   unsigned i;
    134   size_t len, bytes;
    135   struct mbuf *m;
    136 
    137   bytes = 0;
    138   for (i = 0, len = 0; i < LINK_QUEUES(l); i++) {
    139     len = l->Queue[i].len;
    140     m = l->Queue[i].top;
    141     while (len--) {
    142       bytes += m_length(m);
    143       m = m->m_nextpkt;
    144     }
    145   }
    146 
    147   return bytes;
    148 }
    149 
    150 void
    151 link_PendingLowPriorityData(struct link *l, size_t *pkts, size_t *octets)
    152 {
    153   struct mqueue *queue, *highest;
    154   struct mbuf *m;
    155   size_t len;
    156 
    157   /*
    158    * This is all rfc1989 stuff... because our LQR packet is going to bypass
    159    * everything that's not in the highest priority queue, we must be able to
    160    * subtract that data from our outgoing packet/octet counts.  However,
    161    * we've already async-encoded our data at this point, but the async
    162    * encodings MUSTn't be a part of the LQR-reported payload :(  So, we have
    163    * the async layer record how much it's padded the packet in the mbuf's
    164    * priv field, and when we calculate our outgoing LQR values we subtract
    165    * this value for each packet from the octet count sent.
    166    */
    167 
    168   highest = LINK_HIGHQ(l);
    169   *pkts = *octets = 0;
    170   for (queue = l->Queue; queue < highest; queue++) {
    171     len = queue->len;
    172     *pkts += len;
    173     for (m = queue->top; len--; m = m->m_nextpkt)
    174       *octets += m_length(m) - m->priv;
    175   }
    176 }
    177 
    178 struct mbuf *
    179 link_Dequeue(struct link *l)
    180 {
    181   int pri;
    182   struct mbuf *bp;
    183 
    184   for (bp = NULL, pri = LINK_QUEUES(l) - 1; pri >= 0; pri--)
    185     if (l->Queue[pri].len) {
    186       bp = m_dequeue(l->Queue + pri);
    187       log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d,"
    188                 " containing %lu more packets\n", pri,
    189                 (u_long)l->Queue[pri].len);
    190       break;
    191     }
    192 
    193   return bp;
    194 }
    195 
    196 static struct protostatheader {
    197   u_short number;
    198   const char *name;
    199 } ProtocolStat[NPROTOSTAT] = {
    200   { PROTO_IP, "IP" },
    201   { PROTO_VJUNCOMP, "VJ_UNCOMP" },
    202   { PROTO_VJCOMP, "VJ_COMP" },
    203   { PROTO_COMPD, "COMPD" },
    204   { PROTO_ICOMPD, "ICOMPD" },
    205   { PROTO_LCP, "LCP" },
    206   { PROTO_IPCP, "IPCP" },
    207   { PROTO_CCP, "CCP" },
    208   { PROTO_PAP, "PAP" },
    209   { PROTO_LQR, "LQR" },
    210   { PROTO_CHAP, "CHAP" },
    211   { PROTO_MP, "MULTILINK" },
    212   { 0, "Others" }
    213 };
    214 
    215 void
    216 link_ProtocolRecord(struct link *l, u_short proto, int type)
    217 {
    218   int i;
    219 
    220   for (i = 0; i < NPROTOSTAT; i++)
    221     if (ProtocolStat[i].number == proto)
    222       break;
    223 
    224   if (type == PROTO_IN)
    225     l->proto_in[i]++;
    226   else
    227     l->proto_out[i]++;
    228 }
    229 
    230 void
    231 link_ReportProtocolStatus(struct link *l, struct prompt *prompt)
    232 {
    233   int i;
    234 
    235   prompt_Printf(prompt, "    Protocol     in        out      "
    236                 "Protocol      in       out\n");
    237   for (i = 0; i < NPROTOSTAT; i++) {
    238     prompt_Printf(prompt, "   %-9s: %8lu, %8lu",
    239 	    ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]);
    240     if ((i % 2) == 0)
    241       prompt_Printf(prompt, "\n");
    242   }
    243   if (!(i % 2))
    244     prompt_Printf(prompt, "\n");
    245 }
    246 
    247 void
    248 link_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri,
    249                 u_short proto)
    250 {
    251   int layer;
    252 
    253   /*
    254    * When we ``push'' a packet into the link, it gets processed by the
    255    * ``push'' function in each layer starting at the top.
    256    * We never expect the result of a ``push'' to be more than one
    257    * packet (as we do with ``pull''s).
    258    */
    259 
    260   if(pri < 0 || (unsigned)pri >= LINK_QUEUES(l))
    261     pri = 0;
    262 
    263   bp->priv = 0;		/* Adjusted by the async layer ! */
    264   for (layer = l->nlayers; layer && bp; layer--)
    265     if (l->layer[layer - 1]->push != NULL)
    266       bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto);
    267 
    268   if (bp) {
    269     link_AddOutOctets(l, m_length(bp));
    270     log_Printf(LogDEBUG, "link_PushPacket: Transmit proto 0x%04x\n", proto);
    271     m_enqueue(l->Queue + pri, m_pullup(bp));
    272   }
    273 }
    274 
    275 void
    276 link_PullPacket(struct link *l, char *buf, size_t len, struct bundle *b)
    277 {
    278   struct mbuf *bp, *lbp[LAYER_MAX], *next;
    279   u_short lproto[LAYER_MAX], proto;
    280   int layer;
    281 
    282   /*
    283    * When we ``pull'' a packet from the link, it gets processed by the
    284    * ``pull'' function in each layer starting at the bottom.
    285    * Each ``pull'' may produce multiple packets, chained together using
    286    * bp->m_nextpkt.
    287    * Each packet that results from each pull has to be pulled through
    288    * all of the higher layers before the next resulting packet is pulled
    289    * through anything; this ensures that packets that depend on the
    290    * fsm state resulting from the receipt of the previous packet aren't
    291    * surprised.
    292    */
    293 
    294   link_AddInOctets(l, len);
    295 
    296   memset(lbp, '\0', sizeof lbp);
    297   lbp[0] = m_get(len, MB_UNKNOWN);
    298   memcpy(MBUF_CTOP(lbp[0]), buf, len);
    299   lproto[0] = 0;
    300   layer = 0;
    301 
    302   while (layer || lbp[layer]) {
    303     if (lbp[layer] == NULL) {
    304       layer--;
    305       continue;
    306     }
    307     bp = lbp[layer];
    308     lbp[layer] = bp->m_nextpkt;
    309     bp->m_nextpkt = NULL;
    310     proto = lproto[layer];
    311 
    312     if (l->layer[layer]->pull != NULL)
    313       bp = (*l->layer[layer]->pull)(b, l, bp, &proto);
    314 
    315     if (layer == l->nlayers - 1) {
    316       /* We've just done the top layer, despatch the packet(s) */
    317       while (bp) {
    318         next = bp->m_nextpkt;
    319         bp->m_nextpkt = NULL;
    320         log_Printf(LogDEBUG, "link_PullPacket: Despatch proto 0x%04x\n", proto);
    321         Despatch(b, l, bp, proto);
    322         bp = next;
    323       }
    324     } else {
    325       lbp[++layer] = bp;
    326       lproto[layer] = proto;
    327     }
    328   }
    329 }
    330 
    331 int
    332 link_Stack(struct link *l, struct layer *layer)
    333 {
    334   if (l->nlayers == sizeof l->layer / sizeof l->layer[0]) {
    335     log_Printf(LogERROR, "%s: Oops, cannot stack a %s layer...\n",
    336                l->name, layer->name);
    337     return 0;
    338   }
    339   l->layer[l->nlayers++] = layer;
    340   return 1;
    341 }
    342 
    343 void
    344 link_EmptyStack(struct link *l)
    345 {
    346   l->nlayers = 0;
    347 }
    348 
    349 static const struct {
    350   u_short proto;
    351   struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *);
    352 } despatcher[] = {
    353   { PROTO_IP, ipv4_Input },
    354 #ifndef NOINET6
    355   { PROTO_IPV6, ipv6_Input },
    356 #endif
    357   { PROTO_MP, mp_Input },
    358   { PROTO_LCP, lcp_Input },
    359   { PROTO_IPCP, ipcp_Input },
    360 #ifndef NOINET6
    361   { PROTO_IPV6CP, ipv6cp_Input },
    362 #endif
    363   { PROTO_PAP, pap_Input },
    364   { PROTO_CHAP, chap_Input },
    365   { PROTO_CCP, ccp_Input },
    366   { PROTO_LQR, lqr_Input },
    367   { PROTO_CBCP, cbcp_Input }
    368 };
    369 
    370 #define DSIZE (sizeof despatcher / sizeof despatcher[0])
    371 
    372 static void
    373 Despatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto)
    374 {
    375   unsigned f;
    376 
    377   for (f = 0; f < DSIZE; f++)
    378     if (despatcher[f].proto == proto) {
    379       bp = (*despatcher[f].fn)(bundle, l, bp);
    380       break;
    381     }
    382 
    383   if (bp) {
    384     struct physical *p = link2physical(l);
    385 
    386     log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n",
    387                f == DSIZE ? "Unknown" : "Unexpected", proto,
    388                hdlc_Protocol2Nam(proto));
    389     bp = m_pullup(proto_Prepend(bp, proto, 0, 0));
    390     lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->m_len);
    391     if (p) {
    392       p->hdlc.lqm.ifInDiscards++;
    393       p->hdlc.stats.unknownproto++;
    394     }
    395     m_freem(bp);
    396   }
    397 }
    398 
    399 int
    400 link_ShowLayers(struct cmdargs const *arg)
    401 {
    402   struct link *l = command_ChooseLink(arg);
    403   int layer;
    404 
    405   for (layer = l->nlayers; layer; layer--)
    406     prompt_Printf(arg->prompt, "%s%s", layer == l->nlayers ? "" : ", ",
    407                   l->layer[layer - 1]->name);
    408   if (l->nlayers)
    409     prompt_Printf(arg->prompt, "\n");
    410 
    411   return 0;
    412 }
    413