link.c revision 47061
136285Sbrian/*- 236285Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 336285Sbrian * All rights reserved. 436285Sbrian * 536285Sbrian * Redistribution and use in source and binary forms, with or without 636285Sbrian * modification, are permitted provided that the following conditions 736285Sbrian * are met: 836285Sbrian * 1. Redistributions of source code must retain the above copyright 936285Sbrian * notice, this list of conditions and the following disclaimer. 1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer in the 1236285Sbrian * documentation and/or other materials provided with the distribution. 1336285Sbrian * 1436285Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1536285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1636285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1736285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1836285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1936285Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2036285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2136285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2236285Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2336285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2436285Sbrian * SUCH DAMAGE. 2536285Sbrian * 2647061Sbrian * $Id: link.c,v 1.9 1999/05/08 11:06:58 brian Exp $ 2736285Sbrian * 2836285Sbrian */ 2936285Sbrian 3036285Sbrian#include <sys/types.h> 3146686Sbrian#include <netinet/in_systm.h> 3246686Sbrian#include <netdb.h> 3346686Sbrian#include <sys/un.h> 3446686Sbrian#include <netinet/in.h> 3546686Sbrian#include <netinet/ip.h> 3636285Sbrian 3736285Sbrian#include <stdio.h> 3845193Sbrian#include <string.h> 3936285Sbrian#include <termios.h> 4036285Sbrian 4138174Sbrian#include "defs.h" 4246686Sbrian#include "layer.h" 4336285Sbrian#include "mbuf.h" 4436285Sbrian#include "log.h" 4536285Sbrian#include "timer.h" 4636285Sbrian#include "lqr.h" 4736285Sbrian#include "hdlc.h" 4836285Sbrian#include "throughput.h" 4946686Sbrian#include "proto.h" 5036285Sbrian#include "fsm.h" 5136285Sbrian#include "descriptor.h" 5236285Sbrian#include "lcp.h" 5336285Sbrian#include "ccp.h" 5436285Sbrian#include "link.h" 5536285Sbrian#include "prompt.h" 5646686Sbrian#include "async.h" 5746686Sbrian#include "physical.h" 5846686Sbrian#include "mp.h" 5946686Sbrian#include "iplist.h" 6046686Sbrian#include "slcompress.h" 6146686Sbrian#include "ipcp.h" 6246686Sbrian#include "ip.h" 6346686Sbrian#include "auth.h" 6446686Sbrian#include "pap.h" 6546686Sbrian#include "chap.h" 6646686Sbrian#include "cbcp.h" 6736285Sbrian 6846686Sbrianstatic void Despatch(struct bundle *, struct link *, struct mbuf *, u_short); 6946686Sbrian 7036285Sbrianvoid 7136285Sbrianlink_AddInOctets(struct link *l, int n) 7236285Sbrian{ 7336285Sbrian throughput_addin(&l->throughput, n); 7436285Sbrian} 7536285Sbrian 7636285Sbrianvoid 7736285Sbrianlink_AddOutOctets(struct link *l, int n) 7836285Sbrian{ 7936285Sbrian throughput_addout(&l->throughput, n); 8036285Sbrian} 8136285Sbrian 8236285Sbrianvoid 8336285Sbrianlink_SequenceQueue(struct link *l) 8436285Sbrian{ 8536285Sbrian log_Printf(LogDEBUG, "link_SequenceQueue\n"); 8636285Sbrian while (l->Queue[PRI_NORMAL].qlen) 8736285Sbrian mbuf_Enqueue(l->Queue + PRI_LINK, mbuf_Dequeue(l->Queue + PRI_NORMAL)); 8836285Sbrian} 8936285Sbrian 9038544Sbrianvoid 9138544Sbrianlink_DeleteQueue(struct link *l) 9238544Sbrian{ 9338544Sbrian struct mqueue *queue; 9438544Sbrian 9538544Sbrian for (queue = l->Queue; queue < l->Queue + LINK_QUEUES; queue++) 9638544Sbrian while (queue->top) 9738544Sbrian mbuf_Free(mbuf_Dequeue(queue)); 9838544Sbrian} 9938544Sbrian 10036285Sbrianint 10136285Sbrianlink_QueueLen(struct link *l) 10236285Sbrian{ 10336285Sbrian int i, len; 10436285Sbrian 10536285Sbrian for (i = 0, len = 0; i < LINK_QUEUES; i++) 10636285Sbrian len += l->Queue[i].qlen; 10736285Sbrian 10836285Sbrian return len; 10936285Sbrian} 11036285Sbrian 11136285Sbrianint 11236285Sbrianlink_QueueBytes(struct link *l) 11336285Sbrian{ 11436285Sbrian int i, len, bytes; 11536285Sbrian struct mbuf *m; 11636285Sbrian 11736285Sbrian bytes = 0; 11836285Sbrian for (i = 0, len = 0; i < LINK_QUEUES; i++) { 11936285Sbrian len = l->Queue[i].qlen; 12036285Sbrian m = l->Queue[i].top; 12136285Sbrian while (len--) { 12236285Sbrian bytes += mbuf_Length(m); 12336285Sbrian m = m->pnext; 12436285Sbrian } 12536285Sbrian } 12636285Sbrian 12736285Sbrian return bytes; 12836285Sbrian} 12936285Sbrian 13036285Sbrianstruct mbuf * 13136285Sbrianlink_Dequeue(struct link *l) 13236285Sbrian{ 13336285Sbrian int pri; 13436285Sbrian struct mbuf *bp; 13536285Sbrian 13636285Sbrian for (bp = (struct mbuf *)0, pri = LINK_QUEUES - 1; pri >= 0; pri--) 13736285Sbrian if (l->Queue[pri].qlen) { 13836285Sbrian bp = mbuf_Dequeue(l->Queue + pri); 13936285Sbrian log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d," 14036285Sbrian " containing %d more packets\n", pri, l->Queue[pri].qlen); 14136285Sbrian break; 14236285Sbrian } 14336285Sbrian 14436285Sbrian return bp; 14536285Sbrian} 14636285Sbrian 14736285Sbrianstatic struct protostatheader { 14836285Sbrian u_short number; 14936285Sbrian const char *name; 15036285Sbrian} ProtocolStat[NPROTOSTAT] = { 15136285Sbrian { PROTO_IP, "IP" }, 15236285Sbrian { PROTO_VJUNCOMP, "VJ_UNCOMP" }, 15336285Sbrian { PROTO_VJCOMP, "VJ_COMP" }, 15436285Sbrian { PROTO_COMPD, "COMPD" }, 15536285Sbrian { PROTO_ICOMPD, "ICOMPD" }, 15636285Sbrian { PROTO_LCP, "LCP" }, 15736285Sbrian { PROTO_IPCP, "IPCP" }, 15836285Sbrian { PROTO_CCP, "CCP" }, 15936285Sbrian { PROTO_PAP, "PAP" }, 16036285Sbrian { PROTO_LQR, "LQR" }, 16136285Sbrian { PROTO_CHAP, "CHAP" }, 16236285Sbrian { PROTO_MP, "MULTILINK" }, 16336285Sbrian { 0, "Others" } 16436285Sbrian}; 16536285Sbrian 16636285Sbrianvoid 16736285Sbrianlink_ProtocolRecord(struct link *l, u_short proto, int type) 16836285Sbrian{ 16936285Sbrian int i; 17036285Sbrian 17136285Sbrian for (i = 0; i < NPROTOSTAT; i++) 17236285Sbrian if (ProtocolStat[i].number == proto) 17336285Sbrian break; 17436285Sbrian 17536285Sbrian if (type == PROTO_IN) 17636285Sbrian l->proto_in[i]++; 17736285Sbrian else 17836285Sbrian l->proto_out[i]++; 17936285Sbrian} 18036285Sbrian 18136285Sbrianvoid 18236285Sbrianlink_ReportProtocolStatus(struct link *l, struct prompt *prompt) 18336285Sbrian{ 18436285Sbrian int i; 18536285Sbrian 18636285Sbrian prompt_Printf(prompt, " Protocol in out " 18736285Sbrian "Protocol in out\n"); 18836285Sbrian for (i = 0; i < NPROTOSTAT; i++) { 18936285Sbrian prompt_Printf(prompt, " %-9s: %8lu, %8lu", 19036285Sbrian ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]); 19136285Sbrian if ((i % 2) == 0) 19236285Sbrian prompt_Printf(prompt, "\n"); 19336285Sbrian } 19436285Sbrian if (!(i % 2)) 19536285Sbrian prompt_Printf(prompt, "\n"); 19636285Sbrian} 19746686Sbrian 19846686Sbrianvoid 19946686Sbrianlink_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri, 20046686Sbrian u_short proto) 20146686Sbrian{ 20246686Sbrian int layer; 20346686Sbrian 20446686Sbrian /* 20546686Sbrian * When we ``push'' a packet into the link, it gets processed by the 20646686Sbrian * ``push'' function in each layer starting at the top. 20746686Sbrian * We never expect the result of a ``push'' to be more than one 20846686Sbrian * packet (as we do with ``pull''s). 20946686Sbrian */ 21046686Sbrian 21146686Sbrian if(pri < 0 || pri >= LINK_QUEUES) 21246686Sbrian pri = 0; 21346686Sbrian 21446686Sbrian for (layer = l->nlayers; layer && bp; layer--) 21546686Sbrian if (l->layer[layer - 1]->push != NULL) 21646686Sbrian bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto); 21746686Sbrian 21846686Sbrian if (bp) { 21946686Sbrian link_AddOutOctets(l, mbuf_Length(bp)); 22047061Sbrian log_Printf(LogDEBUG, "link_PushPacket: Transmit proto 0x%04x\n", proto); 22146686Sbrian mbuf_Enqueue(l->Queue + pri, mbuf_Contiguous(bp)); 22246686Sbrian } 22346686Sbrian} 22446686Sbrian 22546686Sbrianvoid 22646686Sbrianlink_PullPacket(struct link *l, char *buf, size_t len, struct bundle *b) 22746686Sbrian{ 22846686Sbrian struct mbuf *bp, *lbp[LAYER_MAX], *next; 22946686Sbrian u_short lproto[LAYER_MAX], proto; 23046686Sbrian int layer; 23146686Sbrian 23246686Sbrian /* 23346686Sbrian * When we ``pull'' a packet from the link, it gets processed by the 23446686Sbrian * ``pull'' function in each layer starting at the bottom. 23546686Sbrian * Each ``pull'' may produce multiple packets, chained together using 23646686Sbrian * bp->pnext. 23746686Sbrian * Each packet that results from each pull has to be pulled through 23846686Sbrian * all of the higher layers before the next resulting packet is pulled 23946686Sbrian * through anything; this ensures that packets that depend on the 24046686Sbrian * fsm state resulting from the receipt of the previous packet aren't 24146686Sbrian * surprised. 24246686Sbrian */ 24346686Sbrian 24446686Sbrian link_AddInOctets(l, len); 24546686Sbrian 24646686Sbrian memset(lbp, '\0', sizeof lbp); 24746686Sbrian lbp[0] = mbuf_Alloc(len, MB_ASYNC); 24846686Sbrian memcpy(MBUF_CTOP(lbp[0]), buf, len); 24946686Sbrian lproto[0] = 0; 25046686Sbrian layer = 0; 25146686Sbrian 25246686Sbrian while (layer || lbp[layer]) { 25346686Sbrian if (lbp[layer] == NULL) { 25446686Sbrian layer--; 25546686Sbrian continue; 25646686Sbrian } 25746686Sbrian bp = lbp[layer]; 25846686Sbrian lbp[layer] = bp->pnext; 25946686Sbrian bp->pnext = NULL; 26046686Sbrian proto = lproto[layer]; 26146686Sbrian 26246686Sbrian if (l->layer[layer]->pull != NULL) 26346686Sbrian bp = (*l->layer[layer]->pull)(b, l, bp, &proto); 26446686Sbrian 26546686Sbrian if (layer == l->nlayers - 1) { 26646686Sbrian /* We've just done the top layer, despatch the packet(s) */ 26746686Sbrian while (bp) { 26846686Sbrian next = bp->pnext; 26946686Sbrian bp->pnext = NULL; 27047061Sbrian log_Printf(LogDEBUG, "link_PullPacket: Despatch proto 0x%04x\n", proto); 27146686Sbrian Despatch(b, l, bp, proto); 27246686Sbrian bp = next; 27346686Sbrian } 27446686Sbrian } else { 27546686Sbrian lbp[++layer] = bp; 27646686Sbrian lproto[layer] = proto; 27746686Sbrian } 27846686Sbrian } 27946686Sbrian} 28046686Sbrian 28146686Sbrianint 28246686Sbrianlink_Stack(struct link *l, struct layer *layer) 28346686Sbrian{ 28446686Sbrian if (l->nlayers == sizeof l->layer / sizeof l->layer[0]) { 28546686Sbrian log_Printf(LogERROR, "%s: Oops, cannot stack a %s layer...\n", 28646686Sbrian l->name, layer->name); 28746686Sbrian return 0; 28846686Sbrian } 28946686Sbrian l->layer[l->nlayers++] = layer; 29046686Sbrian return 1; 29146686Sbrian} 29246686Sbrian 29346686Sbrianvoid 29446686Sbrianlink_EmptyStack(struct link *l) 29546686Sbrian{ 29646686Sbrian l->nlayers = 0; 29746686Sbrian} 29846686Sbrian 29946686Sbrianstatic const struct { 30046686Sbrian u_short proto; 30146686Sbrian struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *); 30246686Sbrian} despatcher[] = { 30346686Sbrian { PROTO_IP, ip_Input }, 30446686Sbrian { PROTO_MP, mp_Input }, 30546686Sbrian { PROTO_LCP, lcp_Input }, 30646686Sbrian { PROTO_IPCP, ipcp_Input }, 30746686Sbrian { PROTO_PAP, pap_Input }, 30846686Sbrian { PROTO_CHAP, chap_Input }, 30946686Sbrian { PROTO_CCP, ccp_Input }, 31046686Sbrian { PROTO_LQR, lqr_Input }, 31146686Sbrian { PROTO_CBCP, cbcp_Input } 31246686Sbrian}; 31346686Sbrian 31446686Sbrian#define DSIZE (sizeof despatcher / sizeof despatcher[0]) 31546686Sbrian 31646686Sbrianstatic void 31746686SbrianDespatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto) 31846686Sbrian{ 31946686Sbrian int f; 32046686Sbrian 32146686Sbrian for (f = 0; f < DSIZE; f++) 32246686Sbrian if (despatcher[f].proto == proto) { 32346686Sbrian bp = (*despatcher[f].fn)(bundle, l, bp); 32446686Sbrian break; 32546686Sbrian } 32646686Sbrian 32746686Sbrian if (bp) { 32846686Sbrian struct physical *p = link2physical(l); 32946686Sbrian 33046686Sbrian log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n", 33146686Sbrian f == DSIZE ? "Unknown" : "Unexpected", proto, 33246686Sbrian hdlc_Protocol2Nam(proto)); 33346686Sbrian bp = mbuf_Contiguous(proto_Prepend(bp, proto, 0, 0)); 33446686Sbrian lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->cnt); 33546686Sbrian if (p) { 33646686Sbrian p->hdlc.lqm.SaveInDiscards++; 33746686Sbrian p->hdlc.stats.unknownproto++; 33846686Sbrian } 33946686Sbrian mbuf_Free(bp); 34046686Sbrian } 34146686Sbrian} 342