18c07a7b2SBrian Somers /*- 28c07a7b2SBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 38c07a7b2SBrian Somers * All rights reserved. 48c07a7b2SBrian Somers * 58c07a7b2SBrian Somers * Redistribution and use in source and binary forms, with or without 68c07a7b2SBrian Somers * modification, are permitted provided that the following conditions 78c07a7b2SBrian Somers * are met: 88c07a7b2SBrian Somers * 1. Redistributions of source code must retain the above copyright 98c07a7b2SBrian Somers * notice, this list of conditions and the following disclaimer. 108c07a7b2SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 118c07a7b2SBrian Somers * notice, this list of conditions and the following disclaimer in the 128c07a7b2SBrian Somers * documentation and/or other materials provided with the distribution. 138c07a7b2SBrian Somers * 148c07a7b2SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158c07a7b2SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168c07a7b2SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178c07a7b2SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188c07a7b2SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198c07a7b2SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208c07a7b2SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218c07a7b2SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228c07a7b2SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238c07a7b2SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248c07a7b2SBrian Somers * SUCH DAMAGE. 258c07a7b2SBrian Somers * 265d9e6103SBrian Somers * $Id: link.c,v 1.8 1999/03/31 14:21:45 brian Exp $ 278c07a7b2SBrian Somers * 288c07a7b2SBrian Somers */ 298c07a7b2SBrian Somers 302764b86aSBrian Somers #include <sys/types.h> 315d9e6103SBrian Somers #include <netinet/in_systm.h> 325d9e6103SBrian Somers #include <netdb.h> 335d9e6103SBrian Somers #include <sys/un.h> 345d9e6103SBrian Somers #include <netinet/in.h> 355d9e6103SBrian Somers #include <netinet/ip.h> 368c07a7b2SBrian Somers 378c07a7b2SBrian Somers #include <stdio.h> 38eb2d27cfSBrian Somers #include <string.h> 3985b542cfSBrian Somers #include <termios.h> 408c07a7b2SBrian Somers 4192b09558SBrian Somers #include "defs.h" 425d9e6103SBrian Somers #include "layer.h" 438c07a7b2SBrian Somers #include "mbuf.h" 448c07a7b2SBrian Somers #include "log.h" 458c07a7b2SBrian Somers #include "timer.h" 46879ed6faSBrian Somers #include "lqr.h" 4763258dccSBrian Somers #include "hdlc.h" 488c07a7b2SBrian Somers #include "throughput.h" 495d9e6103SBrian Somers #include "proto.h" 506d666775SBrian Somers #include "fsm.h" 5185b542cfSBrian Somers #include "descriptor.h" 523b0f8d2eSBrian Somers #include "lcp.h" 533b0f8d2eSBrian Somers #include "ccp.h" 543b0f8d2eSBrian Somers #include "link.h" 5585b542cfSBrian Somers #include "prompt.h" 565d9e6103SBrian Somers #include "async.h" 575d9e6103SBrian Somers #include "physical.h" 585d9e6103SBrian Somers #include "mp.h" 595d9e6103SBrian Somers #include "iplist.h" 605d9e6103SBrian Somers #include "slcompress.h" 615d9e6103SBrian Somers #include "ipcp.h" 625d9e6103SBrian Somers #include "ip.h" 635d9e6103SBrian Somers #include "auth.h" 645d9e6103SBrian Somers #include "pap.h" 655d9e6103SBrian Somers #include "chap.h" 665d9e6103SBrian Somers #include "cbcp.h" 675d9e6103SBrian Somers 685d9e6103SBrian Somers static void Despatch(struct bundle *, struct link *, struct mbuf *, u_short); 698c07a7b2SBrian Somers 708c07a7b2SBrian Somers void 718c07a7b2SBrian Somers link_AddInOctets(struct link *l, int n) 728c07a7b2SBrian Somers { 738c07a7b2SBrian Somers throughput_addin(&l->throughput, n); 748c07a7b2SBrian Somers } 758c07a7b2SBrian Somers 768c07a7b2SBrian Somers void 778c07a7b2SBrian Somers link_AddOutOctets(struct link *l, int n) 788c07a7b2SBrian Somers { 798c07a7b2SBrian Somers throughput_addout(&l->throughput, n); 808c07a7b2SBrian Somers } 818c07a7b2SBrian Somers 828c07a7b2SBrian Somers void 838c07a7b2SBrian Somers link_SequenceQueue(struct link *l) 848c07a7b2SBrian Somers { 85dd7e2610SBrian Somers log_Printf(LogDEBUG, "link_SequenceQueue\n"); 868c07a7b2SBrian Somers while (l->Queue[PRI_NORMAL].qlen) 87dd7e2610SBrian Somers mbuf_Enqueue(l->Queue + PRI_LINK, mbuf_Dequeue(l->Queue + PRI_NORMAL)); 888c07a7b2SBrian Somers } 898c07a7b2SBrian Somers 906f8e9f0aSBrian Somers void 916f8e9f0aSBrian Somers link_DeleteQueue(struct link *l) 926f8e9f0aSBrian Somers { 936f8e9f0aSBrian Somers struct mqueue *queue; 946f8e9f0aSBrian Somers 956f8e9f0aSBrian Somers for (queue = l->Queue; queue < l->Queue + LINK_QUEUES; queue++) 966f8e9f0aSBrian Somers while (queue->top) 976f8e9f0aSBrian Somers mbuf_Free(mbuf_Dequeue(queue)); 986f8e9f0aSBrian Somers } 996f8e9f0aSBrian Somers 1008c07a7b2SBrian Somers int 1018c07a7b2SBrian Somers link_QueueLen(struct link *l) 1028c07a7b2SBrian Somers { 1038c07a7b2SBrian Somers int i, len; 1048c07a7b2SBrian Somers 1058c07a7b2SBrian Somers for (i = 0, len = 0; i < LINK_QUEUES; i++) 1068c07a7b2SBrian Somers len += l->Queue[i].qlen; 1078c07a7b2SBrian Somers 1088c07a7b2SBrian Somers return len; 1098c07a7b2SBrian Somers } 1108c07a7b2SBrian Somers 1113b0f8d2eSBrian Somers int 1123b0f8d2eSBrian Somers link_QueueBytes(struct link *l) 1133b0f8d2eSBrian Somers { 1143b0f8d2eSBrian Somers int i, len, bytes; 1153b0f8d2eSBrian Somers struct mbuf *m; 1163b0f8d2eSBrian Somers 1173b0f8d2eSBrian Somers bytes = 0; 1183b0f8d2eSBrian Somers for (i = 0, len = 0; i < LINK_QUEUES; i++) { 1193b0f8d2eSBrian Somers len = l->Queue[i].qlen; 1203b0f8d2eSBrian Somers m = l->Queue[i].top; 1213b0f8d2eSBrian Somers while (len--) { 122dd7e2610SBrian Somers bytes += mbuf_Length(m); 1233b0f8d2eSBrian Somers m = m->pnext; 1243b0f8d2eSBrian Somers } 1253b0f8d2eSBrian Somers } 1263b0f8d2eSBrian Somers 1273b0f8d2eSBrian Somers return bytes; 1283b0f8d2eSBrian Somers } 1293b0f8d2eSBrian Somers 1308c07a7b2SBrian Somers struct mbuf * 1318c07a7b2SBrian Somers link_Dequeue(struct link *l) 1328c07a7b2SBrian Somers { 1338c07a7b2SBrian Somers int pri; 1348c07a7b2SBrian Somers struct mbuf *bp; 1358c07a7b2SBrian Somers 1368c07a7b2SBrian Somers for (bp = (struct mbuf *)0, pri = LINK_QUEUES - 1; pri >= 0; pri--) 1378c07a7b2SBrian Somers if (l->Queue[pri].qlen) { 138dd7e2610SBrian Somers bp = mbuf_Dequeue(l->Queue + pri); 139dd7e2610SBrian Somers log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d," 1402289f246SBrian Somers " containing %d more packets\n", pri, l->Queue[pri].qlen); 1418c07a7b2SBrian Somers break; 1428c07a7b2SBrian Somers } 1438c07a7b2SBrian Somers 1448c07a7b2SBrian Somers return bp; 1458c07a7b2SBrian Somers } 1468c07a7b2SBrian Somers 1478c07a7b2SBrian Somers static struct protostatheader { 1488c07a7b2SBrian Somers u_short number; 1498c07a7b2SBrian Somers const char *name; 1508c07a7b2SBrian Somers } ProtocolStat[NPROTOSTAT] = { 1518c07a7b2SBrian Somers { PROTO_IP, "IP" }, 1528c07a7b2SBrian Somers { PROTO_VJUNCOMP, "VJ_UNCOMP" }, 1538c07a7b2SBrian Somers { PROTO_VJCOMP, "VJ_COMP" }, 1548c07a7b2SBrian Somers { PROTO_COMPD, "COMPD" }, 155ed32233cSBrian Somers { PROTO_ICOMPD, "ICOMPD" }, 1568c07a7b2SBrian Somers { PROTO_LCP, "LCP" }, 1578c07a7b2SBrian Somers { PROTO_IPCP, "IPCP" }, 1588c07a7b2SBrian Somers { PROTO_CCP, "CCP" }, 1598c07a7b2SBrian Somers { PROTO_PAP, "PAP" }, 1608c07a7b2SBrian Somers { PROTO_LQR, "LQR" }, 1618c07a7b2SBrian Somers { PROTO_CHAP, "CHAP" }, 1623b0f8d2eSBrian Somers { PROTO_MP, "MULTILINK" }, 1638c07a7b2SBrian Somers { 0, "Others" } 1648c07a7b2SBrian Somers }; 1658c07a7b2SBrian Somers 1668c07a7b2SBrian Somers void 1678c07a7b2SBrian Somers link_ProtocolRecord(struct link *l, u_short proto, int type) 1688c07a7b2SBrian Somers { 1698c07a7b2SBrian Somers int i; 1708c07a7b2SBrian Somers 1718c07a7b2SBrian Somers for (i = 0; i < NPROTOSTAT; i++) 1728c07a7b2SBrian Somers if (ProtocolStat[i].number == proto) 1738c07a7b2SBrian Somers break; 1748c07a7b2SBrian Somers 1758c07a7b2SBrian Somers if (type == PROTO_IN) 1768c07a7b2SBrian Somers l->proto_in[i]++; 1778c07a7b2SBrian Somers else 1788c07a7b2SBrian Somers l->proto_out[i]++; 1798c07a7b2SBrian Somers } 1808c07a7b2SBrian Somers 1818c07a7b2SBrian Somers void 182b6217683SBrian Somers link_ReportProtocolStatus(struct link *l, struct prompt *prompt) 1838c07a7b2SBrian Somers { 1848c07a7b2SBrian Somers int i; 1858c07a7b2SBrian Somers 186b6217683SBrian Somers prompt_Printf(prompt, " Protocol in out " 18785b542cfSBrian Somers "Protocol in out\n"); 1888c07a7b2SBrian Somers for (i = 0; i < NPROTOSTAT; i++) { 189b6217683SBrian Somers prompt_Printf(prompt, " %-9s: %8lu, %8lu", 1908c07a7b2SBrian Somers ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]); 1918c07a7b2SBrian Somers if ((i % 2) == 0) 192b6217683SBrian Somers prompt_Printf(prompt, "\n"); 1938c07a7b2SBrian Somers } 1943b0f8d2eSBrian Somers if (!(i % 2)) 195b6217683SBrian Somers prompt_Printf(prompt, "\n"); 1968c07a7b2SBrian Somers } 1975d9e6103SBrian Somers 1985d9e6103SBrian Somers void 1995d9e6103SBrian Somers link_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri, 2005d9e6103SBrian Somers u_short proto) 2015d9e6103SBrian Somers { 2025d9e6103SBrian Somers int layer; 2035d9e6103SBrian Somers 2045d9e6103SBrian Somers /* 2055d9e6103SBrian Somers * When we ``push'' a packet into the link, it gets processed by the 2065d9e6103SBrian Somers * ``push'' function in each layer starting at the top. 2075d9e6103SBrian Somers * We never expect the result of a ``push'' to be more than one 2085d9e6103SBrian Somers * packet (as we do with ``pull''s). 2095d9e6103SBrian Somers */ 2105d9e6103SBrian Somers 2115d9e6103SBrian Somers if(pri < 0 || pri >= LINK_QUEUES) 2125d9e6103SBrian Somers pri = 0; 2135d9e6103SBrian Somers 2145d9e6103SBrian Somers for (layer = l->nlayers; layer && bp; layer--) 2155d9e6103SBrian Somers if (l->layer[layer - 1]->push != NULL) 2165d9e6103SBrian Somers bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto); 2175d9e6103SBrian Somers 2185d9e6103SBrian Somers if (bp) { 2195d9e6103SBrian Somers log_Printf(LogDEBUG, "link_PushPacket: proto = 0x%04x\n", proto); 2205d9e6103SBrian Somers link_AddOutOctets(l, mbuf_Length(bp)); 2215d9e6103SBrian Somers mbuf_Enqueue(l->Queue + pri, mbuf_Contiguous(bp)); 2225d9e6103SBrian Somers } 2235d9e6103SBrian Somers } 2245d9e6103SBrian Somers 2255d9e6103SBrian Somers void 2265d9e6103SBrian Somers link_PullPacket(struct link *l, char *buf, size_t len, struct bundle *b) 2275d9e6103SBrian Somers { 2285d9e6103SBrian Somers struct mbuf *bp, *lbp[LAYER_MAX], *next; 2295d9e6103SBrian Somers u_short lproto[LAYER_MAX], proto; 2305d9e6103SBrian Somers int layer; 2315d9e6103SBrian Somers 2325d9e6103SBrian Somers /* 2335d9e6103SBrian Somers * When we ``pull'' a packet from the link, it gets processed by the 2345d9e6103SBrian Somers * ``pull'' function in each layer starting at the bottom. 2355d9e6103SBrian Somers * Each ``pull'' may produce multiple packets, chained together using 2365d9e6103SBrian Somers * bp->pnext. 2375d9e6103SBrian Somers * Each packet that results from each pull has to be pulled through 2385d9e6103SBrian Somers * all of the higher layers before the next resulting packet is pulled 2395d9e6103SBrian Somers * through anything; this ensures that packets that depend on the 2405d9e6103SBrian Somers * fsm state resulting from the receipt of the previous packet aren't 2415d9e6103SBrian Somers * surprised. 2425d9e6103SBrian Somers */ 2435d9e6103SBrian Somers 2445d9e6103SBrian Somers link_AddInOctets(l, len); 2455d9e6103SBrian Somers 2465d9e6103SBrian Somers memset(lbp, '\0', sizeof lbp); 2475d9e6103SBrian Somers lbp[0] = mbuf_Alloc(len, MB_ASYNC); 2485d9e6103SBrian Somers memcpy(MBUF_CTOP(lbp[0]), buf, len); 2495d9e6103SBrian Somers lproto[0] = 0; 2505d9e6103SBrian Somers layer = 0; 2515d9e6103SBrian Somers 2525d9e6103SBrian Somers while (layer || lbp[layer]) { 2535d9e6103SBrian Somers if (lbp[layer] == NULL) { 2545d9e6103SBrian Somers layer--; 2555d9e6103SBrian Somers continue; 2565d9e6103SBrian Somers } 2575d9e6103SBrian Somers bp = lbp[layer]; 2585d9e6103SBrian Somers lbp[layer] = bp->pnext; 2595d9e6103SBrian Somers bp->pnext = NULL; 2605d9e6103SBrian Somers proto = lproto[layer]; 2615d9e6103SBrian Somers 2625d9e6103SBrian Somers if (l->layer[layer]->pull != NULL) 2635d9e6103SBrian Somers bp = (*l->layer[layer]->pull)(b, l, bp, &proto); 2645d9e6103SBrian Somers 2655d9e6103SBrian Somers if (layer == l->nlayers - 1) { 2665d9e6103SBrian Somers /* We've just done the top layer, despatch the packet(s) */ 2675d9e6103SBrian Somers while (bp) { 2685d9e6103SBrian Somers next = bp->pnext; 2695d9e6103SBrian Somers bp->pnext = NULL; 2705d9e6103SBrian Somers Despatch(b, l, bp, proto); 2715d9e6103SBrian Somers bp = next; 2725d9e6103SBrian Somers } 2735d9e6103SBrian Somers } else { 2745d9e6103SBrian Somers lbp[++layer] = bp; 2755d9e6103SBrian Somers lproto[layer] = proto; 2765d9e6103SBrian Somers } 2775d9e6103SBrian Somers } 2785d9e6103SBrian Somers } 2795d9e6103SBrian Somers 2805d9e6103SBrian Somers int 2815d9e6103SBrian Somers link_Stack(struct link *l, struct layer *layer) 2825d9e6103SBrian Somers { 2835d9e6103SBrian Somers if (l->nlayers == sizeof l->layer / sizeof l->layer[0]) { 2845d9e6103SBrian Somers log_Printf(LogERROR, "%s: Oops, cannot stack a %s layer...\n", 2855d9e6103SBrian Somers l->name, layer->name); 2865d9e6103SBrian Somers return 0; 2875d9e6103SBrian Somers } 2885d9e6103SBrian Somers l->layer[l->nlayers++] = layer; 2895d9e6103SBrian Somers return 1; 2905d9e6103SBrian Somers } 2915d9e6103SBrian Somers 2925d9e6103SBrian Somers void 2935d9e6103SBrian Somers link_EmptyStack(struct link *l) 2945d9e6103SBrian Somers { 2955d9e6103SBrian Somers l->nlayers = 0; 2965d9e6103SBrian Somers } 2975d9e6103SBrian Somers 2985d9e6103SBrian Somers static const struct { 2995d9e6103SBrian Somers u_short proto; 3005d9e6103SBrian Somers struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *); 3015d9e6103SBrian Somers } despatcher[] = { 3025d9e6103SBrian Somers { PROTO_IP, ip_Input }, 3035d9e6103SBrian Somers { PROTO_MP, mp_Input }, 3045d9e6103SBrian Somers { PROTO_LCP, lcp_Input }, 3055d9e6103SBrian Somers { PROTO_IPCP, ipcp_Input }, 3065d9e6103SBrian Somers { PROTO_PAP, pap_Input }, 3075d9e6103SBrian Somers { PROTO_CHAP, chap_Input }, 3085d9e6103SBrian Somers { PROTO_CCP, ccp_Input }, 3095d9e6103SBrian Somers { PROTO_LQR, lqr_Input }, 3105d9e6103SBrian Somers { PROTO_CBCP, cbcp_Input } 3115d9e6103SBrian Somers }; 3125d9e6103SBrian Somers 3135d9e6103SBrian Somers #define DSIZE (sizeof despatcher / sizeof despatcher[0]) 3145d9e6103SBrian Somers 3155d9e6103SBrian Somers static void 3165d9e6103SBrian Somers Despatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto) 3175d9e6103SBrian Somers { 3185d9e6103SBrian Somers int f; 3195d9e6103SBrian Somers 3205d9e6103SBrian Somers for (f = 0; f < DSIZE; f++) 3215d9e6103SBrian Somers if (despatcher[f].proto == proto) { 3225d9e6103SBrian Somers bp = (*despatcher[f].fn)(bundle, l, bp); 3235d9e6103SBrian Somers break; 3245d9e6103SBrian Somers } 3255d9e6103SBrian Somers 3265d9e6103SBrian Somers if (bp) { 3275d9e6103SBrian Somers struct physical *p = link2physical(l); 3285d9e6103SBrian Somers 3295d9e6103SBrian Somers log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n", 3305d9e6103SBrian Somers f == DSIZE ? "Unknown" : "Unexpected", proto, 3315d9e6103SBrian Somers hdlc_Protocol2Nam(proto)); 3325d9e6103SBrian Somers bp = mbuf_Contiguous(proto_Prepend(bp, proto, 0, 0)); 3335d9e6103SBrian Somers lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->cnt); 3345d9e6103SBrian Somers if (p) { 3355d9e6103SBrian Somers p->hdlc.lqm.SaveInDiscards++; 3365d9e6103SBrian Somers p->hdlc.stats.unknownproto++; 3375d9e6103SBrian Somers } 3385d9e6103SBrian Somers mbuf_Free(bp); 3395d9e6103SBrian Somers } 3405d9e6103SBrian Somers } 341