link.c revision 50867
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 * 2650479Speter * $FreeBSD: head/usr.sbin/ppp/link.c 50867 1999-09-04 00:00:21Z brian $ 2736285Sbrian * 2836285Sbrian */ 2936285Sbrian 3036285Sbrian#include <sys/types.h> 3146686Sbrian#include <netinet/in_systm.h> 3246686Sbrian#include <sys/un.h> 3346686Sbrian#include <netinet/in.h> 3446686Sbrian#include <netinet/ip.h> 3536285Sbrian 3636285Sbrian#include <stdio.h> 3745193Sbrian#include <string.h> 3836285Sbrian#include <termios.h> 3936285Sbrian 4038174Sbrian#include "defs.h" 4146686Sbrian#include "layer.h" 4236285Sbrian#include "mbuf.h" 4336285Sbrian#include "log.h" 4436285Sbrian#include "timer.h" 4536285Sbrian#include "lqr.h" 4636285Sbrian#include "hdlc.h" 4736285Sbrian#include "throughput.h" 4846686Sbrian#include "proto.h" 4936285Sbrian#include "fsm.h" 5036285Sbrian#include "descriptor.h" 5136285Sbrian#include "lcp.h" 5236285Sbrian#include "ccp.h" 5336285Sbrian#include "link.h" 5436285Sbrian#include "prompt.h" 5546686Sbrian#include "async.h" 5646686Sbrian#include "physical.h" 5746686Sbrian#include "mp.h" 5846686Sbrian#include "iplist.h" 5946686Sbrian#include "slcompress.h" 6046686Sbrian#include "ipcp.h" 6146686Sbrian#include "ip.h" 6246686Sbrian#include "auth.h" 6346686Sbrian#include "pap.h" 6446686Sbrian#include "chap.h" 6546686Sbrian#include "cbcp.h" 6647211Sbrian#include "command.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{ 8550867Sbrian struct mqueue *queue, *highest; 8650867Sbrian 8736285Sbrian log_Printf(LogDEBUG, "link_SequenceQueue\n"); 8850867Sbrian 8950867Sbrian highest = LINK_HIGHQ(l); 9050867Sbrian for (queue = l->Queue; queue < highest; queue++) 9150867Sbrian while (queue->qlen) 9250867Sbrian mbuf_Enqueue(highest, mbuf_Dequeue(queue)); 9336285Sbrian} 9436285Sbrian 9538544Sbrianvoid 9638544Sbrianlink_DeleteQueue(struct link *l) 9738544Sbrian{ 9850867Sbrian struct mqueue *queue, *highest; 9938544Sbrian 10050867Sbrian highest = LINK_HIGHQ(l); 10150867Sbrian for (queue = l->Queue; queue <= highest; queue++) 10238544Sbrian while (queue->top) 10338544Sbrian mbuf_Free(mbuf_Dequeue(queue)); 10438544Sbrian} 10538544Sbrian 10636285Sbrianint 10736285Sbrianlink_QueueLen(struct link *l) 10836285Sbrian{ 10936285Sbrian int i, len; 11036285Sbrian 11150867Sbrian for (i = 0, len = 0; i < LINK_QUEUES(l); i++) 11236285Sbrian len += l->Queue[i].qlen; 11336285Sbrian 11436285Sbrian return len; 11536285Sbrian} 11636285Sbrian 11736285Sbrianint 11836285Sbrianlink_QueueBytes(struct link *l) 11936285Sbrian{ 12036285Sbrian int i, len, bytes; 12136285Sbrian struct mbuf *m; 12236285Sbrian 12336285Sbrian bytes = 0; 12450867Sbrian for (i = 0, len = 0; i < LINK_QUEUES(l); i++) { 12536285Sbrian len = l->Queue[i].qlen; 12636285Sbrian m = l->Queue[i].top; 12736285Sbrian while (len--) { 12836285Sbrian bytes += mbuf_Length(m); 12936285Sbrian m = m->pnext; 13036285Sbrian } 13136285Sbrian } 13236285Sbrian 13336285Sbrian return bytes; 13436285Sbrian} 13536285Sbrian 13636285Sbrianstruct mbuf * 13736285Sbrianlink_Dequeue(struct link *l) 13836285Sbrian{ 13936285Sbrian int pri; 14036285Sbrian struct mbuf *bp; 14136285Sbrian 14250867Sbrian for (bp = NULL, pri = LINK_QUEUES(l) - 1; pri >= 0; pri--) 14336285Sbrian if (l->Queue[pri].qlen) { 14436285Sbrian bp = mbuf_Dequeue(l->Queue + pri); 14536285Sbrian log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d," 14636285Sbrian " containing %d more packets\n", pri, l->Queue[pri].qlen); 14736285Sbrian break; 14836285Sbrian } 14936285Sbrian 15036285Sbrian return bp; 15136285Sbrian} 15236285Sbrian 15336285Sbrianstatic struct protostatheader { 15436285Sbrian u_short number; 15536285Sbrian const char *name; 15636285Sbrian} ProtocolStat[NPROTOSTAT] = { 15736285Sbrian { PROTO_IP, "IP" }, 15836285Sbrian { PROTO_VJUNCOMP, "VJ_UNCOMP" }, 15936285Sbrian { PROTO_VJCOMP, "VJ_COMP" }, 16036285Sbrian { PROTO_COMPD, "COMPD" }, 16136285Sbrian { PROTO_ICOMPD, "ICOMPD" }, 16236285Sbrian { PROTO_LCP, "LCP" }, 16336285Sbrian { PROTO_IPCP, "IPCP" }, 16436285Sbrian { PROTO_CCP, "CCP" }, 16536285Sbrian { PROTO_PAP, "PAP" }, 16636285Sbrian { PROTO_LQR, "LQR" }, 16736285Sbrian { PROTO_CHAP, "CHAP" }, 16836285Sbrian { PROTO_MP, "MULTILINK" }, 16936285Sbrian { 0, "Others" } 17036285Sbrian}; 17136285Sbrian 17236285Sbrianvoid 17336285Sbrianlink_ProtocolRecord(struct link *l, u_short proto, int type) 17436285Sbrian{ 17536285Sbrian int i; 17636285Sbrian 17736285Sbrian for (i = 0; i < NPROTOSTAT; i++) 17836285Sbrian if (ProtocolStat[i].number == proto) 17936285Sbrian break; 18036285Sbrian 18136285Sbrian if (type == PROTO_IN) 18236285Sbrian l->proto_in[i]++; 18336285Sbrian else 18436285Sbrian l->proto_out[i]++; 18536285Sbrian} 18636285Sbrian 18736285Sbrianvoid 18836285Sbrianlink_ReportProtocolStatus(struct link *l, struct prompt *prompt) 18936285Sbrian{ 19036285Sbrian int i; 19136285Sbrian 19236285Sbrian prompt_Printf(prompt, " Protocol in out " 19336285Sbrian "Protocol in out\n"); 19436285Sbrian for (i = 0; i < NPROTOSTAT; i++) { 19536285Sbrian prompt_Printf(prompt, " %-9s: %8lu, %8lu", 19636285Sbrian ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]); 19736285Sbrian if ((i % 2) == 0) 19836285Sbrian prompt_Printf(prompt, "\n"); 19936285Sbrian } 20036285Sbrian if (!(i % 2)) 20136285Sbrian prompt_Printf(prompt, "\n"); 20236285Sbrian} 20346686Sbrian 20446686Sbrianvoid 20546686Sbrianlink_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri, 20646686Sbrian u_short proto) 20746686Sbrian{ 20846686Sbrian int layer; 20946686Sbrian 21046686Sbrian /* 21146686Sbrian * When we ``push'' a packet into the link, it gets processed by the 21246686Sbrian * ``push'' function in each layer starting at the top. 21346686Sbrian * We never expect the result of a ``push'' to be more than one 21446686Sbrian * packet (as we do with ``pull''s). 21546686Sbrian */ 21646686Sbrian 21750867Sbrian if(pri < 0 || pri >= LINK_QUEUES(l)) 21846686Sbrian pri = 0; 21946686Sbrian 22046686Sbrian for (layer = l->nlayers; layer && bp; layer--) 22146686Sbrian if (l->layer[layer - 1]->push != NULL) 22246686Sbrian bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto); 22346686Sbrian 22446686Sbrian if (bp) { 22546686Sbrian link_AddOutOctets(l, mbuf_Length(bp)); 22647061Sbrian log_Printf(LogDEBUG, "link_PushPacket: Transmit proto 0x%04x\n", proto); 22746686Sbrian mbuf_Enqueue(l->Queue + pri, mbuf_Contiguous(bp)); 22846686Sbrian } 22946686Sbrian} 23046686Sbrian 23146686Sbrianvoid 23246686Sbrianlink_PullPacket(struct link *l, char *buf, size_t len, struct bundle *b) 23346686Sbrian{ 23446686Sbrian struct mbuf *bp, *lbp[LAYER_MAX], *next; 23546686Sbrian u_short lproto[LAYER_MAX], proto; 23646686Sbrian int layer; 23746686Sbrian 23846686Sbrian /* 23946686Sbrian * When we ``pull'' a packet from the link, it gets processed by the 24046686Sbrian * ``pull'' function in each layer starting at the bottom. 24146686Sbrian * Each ``pull'' may produce multiple packets, chained together using 24246686Sbrian * bp->pnext. 24346686Sbrian * Each packet that results from each pull has to be pulled through 24446686Sbrian * all of the higher layers before the next resulting packet is pulled 24546686Sbrian * through anything; this ensures that packets that depend on the 24646686Sbrian * fsm state resulting from the receipt of the previous packet aren't 24746686Sbrian * surprised. 24846686Sbrian */ 24946686Sbrian 25046686Sbrian link_AddInOctets(l, len); 25146686Sbrian 25246686Sbrian memset(lbp, '\0', sizeof lbp); 25347695Sbrian lbp[0] = mbuf_Alloc(len, MB_UNKNOWN); 25446686Sbrian memcpy(MBUF_CTOP(lbp[0]), buf, len); 25546686Sbrian lproto[0] = 0; 25646686Sbrian layer = 0; 25746686Sbrian 25846686Sbrian while (layer || lbp[layer]) { 25946686Sbrian if (lbp[layer] == NULL) { 26046686Sbrian layer--; 26146686Sbrian continue; 26246686Sbrian } 26346686Sbrian bp = lbp[layer]; 26446686Sbrian lbp[layer] = bp->pnext; 26546686Sbrian bp->pnext = NULL; 26646686Sbrian proto = lproto[layer]; 26746686Sbrian 26846686Sbrian if (l->layer[layer]->pull != NULL) 26946686Sbrian bp = (*l->layer[layer]->pull)(b, l, bp, &proto); 27046686Sbrian 27146686Sbrian if (layer == l->nlayers - 1) { 27246686Sbrian /* We've just done the top layer, despatch the packet(s) */ 27346686Sbrian while (bp) { 27446686Sbrian next = bp->pnext; 27546686Sbrian bp->pnext = NULL; 27647061Sbrian log_Printf(LogDEBUG, "link_PullPacket: Despatch proto 0x%04x\n", proto); 27746686Sbrian Despatch(b, l, bp, proto); 27846686Sbrian bp = next; 27946686Sbrian } 28046686Sbrian } else { 28146686Sbrian lbp[++layer] = bp; 28246686Sbrian lproto[layer] = proto; 28346686Sbrian } 28446686Sbrian } 28546686Sbrian} 28646686Sbrian 28746686Sbrianint 28846686Sbrianlink_Stack(struct link *l, struct layer *layer) 28946686Sbrian{ 29046686Sbrian if (l->nlayers == sizeof l->layer / sizeof l->layer[0]) { 29146686Sbrian log_Printf(LogERROR, "%s: Oops, cannot stack a %s layer...\n", 29246686Sbrian l->name, layer->name); 29346686Sbrian return 0; 29446686Sbrian } 29546686Sbrian l->layer[l->nlayers++] = layer; 29646686Sbrian return 1; 29746686Sbrian} 29846686Sbrian 29946686Sbrianvoid 30046686Sbrianlink_EmptyStack(struct link *l) 30146686Sbrian{ 30246686Sbrian l->nlayers = 0; 30346686Sbrian} 30446686Sbrian 30546686Sbrianstatic const struct { 30646686Sbrian u_short proto; 30746686Sbrian struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *); 30846686Sbrian} despatcher[] = { 30946686Sbrian { PROTO_IP, ip_Input }, 31046686Sbrian { PROTO_MP, mp_Input }, 31146686Sbrian { PROTO_LCP, lcp_Input }, 31246686Sbrian { PROTO_IPCP, ipcp_Input }, 31346686Sbrian { PROTO_PAP, pap_Input }, 31446686Sbrian { PROTO_CHAP, chap_Input }, 31546686Sbrian { PROTO_CCP, ccp_Input }, 31646686Sbrian { PROTO_LQR, lqr_Input }, 31746686Sbrian { PROTO_CBCP, cbcp_Input } 31846686Sbrian}; 31946686Sbrian 32046686Sbrian#define DSIZE (sizeof despatcher / sizeof despatcher[0]) 32146686Sbrian 32246686Sbrianstatic void 32346686SbrianDespatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto) 32446686Sbrian{ 32546686Sbrian int f; 32646686Sbrian 32746686Sbrian for (f = 0; f < DSIZE; f++) 32846686Sbrian if (despatcher[f].proto == proto) { 32946686Sbrian bp = (*despatcher[f].fn)(bundle, l, bp); 33046686Sbrian break; 33146686Sbrian } 33246686Sbrian 33346686Sbrian if (bp) { 33446686Sbrian struct physical *p = link2physical(l); 33546686Sbrian 33646686Sbrian log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n", 33746686Sbrian f == DSIZE ? "Unknown" : "Unexpected", proto, 33846686Sbrian hdlc_Protocol2Nam(proto)); 33946686Sbrian bp = mbuf_Contiguous(proto_Prepend(bp, proto, 0, 0)); 34046686Sbrian lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->cnt); 34146686Sbrian if (p) { 34246686Sbrian p->hdlc.lqm.SaveInDiscards++; 34346686Sbrian p->hdlc.stats.unknownproto++; 34446686Sbrian } 34546686Sbrian mbuf_Free(bp); 34646686Sbrian } 34746686Sbrian} 34847211Sbrian 34947211Sbrianint 35047211Sbrianlink_ShowLayers(struct cmdargs const *arg) 35147211Sbrian{ 35247211Sbrian struct link *l = command_ChooseLink(arg); 35347211Sbrian int layer; 35447211Sbrian 35547211Sbrian for (layer = l->nlayers; layer; layer--) 35647211Sbrian prompt_Printf(arg->prompt, "%s%s", layer == l->nlayers ? "" : ", ", 35747211Sbrian l->layer[layer - 1]->name); 35847211Sbrian if (l->nlayers) 35947211Sbrian prompt_Printf(arg->prompt, "\n"); 36047211Sbrian 36147211Sbrian return 0; 36247211Sbrian} 363