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 * 2697d92980SPeter Wemm * $FreeBSD$ 278c07a7b2SBrian Somers * 288c07a7b2SBrian Somers */ 298c07a7b2SBrian Somers 302764b86aSBrian Somers #include <sys/types.h> 315d9e6103SBrian Somers #include <netinet/in_systm.h> 3230949fd4SBrian Somers #include <sys/socket.h> 335d9e6103SBrian Somers #include <sys/un.h> 345d9e6103SBrian Somers #include <netinet/in.h> 355d9e6103SBrian Somers #include <netinet/ip.h> 368c07a7b2SBrian Somers 376eafd353SBrian Somers #include <stdarg.h> 388c07a7b2SBrian Somers #include <stdio.h> 39eb2d27cfSBrian Somers #include <string.h> 4085b542cfSBrian Somers #include <termios.h> 418c07a7b2SBrian Somers 4292b09558SBrian Somers #include "defs.h" 435d9e6103SBrian Somers #include "layer.h" 448c07a7b2SBrian Somers #include "mbuf.h" 458c07a7b2SBrian Somers #include "log.h" 468c07a7b2SBrian Somers #include "timer.h" 47879ed6faSBrian Somers #include "lqr.h" 4863258dccSBrian Somers #include "hdlc.h" 498c07a7b2SBrian Somers #include "throughput.h" 505d9e6103SBrian Somers #include "proto.h" 516d666775SBrian Somers #include "fsm.h" 5285b542cfSBrian Somers #include "descriptor.h" 533b0f8d2eSBrian Somers #include "lcp.h" 543b0f8d2eSBrian Somers #include "ccp.h" 553b0f8d2eSBrian Somers #include "link.h" 5685b542cfSBrian Somers #include "prompt.h" 575d9e6103SBrian Somers #include "async.h" 585d9e6103SBrian Somers #include "physical.h" 595d9e6103SBrian Somers #include "mp.h" 605d9e6103SBrian Somers #include "iplist.h" 615d9e6103SBrian Somers #include "slcompress.h" 6230949fd4SBrian Somers #include "ncpaddr.h" 635d9e6103SBrian Somers #include "ip.h" 6430949fd4SBrian Somers #include "ipcp.h" 6530949fd4SBrian Somers #include "ipv6cp.h" 665d9e6103SBrian Somers #include "auth.h" 675d9e6103SBrian Somers #include "pap.h" 685d9e6103SBrian Somers #include "chap.h" 695d9e6103SBrian Somers #include "cbcp.h" 704faec430SBrian Somers #include "command.h" 715d9e6103SBrian Somers 725d9e6103SBrian Somers static void Despatch(struct bundle *, struct link *, struct mbuf *, u_short); 738c07a7b2SBrian Somers 7411572abfSBrian Somers static inline void 758c07a7b2SBrian Somers link_AddInOctets(struct link *l, int n) 768c07a7b2SBrian Somers { 7711572abfSBrian Somers if (l->stats.gather) { 7811572abfSBrian Somers throughput_addin(&l->stats.total, n); 7911572abfSBrian Somers if (l->stats.parent) 8011572abfSBrian Somers throughput_addin(l->stats.parent, n); 8111572abfSBrian Somers } 828c07a7b2SBrian Somers } 838c07a7b2SBrian Somers 8411572abfSBrian Somers static inline void 858c07a7b2SBrian Somers link_AddOutOctets(struct link *l, int n) 868c07a7b2SBrian Somers { 8711572abfSBrian Somers if (l->stats.gather) { 8811572abfSBrian Somers throughput_addout(&l->stats.total, n); 8911572abfSBrian Somers if (l->stats.parent) 9011572abfSBrian Somers throughput_addout(l->stats.parent, n); 9111572abfSBrian Somers } 928c07a7b2SBrian Somers } 938c07a7b2SBrian Somers 948c07a7b2SBrian Somers void 958c07a7b2SBrian Somers link_SequenceQueue(struct link *l) 968c07a7b2SBrian Somers { 97442f8495SBrian Somers struct mqueue *queue, *highest; 98442f8495SBrian Somers 99dd7e2610SBrian Somers log_Printf(LogDEBUG, "link_SequenceQueue\n"); 100442f8495SBrian Somers 101442f8495SBrian Somers highest = LINK_HIGHQ(l); 102442f8495SBrian Somers for (queue = l->Queue; queue < highest; queue++) 10326af0ae9SBrian Somers while (queue->len) 10426af0ae9SBrian Somers m_enqueue(highest, m_dequeue(queue)); 1058c07a7b2SBrian Somers } 1068c07a7b2SBrian Somers 1076f8e9f0aSBrian Somers void 1086f8e9f0aSBrian Somers link_DeleteQueue(struct link *l) 1096f8e9f0aSBrian Somers { 110442f8495SBrian Somers struct mqueue *queue, *highest; 1116f8e9f0aSBrian Somers 112442f8495SBrian Somers highest = LINK_HIGHQ(l); 113442f8495SBrian Somers for (queue = l->Queue; queue <= highest; queue++) 1146f8e9f0aSBrian Somers while (queue->top) 11526af0ae9SBrian Somers m_freem(m_dequeue(queue)); 1166f8e9f0aSBrian Somers } 1176f8e9f0aSBrian Somers 11826af0ae9SBrian Somers size_t 1198c07a7b2SBrian Somers link_QueueLen(struct link *l) 1208c07a7b2SBrian Somers { 121057f1760SBrian Somers unsigned i; 12226af0ae9SBrian Somers size_t len; 1238c07a7b2SBrian Somers 124442f8495SBrian Somers for (i = 0, len = 0; i < LINK_QUEUES(l); i++) 12526af0ae9SBrian Somers len += l->Queue[i].len; 1268c07a7b2SBrian Somers 1278c07a7b2SBrian Somers return len; 1288c07a7b2SBrian Somers } 1298c07a7b2SBrian Somers 13026af0ae9SBrian Somers size_t 1313b0f8d2eSBrian Somers link_QueueBytes(struct link *l) 1323b0f8d2eSBrian Somers { 133057f1760SBrian Somers unsigned i; 13426af0ae9SBrian Somers size_t len, bytes; 1353b0f8d2eSBrian Somers struct mbuf *m; 1363b0f8d2eSBrian Somers 1373b0f8d2eSBrian Somers bytes = 0; 138442f8495SBrian Somers for (i = 0, len = 0; i < LINK_QUEUES(l); i++) { 13926af0ae9SBrian Somers len = l->Queue[i].len; 1403b0f8d2eSBrian Somers m = l->Queue[i].top; 1413b0f8d2eSBrian Somers while (len--) { 14226af0ae9SBrian Somers bytes += m_length(m); 14326af0ae9SBrian Somers m = m->m_nextpkt; 1443b0f8d2eSBrian Somers } 1453b0f8d2eSBrian Somers } 1463b0f8d2eSBrian Somers 1473b0f8d2eSBrian Somers return bytes; 1483b0f8d2eSBrian Somers } 1493b0f8d2eSBrian Somers 150a57095e7SBrian Somers void 151a57095e7SBrian Somers link_PendingLowPriorityData(struct link *l, size_t *pkts, size_t *octets) 152a57095e7SBrian Somers { 153a57095e7SBrian Somers struct mqueue *queue, *highest; 154a57095e7SBrian Somers struct mbuf *m; 155a57095e7SBrian Somers size_t len; 156a57095e7SBrian Somers 157a57095e7SBrian Somers /* 158a57095e7SBrian Somers * This is all rfc1989 stuff... because our LQR packet is going to bypass 159a57095e7SBrian Somers * everything that's not in the highest priority queue, we must be able to 160a57095e7SBrian Somers * subtract that data from our outgoing packet/octet counts. However, 161a57095e7SBrian Somers * we've already async-encoded our data at this point, but the async 162a57095e7SBrian Somers * encodings MUSTn't be a part of the LQR-reported payload :( So, we have 163a57095e7SBrian Somers * the async layer record how much it's padded the packet in the mbuf's 164a57095e7SBrian Somers * priv field, and when we calculate our outgoing LQR values we subtract 165a57095e7SBrian Somers * this value for each packet from the octet count sent. 166a57095e7SBrian Somers */ 167a57095e7SBrian Somers 168a57095e7SBrian Somers highest = LINK_HIGHQ(l); 169a57095e7SBrian Somers *pkts = *octets = 0; 170a57095e7SBrian Somers for (queue = l->Queue; queue < highest; queue++) { 171a57095e7SBrian Somers len = queue->len; 172a57095e7SBrian Somers *pkts += len; 173a57095e7SBrian Somers for (m = queue->top; len--; m = m->m_nextpkt) 174a57095e7SBrian Somers *octets += m_length(m) - m->priv; 175a57095e7SBrian Somers } 176a57095e7SBrian Somers } 177a57095e7SBrian Somers 1788c07a7b2SBrian Somers struct mbuf * 1798c07a7b2SBrian Somers link_Dequeue(struct link *l) 1808c07a7b2SBrian Somers { 1818c07a7b2SBrian Somers int pri; 1828c07a7b2SBrian Somers struct mbuf *bp; 1838c07a7b2SBrian Somers 184442f8495SBrian Somers for (bp = NULL, pri = LINK_QUEUES(l) - 1; pri >= 0; pri--) 18526af0ae9SBrian Somers if (l->Queue[pri].len) { 18626af0ae9SBrian Somers bp = m_dequeue(l->Queue + pri); 187dd7e2610SBrian Somers log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d," 18826af0ae9SBrian Somers " containing %lu more packets\n", pri, 18926af0ae9SBrian Somers (u_long)l->Queue[pri].len); 1908c07a7b2SBrian Somers break; 1918c07a7b2SBrian Somers } 1928c07a7b2SBrian Somers 1938c07a7b2SBrian Somers return bp; 1948c07a7b2SBrian Somers } 1958c07a7b2SBrian Somers 1968c07a7b2SBrian Somers static struct protostatheader { 1978c07a7b2SBrian Somers u_short number; 1988c07a7b2SBrian Somers const char *name; 1998c07a7b2SBrian Somers } ProtocolStat[NPROTOSTAT] = { 2008c07a7b2SBrian Somers { PROTO_IP, "IP" }, 2018c07a7b2SBrian Somers { PROTO_VJUNCOMP, "VJ_UNCOMP" }, 2028c07a7b2SBrian Somers { PROTO_VJCOMP, "VJ_COMP" }, 2038c07a7b2SBrian Somers { PROTO_COMPD, "COMPD" }, 204ed32233cSBrian Somers { PROTO_ICOMPD, "ICOMPD" }, 2058c07a7b2SBrian Somers { PROTO_LCP, "LCP" }, 2068c07a7b2SBrian Somers { PROTO_IPCP, "IPCP" }, 2078c07a7b2SBrian Somers { PROTO_CCP, "CCP" }, 2088c07a7b2SBrian Somers { PROTO_PAP, "PAP" }, 2098c07a7b2SBrian Somers { PROTO_LQR, "LQR" }, 2108c07a7b2SBrian Somers { PROTO_CHAP, "CHAP" }, 2113b0f8d2eSBrian Somers { PROTO_MP, "MULTILINK" }, 212*647bedd5SDon Lewis { 0, "Others" } /* must be last */ 2138c07a7b2SBrian Somers }; 2148c07a7b2SBrian Somers 2158c07a7b2SBrian Somers void 2168c07a7b2SBrian Somers link_ProtocolRecord(struct link *l, u_short proto, int type) 2178c07a7b2SBrian Somers { 2188c07a7b2SBrian Somers int i; 2198c07a7b2SBrian Somers 2208c07a7b2SBrian Somers for (i = 0; i < NPROTOSTAT; i++) 221*647bedd5SDon Lewis if (ProtocolStat[i].number == proto || ProtocolStat[i].number == 0) { 2228c07a7b2SBrian Somers if (type == PROTO_IN) 2238c07a7b2SBrian Somers l->proto_in[i]++; 2248c07a7b2SBrian Somers else 2258c07a7b2SBrian Somers l->proto_out[i]++; 226*647bedd5SDon Lewis break; 227*647bedd5SDon Lewis } 2288c07a7b2SBrian Somers } 2298c07a7b2SBrian Somers 2308c07a7b2SBrian Somers void 231b6217683SBrian Somers link_ReportProtocolStatus(struct link *l, struct prompt *prompt) 2328c07a7b2SBrian Somers { 2338c07a7b2SBrian Somers int i; 2348c07a7b2SBrian Somers 235b6217683SBrian Somers prompt_Printf(prompt, " Protocol in out " 23685b542cfSBrian Somers "Protocol in out\n"); 2378c07a7b2SBrian Somers for (i = 0; i < NPROTOSTAT; i++) { 238b6217683SBrian Somers prompt_Printf(prompt, " %-9s: %8lu, %8lu", 2398c07a7b2SBrian Somers ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]); 2408c07a7b2SBrian Somers if ((i % 2) == 0) 241b6217683SBrian Somers prompt_Printf(prompt, "\n"); 2428c07a7b2SBrian Somers } 2433b0f8d2eSBrian Somers if (!(i % 2)) 244b6217683SBrian Somers prompt_Printf(prompt, "\n"); 2458c07a7b2SBrian Somers } 2465d9e6103SBrian Somers 2475d9e6103SBrian Somers void 2485d9e6103SBrian Somers link_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri, 2495d9e6103SBrian Somers u_short proto) 2505d9e6103SBrian Somers { 2515d9e6103SBrian Somers int layer; 2525d9e6103SBrian Somers 2535d9e6103SBrian Somers /* 2545d9e6103SBrian Somers * When we ``push'' a packet into the link, it gets processed by the 2555d9e6103SBrian Somers * ``push'' function in each layer starting at the top. 2565d9e6103SBrian Somers * We never expect the result of a ``push'' to be more than one 2575d9e6103SBrian Somers * packet (as we do with ``pull''s). 2585d9e6103SBrian Somers */ 2595d9e6103SBrian Somers 260057f1760SBrian Somers if(pri < 0 || (unsigned)pri >= LINK_QUEUES(l)) 2615d9e6103SBrian Somers pri = 0; 2625d9e6103SBrian Somers 263a57095e7SBrian Somers bp->priv = 0; /* Adjusted by the async layer ! */ 2645d9e6103SBrian Somers for (layer = l->nlayers; layer && bp; layer--) 2655d9e6103SBrian Somers if (l->layer[layer - 1]->push != NULL) 2665d9e6103SBrian Somers bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto); 2675d9e6103SBrian Somers 2685d9e6103SBrian Somers if (bp) { 26926af0ae9SBrian Somers link_AddOutOctets(l, m_length(bp)); 2706815097bSBrian Somers log_Printf(LogDEBUG, "link_PushPacket: Transmit proto 0x%04x\n", proto); 27126af0ae9SBrian Somers m_enqueue(l->Queue + pri, m_pullup(bp)); 2725d9e6103SBrian Somers } 2735d9e6103SBrian Somers } 2745d9e6103SBrian Somers 2755d9e6103SBrian Somers void 2765d9e6103SBrian Somers link_PullPacket(struct link *l, char *buf, size_t len, struct bundle *b) 2775d9e6103SBrian Somers { 2785d9e6103SBrian Somers struct mbuf *bp, *lbp[LAYER_MAX], *next; 2795d9e6103SBrian Somers u_short lproto[LAYER_MAX], proto; 2805d9e6103SBrian Somers int layer; 2815d9e6103SBrian Somers 2825d9e6103SBrian Somers /* 2835d9e6103SBrian Somers * When we ``pull'' a packet from the link, it gets processed by the 2845d9e6103SBrian Somers * ``pull'' function in each layer starting at the bottom. 2855d9e6103SBrian Somers * Each ``pull'' may produce multiple packets, chained together using 28626af0ae9SBrian Somers * bp->m_nextpkt. 2875d9e6103SBrian Somers * Each packet that results from each pull has to be pulled through 2885d9e6103SBrian Somers * all of the higher layers before the next resulting packet is pulled 2895d9e6103SBrian Somers * through anything; this ensures that packets that depend on the 2905d9e6103SBrian Somers * fsm state resulting from the receipt of the previous packet aren't 2915d9e6103SBrian Somers * surprised. 2925d9e6103SBrian Somers */ 2935d9e6103SBrian Somers 2945d9e6103SBrian Somers link_AddInOctets(l, len); 2955d9e6103SBrian Somers 2965d9e6103SBrian Somers memset(lbp, '\0', sizeof lbp); 29726af0ae9SBrian Somers lbp[0] = m_get(len, MB_UNKNOWN); 2985d9e6103SBrian Somers memcpy(MBUF_CTOP(lbp[0]), buf, len); 2995d9e6103SBrian Somers lproto[0] = 0; 3005d9e6103SBrian Somers layer = 0; 3015d9e6103SBrian Somers 3025d9e6103SBrian Somers while (layer || lbp[layer]) { 3035d9e6103SBrian Somers if (lbp[layer] == NULL) { 3045d9e6103SBrian Somers layer--; 3055d9e6103SBrian Somers continue; 3065d9e6103SBrian Somers } 3075d9e6103SBrian Somers bp = lbp[layer]; 30826af0ae9SBrian Somers lbp[layer] = bp->m_nextpkt; 30926af0ae9SBrian Somers bp->m_nextpkt = NULL; 3105d9e6103SBrian Somers proto = lproto[layer]; 3115d9e6103SBrian Somers 3125d9e6103SBrian Somers if (l->layer[layer]->pull != NULL) 3135d9e6103SBrian Somers bp = (*l->layer[layer]->pull)(b, l, bp, &proto); 3145d9e6103SBrian Somers 3155d9e6103SBrian Somers if (layer == l->nlayers - 1) { 3165d9e6103SBrian Somers /* We've just done the top layer, despatch the packet(s) */ 3175d9e6103SBrian Somers while (bp) { 31826af0ae9SBrian Somers next = bp->m_nextpkt; 31926af0ae9SBrian Somers bp->m_nextpkt = NULL; 3206815097bSBrian Somers log_Printf(LogDEBUG, "link_PullPacket: Despatch proto 0x%04x\n", proto); 3215d9e6103SBrian Somers Despatch(b, l, bp, proto); 3225d9e6103SBrian Somers bp = next; 3235d9e6103SBrian Somers } 3245d9e6103SBrian Somers } else { 3255d9e6103SBrian Somers lbp[++layer] = bp; 3265d9e6103SBrian Somers lproto[layer] = proto; 3275d9e6103SBrian Somers } 3285d9e6103SBrian Somers } 3295d9e6103SBrian Somers } 3305d9e6103SBrian Somers 3315d9e6103SBrian Somers int 3325d9e6103SBrian Somers link_Stack(struct link *l, struct layer *layer) 3335d9e6103SBrian Somers { 3345d9e6103SBrian Somers if (l->nlayers == sizeof l->layer / sizeof l->layer[0]) { 3355d9e6103SBrian Somers log_Printf(LogERROR, "%s: Oops, cannot stack a %s layer...\n", 3365d9e6103SBrian Somers l->name, layer->name); 3375d9e6103SBrian Somers return 0; 3385d9e6103SBrian Somers } 3395d9e6103SBrian Somers l->layer[l->nlayers++] = layer; 3405d9e6103SBrian Somers return 1; 3415d9e6103SBrian Somers } 3425d9e6103SBrian Somers 3435d9e6103SBrian Somers void 3445d9e6103SBrian Somers link_EmptyStack(struct link *l) 3455d9e6103SBrian Somers { 3465d9e6103SBrian Somers l->nlayers = 0; 3475d9e6103SBrian Somers } 3485d9e6103SBrian Somers 3495d9e6103SBrian Somers static const struct { 3505d9e6103SBrian Somers u_short proto; 3515d9e6103SBrian Somers struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *); 3525d9e6103SBrian Somers } despatcher[] = { 35330949fd4SBrian Somers { PROTO_IP, ipv4_Input }, 35430949fd4SBrian Somers #ifndef NOINET6 35530949fd4SBrian Somers { PROTO_IPV6, ipv6_Input }, 35630949fd4SBrian Somers #endif 3575d9e6103SBrian Somers { PROTO_MP, mp_Input }, 3585d9e6103SBrian Somers { PROTO_LCP, lcp_Input }, 3595d9e6103SBrian Somers { PROTO_IPCP, ipcp_Input }, 36030949fd4SBrian Somers #ifndef NOINET6 36130949fd4SBrian Somers { PROTO_IPV6CP, ipv6cp_Input }, 36230949fd4SBrian Somers #endif 3635d9e6103SBrian Somers { PROTO_PAP, pap_Input }, 3645d9e6103SBrian Somers { PROTO_CHAP, chap_Input }, 3655d9e6103SBrian Somers { PROTO_CCP, ccp_Input }, 3665d9e6103SBrian Somers { PROTO_LQR, lqr_Input }, 3675d9e6103SBrian Somers { PROTO_CBCP, cbcp_Input } 3685d9e6103SBrian Somers }; 3695d9e6103SBrian Somers 3705d9e6103SBrian Somers #define DSIZE (sizeof despatcher / sizeof despatcher[0]) 3715d9e6103SBrian Somers 3725d9e6103SBrian Somers static void 3735d9e6103SBrian Somers Despatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto) 3745d9e6103SBrian Somers { 375057f1760SBrian Somers unsigned f; 3765d9e6103SBrian Somers 3775d9e6103SBrian Somers for (f = 0; f < DSIZE; f++) 3785d9e6103SBrian Somers if (despatcher[f].proto == proto) { 3795d9e6103SBrian Somers bp = (*despatcher[f].fn)(bundle, l, bp); 3805d9e6103SBrian Somers break; 3815d9e6103SBrian Somers } 3825d9e6103SBrian Somers 3835d9e6103SBrian Somers if (bp) { 3845d9e6103SBrian Somers struct physical *p = link2physical(l); 3855d9e6103SBrian Somers 3865d9e6103SBrian Somers log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n", 3875d9e6103SBrian Somers f == DSIZE ? "Unknown" : "Unexpected", proto, 3885d9e6103SBrian Somers hdlc_Protocol2Nam(proto)); 38926af0ae9SBrian Somers bp = m_pullup(proto_Prepend(bp, proto, 0, 0)); 39026af0ae9SBrian Somers lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->m_len); 3915d9e6103SBrian Somers if (p) { 392a57095e7SBrian Somers p->hdlc.lqm.ifInDiscards++; 3935d9e6103SBrian Somers p->hdlc.stats.unknownproto++; 3945d9e6103SBrian Somers } 39526af0ae9SBrian Somers m_freem(bp); 3965d9e6103SBrian Somers } 3975d9e6103SBrian Somers } 3984faec430SBrian Somers 3994faec430SBrian Somers int 4004faec430SBrian Somers link_ShowLayers(struct cmdargs const *arg) 4014faec430SBrian Somers { 4024faec430SBrian Somers struct link *l = command_ChooseLink(arg); 4034faec430SBrian Somers int layer; 4044faec430SBrian Somers 4054faec430SBrian Somers for (layer = l->nlayers; layer; layer--) 4064faec430SBrian Somers prompt_Printf(arg->prompt, "%s%s", layer == l->nlayers ? "" : ", ", 4074faec430SBrian Somers l->layer[layer - 1]->name); 4084faec430SBrian Somers if (l->nlayers) 4094faec430SBrian Somers prompt_Printf(arg->prompt, "\n"); 4104faec430SBrian Somers 4114faec430SBrian Somers return 0; 4124faec430SBrian Somers } 413