xref: /freebsd/usr.sbin/ppp/link.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
1 /*-
2  * Copyright (c) 1998 Brian Somers <brian@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  *  $Id: link.c,v 1.11 1999/05/15 02:24:18 brian Exp $
27  *
28  */
29 
30 #include <sys/types.h>
31 #include <netinet/in_systm.h>
32 #include <netdb.h>
33 #include <sys/un.h>
34 #include <netinet/in.h>
35 #include <netinet/ip.h>
36 
37 #include <stdio.h>
38 #include <string.h>
39 #include <termios.h>
40 
41 #include "defs.h"
42 #include "layer.h"
43 #include "mbuf.h"
44 #include "log.h"
45 #include "timer.h"
46 #include "lqr.h"
47 #include "hdlc.h"
48 #include "throughput.h"
49 #include "proto.h"
50 #include "fsm.h"
51 #include "descriptor.h"
52 #include "lcp.h"
53 #include "ccp.h"
54 #include "link.h"
55 #include "prompt.h"
56 #include "async.h"
57 #include "physical.h"
58 #include "mp.h"
59 #include "iplist.h"
60 #include "slcompress.h"
61 #include "ipcp.h"
62 #include "ip.h"
63 #include "auth.h"
64 #include "pap.h"
65 #include "chap.h"
66 #include "cbcp.h"
67 #include "command.h"
68 
69 static void Despatch(struct bundle *, struct link *, struct mbuf *, u_short);
70 
71 void
72 link_AddInOctets(struct link *l, int n)
73 {
74   throughput_addin(&l->throughput, n);
75 }
76 
77 void
78 link_AddOutOctets(struct link *l, int n)
79 {
80   throughput_addout(&l->throughput, n);
81 }
82 
83 void
84 link_SequenceQueue(struct link *l)
85 {
86   log_Printf(LogDEBUG, "link_SequenceQueue\n");
87   while (l->Queue[PRI_NORMAL].qlen)
88     mbuf_Enqueue(l->Queue + PRI_LINK, mbuf_Dequeue(l->Queue + PRI_NORMAL));
89 }
90 
91 void
92 link_DeleteQueue(struct link *l)
93 {
94   struct mqueue *queue;
95 
96   for (queue = l->Queue; queue < l->Queue + LINK_QUEUES; queue++)
97     while (queue->top)
98       mbuf_Free(mbuf_Dequeue(queue));
99 }
100 
101 int
102 link_QueueLen(struct link *l)
103 {
104   int i, len;
105 
106   for (i = 0, len = 0; i < LINK_QUEUES; i++)
107     len += l->Queue[i].qlen;
108 
109   return len;
110 }
111 
112 int
113 link_QueueBytes(struct link *l)
114 {
115   int i, len, bytes;
116   struct mbuf *m;
117 
118   bytes = 0;
119   for (i = 0, len = 0; i < LINK_QUEUES; i++) {
120     len = l->Queue[i].qlen;
121     m = l->Queue[i].top;
122     while (len--) {
123       bytes += mbuf_Length(m);
124       m = m->pnext;
125     }
126   }
127 
128   return bytes;
129 }
130 
131 struct mbuf *
132 link_Dequeue(struct link *l)
133 {
134   int pri;
135   struct mbuf *bp;
136 
137   for (bp = (struct mbuf *)0, pri = LINK_QUEUES - 1; pri >= 0; pri--)
138     if (l->Queue[pri].qlen) {
139       bp = mbuf_Dequeue(l->Queue + pri);
140       log_Printf(LogDEBUG, "link_Dequeue: Dequeued from queue %d,"
141                 " containing %d more packets\n", pri, l->Queue[pri].qlen);
142       break;
143     }
144 
145   return bp;
146 }
147 
148 static struct protostatheader {
149   u_short number;
150   const char *name;
151 } ProtocolStat[NPROTOSTAT] = {
152   { PROTO_IP, "IP" },
153   { PROTO_VJUNCOMP, "VJ_UNCOMP" },
154   { PROTO_VJCOMP, "VJ_COMP" },
155   { PROTO_COMPD, "COMPD" },
156   { PROTO_ICOMPD, "ICOMPD" },
157   { PROTO_LCP, "LCP" },
158   { PROTO_IPCP, "IPCP" },
159   { PROTO_CCP, "CCP" },
160   { PROTO_PAP, "PAP" },
161   { PROTO_LQR, "LQR" },
162   { PROTO_CHAP, "CHAP" },
163   { PROTO_MP, "MULTILINK" },
164   { 0, "Others" }
165 };
166 
167 void
168 link_ProtocolRecord(struct link *l, u_short proto, int type)
169 {
170   int i;
171 
172   for (i = 0; i < NPROTOSTAT; i++)
173     if (ProtocolStat[i].number == proto)
174       break;
175 
176   if (type == PROTO_IN)
177     l->proto_in[i]++;
178   else
179     l->proto_out[i]++;
180 }
181 
182 void
183 link_ReportProtocolStatus(struct link *l, struct prompt *prompt)
184 {
185   int i;
186 
187   prompt_Printf(prompt, "    Protocol     in        out      "
188                 "Protocol      in       out\n");
189   for (i = 0; i < NPROTOSTAT; i++) {
190     prompt_Printf(prompt, "   %-9s: %8lu, %8lu",
191 	    ProtocolStat[i].name, l->proto_in[i], l->proto_out[i]);
192     if ((i % 2) == 0)
193       prompt_Printf(prompt, "\n");
194   }
195   if (!(i % 2))
196     prompt_Printf(prompt, "\n");
197 }
198 
199 void
200 link_PushPacket(struct link *l, struct mbuf *bp, struct bundle *b, int pri,
201                 u_short proto)
202 {
203   int layer;
204 
205   /*
206    * When we ``push'' a packet into the link, it gets processed by the
207    * ``push'' function in each layer starting at the top.
208    * We never expect the result of a ``push'' to be more than one
209    * packet (as we do with ``pull''s).
210    */
211 
212   if(pri < 0 || pri >= LINK_QUEUES)
213     pri = 0;
214 
215   for (layer = l->nlayers; layer && bp; layer--)
216     if (l->layer[layer - 1]->push != NULL)
217       bp = (*l->layer[layer - 1]->push)(b, l, bp, pri, &proto);
218 
219   if (bp) {
220     link_AddOutOctets(l, mbuf_Length(bp));
221     log_Printf(LogDEBUG, "link_PushPacket: Transmit proto 0x%04x\n", proto);
222     mbuf_Enqueue(l->Queue + pri, mbuf_Contiguous(bp));
223   }
224 }
225 
226 void
227 link_PullPacket(struct link *l, char *buf, size_t len, struct bundle *b)
228 {
229   struct mbuf *bp, *lbp[LAYER_MAX], *next;
230   u_short lproto[LAYER_MAX], proto;
231   int layer;
232 
233   /*
234    * When we ``pull'' a packet from the link, it gets processed by the
235    * ``pull'' function in each layer starting at the bottom.
236    * Each ``pull'' may produce multiple packets, chained together using
237    * bp->pnext.
238    * Each packet that results from each pull has to be pulled through
239    * all of the higher layers before the next resulting packet is pulled
240    * through anything; this ensures that packets that depend on the
241    * fsm state resulting from the receipt of the previous packet aren't
242    * surprised.
243    */
244 
245   link_AddInOctets(l, len);
246 
247   memset(lbp, '\0', sizeof lbp);
248   lbp[0] = mbuf_Alloc(len, MB_UNKNOWN);
249   memcpy(MBUF_CTOP(lbp[0]), buf, len);
250   lproto[0] = 0;
251   layer = 0;
252 
253   while (layer || lbp[layer]) {
254     if (lbp[layer] == NULL) {
255       layer--;
256       continue;
257     }
258     bp = lbp[layer];
259     lbp[layer] = bp->pnext;
260     bp->pnext = NULL;
261     proto = lproto[layer];
262 
263     if (l->layer[layer]->pull != NULL)
264       bp = (*l->layer[layer]->pull)(b, l, bp, &proto);
265 
266     if (layer == l->nlayers - 1) {
267       /* We've just done the top layer, despatch the packet(s) */
268       while (bp) {
269         next = bp->pnext;
270         bp->pnext = NULL;
271         log_Printf(LogDEBUG, "link_PullPacket: Despatch proto 0x%04x\n", proto);
272         Despatch(b, l, bp, proto);
273         bp = next;
274       }
275     } else {
276       lbp[++layer] = bp;
277       lproto[layer] = proto;
278     }
279   }
280 }
281 
282 int
283 link_Stack(struct link *l, struct layer *layer)
284 {
285   if (l->nlayers == sizeof l->layer / sizeof l->layer[0]) {
286     log_Printf(LogERROR, "%s: Oops, cannot stack a %s layer...\n",
287                l->name, layer->name);
288     return 0;
289   }
290   l->layer[l->nlayers++] = layer;
291   return 1;
292 }
293 
294 void
295 link_EmptyStack(struct link *l)
296 {
297   l->nlayers = 0;
298 }
299 
300 static const struct {
301   u_short proto;
302   struct mbuf *(*fn)(struct bundle *, struct link *, struct mbuf *);
303 } despatcher[] = {
304   { PROTO_IP, ip_Input },
305   { PROTO_MP, mp_Input },
306   { PROTO_LCP, lcp_Input },
307   { PROTO_IPCP, ipcp_Input },
308   { PROTO_PAP, pap_Input },
309   { PROTO_CHAP, chap_Input },
310   { PROTO_CCP, ccp_Input },
311   { PROTO_LQR, lqr_Input },
312   { PROTO_CBCP, cbcp_Input }
313 };
314 
315 #define DSIZE (sizeof despatcher / sizeof despatcher[0])
316 
317 static void
318 Despatch(struct bundle *bundle, struct link *l, struct mbuf *bp, u_short proto)
319 {
320   int f;
321 
322   for (f = 0; f < DSIZE; f++)
323     if (despatcher[f].proto == proto) {
324       bp = (*despatcher[f].fn)(bundle, l, bp);
325       break;
326     }
327 
328   if (bp) {
329     struct physical *p = link2physical(l);
330 
331     log_Printf(LogPHASE, "%s protocol 0x%04x (%s)\n",
332                f == DSIZE ? "Unknown" : "Unexpected", proto,
333                hdlc_Protocol2Nam(proto));
334     bp = mbuf_Contiguous(proto_Prepend(bp, proto, 0, 0));
335     lcp_SendProtoRej(&l->lcp, MBUF_CTOP(bp), bp->cnt);
336     if (p) {
337       p->hdlc.lqm.SaveInDiscards++;
338       p->hdlc.stats.unknownproto++;
339     }
340     mbuf_Free(bp);
341   }
342 }
343 
344 int
345 link_ShowLayers(struct cmdargs const *arg)
346 {
347   struct link *l = command_ChooseLink(arg);
348   int layer;
349 
350   for (layer = l->nlayers; layer; layer--)
351     prompt_Printf(arg->prompt, "%s%s", layer == l->nlayers ? "" : ", ",
352                   l->layer[layer - 1]->name);
353   if (l->nlayers)
354     prompt_Printf(arg->prompt, "\n");
355 
356   return 0;
357 }
358