xref: /freebsd/usr.sbin/ppp/mp.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
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: mp.c,v 1.16 1998/09/04 18:25:59 brian Exp $
27  */
28 
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <arpa/inet.h>
34 #include <net/if_dl.h>
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 
38 #include <errno.h>
39 #include <paths.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 #include <termios.h>
45 #include <unistd.h>
46 
47 #include "ua.h"
48 #include "defs.h"
49 #include "command.h"
50 #include "mbuf.h"
51 #include "log.h"
52 #include "timer.h"
53 #include "fsm.h"
54 #include "iplist.h"
55 #include "throughput.h"
56 #include "slcompress.h"
57 #include "lqr.h"
58 #include "hdlc.h"
59 #include "ipcp.h"
60 #include "auth.h"
61 #include "lcp.h"
62 #include "async.h"
63 #include "ccp.h"
64 #include "link.h"
65 #include "descriptor.h"
66 #include "physical.h"
67 #include "chat.h"
68 #include "lcpproto.h"
69 #include "filter.h"
70 #include "mp.h"
71 #include "chap.h"
72 #include "cbcp.h"
73 #include "datalink.h"
74 #include "bundle.h"
75 #include "ip.h"
76 #include "prompt.h"
77 #include "id.h"
78 #include "arp.h"
79 
80 void
81 peerid_Init(struct peerid *peer)
82 {
83   peer->enddisc.class = 0;
84   *peer->enddisc.address = '\0';
85   peer->enddisc.len = 0;
86   *peer->authname = '\0';
87 }
88 
89 int
90 peerid_Equal(const struct peerid *p1, const struct peerid *p2)
91 {
92   return !strcmp(p1->authname, p2->authname) &&
93          p1->enddisc.class == p2->enddisc.class &&
94          p1->enddisc.len == p2->enddisc.len &&
95          !memcmp(p1->enddisc.address, p2->enddisc.address, p1->enddisc.len);
96 }
97 
98 static u_int32_t
99 inc_seq(unsigned is12bit, u_int32_t seq)
100 {
101   seq++;
102   if (is12bit) {
103     if (seq & 0xfffff000)
104       seq = 0;
105   } else if (seq & 0xff000000)
106     seq = 0;
107   return seq;
108 }
109 
110 static int
111 isbefore(unsigned is12bit, u_int32_t seq1, u_int32_t seq2)
112 {
113   u_int32_t max = (is12bit ? 0xfff : 0xffffff) - 0x200;
114 
115   if (seq1 > max) {
116     if (seq2 < 0x200 || seq2 > seq1)
117       return 1;
118   } else if ((seq1 > 0x200 || seq2 <= max) && seq1 < seq2)
119     return 1;
120 
121   return 0;
122 }
123 
124 static int
125 mp_ReadHeader(struct mp *mp, struct mbuf *m, struct mp_header *header)
126 {
127   if (mp->local_is12bit) {
128     u_int16_t val;
129 
130     ua_ntohs(MBUF_CTOP(m), &val);
131     if (val & 0x3000) {
132       log_Printf(LogWARN, "Oops - MP header without required zero bits\n");
133       return 0;
134     }
135     header->begin = val & 0x8000 ? 1 : 0;
136     header->end = val & 0x4000 ? 1 : 0;
137     header->seq = val & 0x0fff;
138     return 2;
139   } else {
140     ua_ntohl(MBUF_CTOP(m), &header->seq);
141     if (header->seq & 0x3f000000) {
142       log_Printf(LogWARN, "Oops - MP header without required zero bits\n");
143       return 0;
144     }
145     header->begin = header->seq & 0x80000000 ? 1 : 0;
146     header->end = header->seq & 0x40000000 ? 1 : 0;
147     header->seq &= 0x00ffffff;
148     return 4;
149   }
150 }
151 
152 static void
153 mp_LayerStart(void *v, struct fsm *fp)
154 {
155   /* The given FSM (ccp) is about to start up ! */
156 }
157 
158 static void
159 mp_LayerUp(void *v, struct fsm *fp)
160 {
161   /* The given fsm (ccp) is now up */
162 }
163 
164 static void
165 mp_LayerDown(void *v, struct fsm *fp)
166 {
167   /* The given FSM (ccp) has been told to come down */
168 }
169 
170 static void
171 mp_LayerFinish(void *v, struct fsm *fp)
172 {
173   /* The given fsm (ccp) is now down */
174   if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE)
175     fsm_Open(fp);		/* CCP goes to ST_STOPPED */
176 }
177 
178 void
179 mp_Init(struct mp *mp, struct bundle *bundle)
180 {
181   mp->peer_is12bit = mp->local_is12bit = 0;
182   mp->peer_mrru = mp->local_mrru = 0;
183 
184   peerid_Init(&mp->peer);
185 
186   mp->out.seq = 0;
187   mp->out.link = 0;
188   mp->seq.min_in = 0;
189   mp->seq.next_in = 0;
190   mp->inbufs = NULL;
191   mp->bundle = bundle;
192 
193   mp->link.type = MP_LINK;
194   mp->link.name = "mp";
195   mp->link.len = sizeof *mp;
196 
197   throughput_init(&mp->link.throughput);
198   memset(mp->link.Queue, '\0', sizeof mp->link.Queue);
199   memset(mp->link.proto_in, '\0', sizeof mp->link.proto_in);
200   memset(mp->link.proto_out, '\0', sizeof mp->link.proto_out);
201 
202   mp->fsmp.LayerStart = mp_LayerStart;
203   mp->fsmp.LayerUp = mp_LayerUp;
204   mp->fsmp.LayerDown = mp_LayerDown;
205   mp->fsmp.LayerFinish = mp_LayerFinish;
206   mp->fsmp.object = mp;
207 
208   mpserver_Init(&mp->server);
209 
210   mp->cfg.mrru = 0;
211   mp->cfg.shortseq = NEG_ENABLED|NEG_ACCEPTED;
212   mp->cfg.enddisc.class = 0;
213   *mp->cfg.enddisc.address = '\0';
214   mp->cfg.enddisc.len = 0;
215 
216   lcp_Init(&mp->link.lcp, mp->bundle, &mp->link, NULL);
217   ccp_Init(&mp->link.ccp, mp->bundle, &mp->link, &mp->fsmp);
218 }
219 
220 int
221 mp_Up(struct mp *mp, struct datalink *dl)
222 {
223   struct lcp *lcp = &dl->physical->link.lcp;
224 
225   if (mp->active) {
226     /* We're adding a link - do a last validation on our parameters */
227     if (!peerid_Equal(&dl->peer, &mp->peer)) {
228       log_Printf(LogPHASE, "%s: Inappropriate peer !\n", dl->name);
229       return MP_FAILED;
230     }
231     if (mp->local_mrru != lcp->want_mrru ||
232         mp->peer_mrru != lcp->his_mrru ||
233         mp->local_is12bit != lcp->want_shortseq ||
234         mp->peer_is12bit != lcp->his_shortseq) {
235       log_Printf(LogPHASE, "%s: Invalid MRRU/SHORTSEQ MP parameters !\n",
236                 dl->name);
237       return MP_FAILED;
238     }
239     return MP_ADDED;
240   } else {
241     /* First link in multilink mode */
242 
243     mp->local_mrru = lcp->want_mrru;
244     mp->peer_mrru = lcp->his_mrru;
245     mp->local_is12bit = lcp->want_shortseq;
246     mp->peer_is12bit = lcp->his_shortseq;
247     mp->peer = dl->peer;
248 
249     throughput_init(&mp->link.throughput);
250     memset(mp->link.Queue, '\0', sizeof mp->link.Queue);
251     memset(mp->link.proto_in, '\0', sizeof mp->link.proto_in);
252     memset(mp->link.proto_out, '\0', sizeof mp->link.proto_out);
253 
254     mp->out.seq = 0;
255     mp->out.link = 0;
256     mp->seq.min_in = 0;
257     mp->seq.next_in = 0;
258 
259     /*
260      * Now we create our server socket.
261      * If it already exists, join it.  Otherwise, create and own it
262      */
263     switch (mpserver_Open(&mp->server, &mp->peer)) {
264     case MPSERVER_CONNECTED:
265       log_Printf(LogPHASE, "mp: Transfer link on %s\n",
266                 mp->server.socket.sun_path);
267       mp->server.send.dl = dl;		/* Defer 'till it's safe to send */
268       return MP_LINKSENT;
269     case MPSERVER_FAILED:
270       return MP_FAILED;
271     case MPSERVER_LISTENING:
272       log_Printf(LogPHASE, "mp: Listening on %s\n", mp->server.socket.sun_path);
273       log_Printf(LogPHASE, "    First link: %s\n", dl->name);
274 
275       /* Re-point our IPCP layer at our MP link */
276       ipcp_SetLink(&mp->bundle->ncp.ipcp, &mp->link);
277 
278       /* Our lcp's already up 'cos of the NULL parent */
279       if (ccp_SetOpenMode(&mp->link.ccp)) {
280         fsm_Up(&mp->link.ccp.fsm);
281         fsm_Open(&mp->link.ccp.fsm);
282       }
283 
284       mp->active = 1;
285       break;
286     }
287   }
288 
289   return MP_UP;
290 }
291 
292 void
293 mp_Down(struct mp *mp)
294 {
295   if (mp->active) {
296     struct mbuf *next;
297 
298     /* Don't want any more of these */
299     mpserver_Close(&mp->server);
300 
301     /* CCP goes down with a bang */
302     fsm2initial(&mp->link.ccp.fsm);
303 
304     /* Received fragments go in the bit-bucket */
305     while (mp->inbufs) {
306       next = mp->inbufs->pnext;
307       mbuf_Free(mp->inbufs);
308       mp->inbufs = next;
309     }
310 
311     peerid_Init(&mp->peer);
312     mp->active = 0;
313   }
314 }
315 
316 void
317 mp_linkInit(struct mp_link *mplink)
318 {
319   mplink->seq = 0;
320   mplink->weight = 1500;
321 }
322 
323 void
324 mp_Input(struct mp *mp, struct mbuf *m, struct physical *p)
325 {
326   struct mp_header mh, h;
327   struct mbuf *q, *last;
328   int32_t seq;
329 
330   /*
331    * When `m' and `p' are NULL, it means our oldest link has gone down.
332    * We want to determine a new min, and process any intermediate stuff
333    * as normal
334    */
335 
336   if (m && mp_ReadHeader(mp, m, &mh) == 0) {
337     mbuf_Free(m);
338     return;
339   }
340 
341   if (p) {
342     seq = p->dl->mp.seq;
343     p->dl->mp.seq = mh.seq;
344   } else
345     seq = mp->seq.min_in;
346 
347   if (mp->seq.min_in == seq) {
348     /*
349      * We've received new data on the link that has our min (oldest) seq.
350      * Figure out which link now has the smallest (oldest) seq.
351      */
352     struct datalink *dl;
353 
354     mp->seq.min_in = (u_int32_t)-1;
355     for (dl = mp->bundle->links; dl; dl = dl->next)
356       if (dl->state == DATALINK_OPEN &&
357           (mp->seq.min_in == -1 ||
358            isbefore(mp->local_is12bit, dl->mp.seq, mp->seq.min_in)))
359         mp->seq.min_in = dl->mp.seq;
360   }
361 
362   /*
363    * Now process as many of our fragments as we can, adding our new
364    * fragment in as we go, and ordering with the oldest at the top of
365    * the queue.
366    */
367 
368   if (!mp->inbufs) {
369     mp->inbufs = m;
370     m = NULL;
371   }
372 
373   last = NULL;
374   seq = mp->seq.next_in;
375   q = mp->inbufs;
376   while (q) {
377     mp_ReadHeader(mp, q, &h);
378     if (m && isbefore(mp->local_is12bit, mh.seq, h.seq)) {
379       /* Our received fragment fits in before this one, so link it in */
380       if (last)
381         last->pnext = m;
382       else
383         mp->inbufs = m;
384       m->pnext = q;
385       q = m;
386       h = mh;
387       m = NULL;
388     }
389 
390     if (h.seq != seq) {
391       /* we're missing something :-( */
392       if (mp->seq.min_in > seq) {
393         /* we're never gonna get it */
394         struct mbuf *next;
395 
396         /* Zap all older fragments */
397         while (mp->inbufs != q) {
398           log_Printf(LogDEBUG, "Drop frag\n");
399           next = mp->inbufs->pnext;
400           mbuf_Free(mp->inbufs);
401           mp->inbufs = next;
402         }
403 
404         /*
405          * Zap everything until the next `end' fragment OR just before
406          * the next `begin' fragment OR 'till seq.min_in - whichever
407          * comes first.
408          */
409         do {
410           mp_ReadHeader(mp, mp->inbufs, &h);
411           if (h.begin) {
412             /* We might be able to process this ! */
413             h.seq--;  /* We're gonna look for fragment with h.seq+1 */
414             break;
415           }
416           next = mp->inbufs->pnext;
417           log_Printf(LogDEBUG, "Drop frag %u\n", h.seq);
418           mbuf_Free(mp->inbufs);
419           mp->inbufs = next;
420         } while (mp->inbufs && (h.seq >= mp->seq.min_in || h.end));
421 
422         /*
423          * Continue processing things from here.
424          * This deals with the possibility that we received a fragment
425          * on the slowest link that invalidates some of our data (because
426          * of the hole at `q'), but where there are subsequent `whole'
427          * packets that have already been received.
428          */
429 
430         mp->seq.next_in = seq = inc_seq(mp->local_is12bit, h.seq);
431         last = NULL;
432         q = mp->inbufs;
433       } else
434         /* we may still receive the missing fragment */
435         break;
436     } else if (h.end) {
437       /* We've got something, reassemble */
438       struct mbuf **frag = &q;
439       int len;
440       u_long first = -1;
441 
442       do {
443         *frag = mp->inbufs;
444         mp->inbufs = mp->inbufs->pnext;
445         len = mp_ReadHeader(mp, *frag, &h);
446         if (first == -1)
447           first = h.seq;
448         (*frag)->offset += len;
449         (*frag)->cnt -= len;
450         (*frag)->pnext = NULL;
451         if (frag == &q && !h.begin) {
452           log_Printf(LogWARN, "Oops - MP frag %lu should have a begin flag\n",
453                     (u_long)h.seq);
454           mbuf_Free(q);
455           q = NULL;
456         } else if (frag != &q && h.begin) {
457           log_Printf(LogWARN, "Oops - MP frag %lu should have an end flag\n",
458                     (u_long)h.seq - 1);
459           /*
460            * Stuff our fragment back at the front of the queue and zap
461            * our half-assembed packet.
462            */
463           (*frag)->pnext = mp->inbufs;
464           mp->inbufs = *frag;
465           *frag = NULL;
466           mbuf_Free(q);
467           q = NULL;
468           frag = &q;
469           h.end = 0;	/* just in case it's a whole packet */
470         } else
471           do
472             frag = &(*frag)->next;
473           while (*frag != NULL);
474       } while (!h.end);
475 
476       if (q) {
477         u_short proto;
478         u_char ch;
479 
480         q = mbuf_Read(q, &ch, 1);
481         proto = ch;
482         if (!(proto & 1)) {
483           q = mbuf_Read(q, &ch, 1);
484           proto <<= 8;
485           proto += ch;
486         }
487         if (log_IsKept(LogDEBUG))
488           log_Printf(LogDEBUG, "MP: Reassembled frags %ld-%lu, length %d\n",
489                     first, (u_long)h.seq, mbuf_Length(q));
490         hdlc_DecodePacket(mp->bundle, proto, q, &mp->link);
491       }
492 
493       mp->seq.next_in = seq = inc_seq(mp->local_is12bit, h.seq);
494       last = NULL;
495       q = mp->inbufs;
496     } else {
497       /* Look for the next fragment */
498       seq = inc_seq(mp->local_is12bit, seq);
499       last = q;
500       q = q->pnext;
501     }
502   }
503 
504   if (m) {
505     /* We still have to find a home for our new fragment */
506     last = NULL;
507     for (q = mp->inbufs; q; last = q, q = q->pnext) {
508       mp_ReadHeader(mp, q, &h);
509       if (isbefore(mp->local_is12bit, mh.seq, h.seq))
510         break;
511     }
512     /* Our received fragment fits in here */
513     if (last)
514       last->pnext = m;
515     else
516       mp->inbufs = m;
517     m->pnext = q;
518   }
519 }
520 
521 static void
522 mp_Output(struct mp *mp, struct link *l, struct mbuf *m, u_int32_t begin,
523           u_int32_t end)
524 {
525   struct mbuf *mo;
526 
527   /* Stuff an MP header on the front of our packet and send it */
528   mo = mbuf_Alloc(4, MB_MP);
529   mo->next = m;
530   if (mp->peer_is12bit) {
531     u_int16_t val;
532 
533     val = (begin << 15) | (end << 14) | (u_int16_t)mp->out.seq;
534     ua_htons(&val, MBUF_CTOP(mo));
535     mo->cnt = 2;
536   } else {
537     u_int32_t val;
538 
539     val = (begin << 31) | (end << 30) | (u_int32_t)mp->out.seq;
540     ua_htonl(&val, MBUF_CTOP(mo));
541     mo->cnt = 4;
542   }
543   if (log_IsKept(LogDEBUG))
544     log_Printf(LogDEBUG, "MP[frag %d]: Send %d bytes on link `%s'\n",
545               mp->out.seq, mbuf_Length(mo), l->name);
546   mp->out.seq = inc_seq(mp->peer_is12bit, mp->out.seq);
547 
548   if (!ccp_Compress(&l->ccp, l, PRI_NORMAL, PROTO_MP, mo))
549     hdlc_Output(l, PRI_NORMAL, PROTO_MP, mo);
550 }
551 
552 int
553 mp_FillQueues(struct bundle *bundle)
554 {
555   struct mp *mp = &bundle->ncp.mp;
556   struct datalink *dl, *fdl;
557   int total, add, len, thislink, nlinks;
558   u_int32_t begin, end;
559   struct mbuf *m, *mo;
560 
561   thislink = nlinks = 0;
562   for (fdl = NULL, dl = bundle->links; dl; dl = dl->next) {
563     /* Include non-open links here as mp->out.link will stay more correct */
564     if (!fdl) {
565       if (thislink == mp->out.link)
566         fdl = dl;
567       else
568         thislink++;
569     }
570     nlinks++;
571   }
572 
573   if (!fdl) {
574     fdl = bundle->links;
575     if (!fdl)
576       return 0;
577     thislink = 0;
578   }
579 
580   total = 0;
581   for (dl = fdl; nlinks > 0; dl = dl->next, nlinks--, thislink++) {
582     if (!dl) {
583       dl = bundle->links;
584       thislink = 0;
585     }
586 
587     if (dl->state != DATALINK_OPEN)
588       continue;
589 
590     if (dl->physical->out)
591       /* this link has suffered a short write.  Let it continue */
592       continue;
593 
594     add = link_QueueLen(&dl->physical->link);
595     total += add;
596     if (add)
597       /* this link has got stuff already queued.  Let it continue */
598       continue;
599 
600     if (!link_QueueLen(&mp->link) && !ip_FlushPacket(&mp->link, bundle))
601       /* Nothing else to send */
602       break;
603 
604     m = link_Dequeue(&mp->link);
605     len = mbuf_Length(m);
606     begin = 1;
607     end = 0;
608 
609     while (!end) {
610       if (dl->state == DATALINK_OPEN) {
611         if (len <= dl->mp.weight + LINK_MINWEIGHT) {
612           /*
613            * XXX: Should we remember how much of our `weight' wasn't sent
614            *      so that we can compensate next time ?
615            */
616           mo = m;
617           end = 1;
618         } else {
619           mo = mbuf_Alloc(dl->mp.weight, MB_MP);
620           mo->cnt = dl->mp.weight;
621           len -= mo->cnt;
622           m = mbuf_Read(m, MBUF_CTOP(mo), mo->cnt);
623         }
624         mp_Output(mp, &dl->physical->link, mo, begin, end);
625         begin = 0;
626       }
627 
628       if (!end) {
629         nlinks--;
630         dl = dl->next;
631         if (!dl) {
632           dl = bundle->links;
633           thislink = 0;
634         } else
635           thislink++;
636       }
637     }
638   }
639   mp->out.link = thislink;		/* Start here next time */
640 
641   return total;
642 }
643 
644 int
645 mp_SetDatalinkWeight(struct cmdargs const *arg)
646 {
647   int val;
648 
649   if (arg->argc != arg->argn+1)
650     return -1;
651 
652   val = atoi(arg->argv[arg->argn]);
653   if (val < LINK_MINWEIGHT) {
654     log_Printf(LogWARN, "Link weights must not be less than %d\n",
655               LINK_MINWEIGHT);
656     return 1;
657   }
658   arg->cx->mp.weight = val;
659   return 0;
660 }
661 
662 int
663 mp_ShowStatus(struct cmdargs const *arg)
664 {
665   struct mp *mp = &arg->bundle->ncp.mp;
666 
667   prompt_Printf(arg->prompt, "Multilink is %sactive\n", mp->active ? "" : "in");
668   if (mp->active) {
669     struct mbuf *m;
670     int bufs = 0;
671 
672     prompt_Printf(arg->prompt, "Socket:         %s\n",
673                   mp->server.socket.sun_path);
674     for (m = mp->inbufs; m; m = m->pnext)
675       bufs++;
676     prompt_Printf(arg->prompt, "Pending frags:  %d\n", bufs);
677   }
678 
679   prompt_Printf(arg->prompt, "\nMy Side:\n");
680   if (mp->active) {
681     prompt_Printf(arg->prompt, " MRRU:          %u\n", mp->local_mrru);
682     prompt_Printf(arg->prompt, " Short Seq:     %s\n",
683                   mp->local_is12bit ? "on" : "off");
684   }
685   prompt_Printf(arg->prompt, " Discriminator: %s\n",
686                 mp_Enddisc(mp->cfg.enddisc.class, mp->cfg.enddisc.address,
687                            mp->cfg.enddisc.len));
688 
689   prompt_Printf(arg->prompt, "\nHis Side:\n");
690   if (mp->active) {
691     prompt_Printf(arg->prompt, " Auth Name:     %s\n", mp->peer.authname);
692     prompt_Printf(arg->prompt, " Next SEQ:      %u\n", mp->out.seq);
693     prompt_Printf(arg->prompt, " MRRU:          %u\n", mp->peer_mrru);
694     prompt_Printf(arg->prompt, " Short Seq:     %s\n",
695                   mp->peer_is12bit ? "on" : "off");
696   }
697   prompt_Printf(arg->prompt,   " Discriminator: %s\n",
698                 mp_Enddisc(mp->peer.enddisc.class, mp->peer.enddisc.address,
699                            mp->peer.enddisc.len));
700 
701   prompt_Printf(arg->prompt, "\nDefaults:\n");
702 
703   prompt_Printf(arg->prompt, " MRRU:          ");
704   if (mp->cfg.mrru)
705     prompt_Printf(arg->prompt, "%d (multilink enabled)\n", mp->cfg.mrru);
706   else
707     prompt_Printf(arg->prompt, "disabled\n");
708   prompt_Printf(arg->prompt, " Short Seq:     %s\n",
709                   command_ShowNegval(mp->cfg.shortseq));
710 
711   return 0;
712 }
713 
714 const char *
715 mp_Enddisc(u_char c, const char *address, int len)
716 {
717   static char result[100];	/* Used immediately after it's returned */
718   int f, header;
719 
720   switch (c) {
721     case ENDDISC_NULL:
722       sprintf(result, "Null Class");
723       break;
724 
725     case ENDDISC_LOCAL:
726       snprintf(result, sizeof result, "Local Addr: %.*s", len, address);
727       break;
728 
729     case ENDDISC_IP:
730       if (len == 4)
731         snprintf(result, sizeof result, "IP %s",
732                  inet_ntoa(*(const struct in_addr *)address));
733       else
734         sprintf(result, "IP[%d] ???", len);
735       break;
736 
737     case ENDDISC_MAC:
738       if (len == 6) {
739         const u_char *m = (const u_char *)address;
740         snprintf(result, sizeof result, "MAC %02x:%02x:%02x:%02x:%02x:%02x",
741                  m[0], m[1], m[2], m[3], m[4], m[5]);
742       } else
743         sprintf(result, "MAC[%d] ???", len);
744       break;
745 
746     case ENDDISC_MAGIC:
747       sprintf(result, "Magic: 0x");
748       header = strlen(result);
749       if (len > sizeof result - header - 1)
750         len = sizeof result - header - 1;
751       for (f = 0; f < len; f++)
752         sprintf(result + header + 2 * f, "%02x", address[f]);
753       break;
754 
755     case ENDDISC_PSN:
756       snprintf(result, sizeof result, "PSN: %.*s", len, address);
757       break;
758 
759      default:
760       sprintf(result, "%d: ", (int)c);
761       header = strlen(result);
762       if (len > sizeof result - header - 1)
763         len = sizeof result - header - 1;
764       for (f = 0; f < len; f++)
765         sprintf(result + header + 2 * f, "%02x", address[f]);
766       break;
767   }
768   return result;
769 }
770 
771 int
772 mp_SetEnddisc(struct cmdargs const *arg)
773 {
774   struct mp *mp = &arg->bundle->ncp.mp;
775   struct in_addr addr;
776 
777   switch (bundle_Phase(arg->bundle)) {
778     case PHASE_DEAD:
779       break;
780     case PHASE_ESTABLISH:
781       /* Make sure none of our links are DATALINK_LCP or greater */
782       if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
783         log_Printf(LogWARN, "enddisc: Only changable before"
784                    " LCP negotiations\n");
785         return 1;
786       }
787       break;
788     default:
789       log_Printf(LogWARN, "enddisc: Only changable at phase DEAD/ESTABLISH\n");
790       return 1;
791   }
792 
793   if (arg->argc == arg->argn) {
794     mp->cfg.enddisc.class = 0;
795     *mp->cfg.enddisc.address = '\0';
796     mp->cfg.enddisc.len = 0;
797   } else if (arg->argc > arg->argn) {
798     if (!strcasecmp(arg->argv[arg->argn], "label")) {
799       mp->cfg.enddisc.class = ENDDISC_LOCAL;
800       strcpy(mp->cfg.enddisc.address, arg->bundle->cfg.label);
801       mp->cfg.enddisc.len = strlen(mp->cfg.enddisc.address);
802     } else if (!strcasecmp(arg->argv[arg->argn], "ip")) {
803       if (arg->bundle->ncp.ipcp.my_ip.s_addr == INADDR_ANY)
804         addr = arg->bundle->ncp.ipcp.cfg.my_range.ipaddr;
805       else
806         addr = arg->bundle->ncp.ipcp.my_ip;
807       memcpy(mp->cfg.enddisc.address, &addr.s_addr, sizeof addr.s_addr);
808       mp->cfg.enddisc.class = ENDDISC_IP;
809       mp->cfg.enddisc.len = sizeof arg->bundle->ncp.ipcp.my_ip.s_addr;
810     } else if (!strcasecmp(arg->argv[arg->argn], "mac")) {
811       struct sockaddr_dl hwaddr;
812       int s;
813 
814       if (arg->bundle->ncp.ipcp.my_ip.s_addr == INADDR_ANY)
815         addr = arg->bundle->ncp.ipcp.cfg.my_range.ipaddr;
816       else
817         addr = arg->bundle->ncp.ipcp.my_ip;
818 
819       s = ID0socket(AF_INET, SOCK_DGRAM, 0);
820       if (s < 0) {
821         log_Printf(LogERROR, "set enddisc: socket(): %s\n", strerror(errno));
822         return 2;
823       }
824       if (get_ether_addr(s, addr, &hwaddr)) {
825         mp->cfg.enddisc.class = ENDDISC_MAC;
826         memcpy(mp->cfg.enddisc.address, hwaddr.sdl_data + hwaddr.sdl_nlen,
827                hwaddr.sdl_alen);
828         mp->cfg.enddisc.len = hwaddr.sdl_alen;
829       } else {
830         log_Printf(LogWARN, "set enddisc: Can't locate MAC address for %s\n",
831                   inet_ntoa(addr));
832         close(s);
833         return 4;
834       }
835       close(s);
836     } else if (!strcasecmp(arg->argv[arg->argn], "magic")) {
837       int f;
838 
839       randinit();
840       for (f = 0; f < 20; f += sizeof(long))
841         *(long *)(mp->cfg.enddisc.address + f) = random();
842       mp->cfg.enddisc.class = ENDDISC_MAGIC;
843       mp->cfg.enddisc.len = 20;
844     } else if (!strcasecmp(arg->argv[arg->argn], "psn")) {
845       if (arg->argc > arg->argn+1) {
846         mp->cfg.enddisc.class = ENDDISC_PSN;
847         strcpy(mp->cfg.enddisc.address, arg->argv[arg->argn+1]);
848         mp->cfg.enddisc.len = strlen(mp->cfg.enddisc.address);
849       } else {
850         log_Printf(LogWARN, "PSN endpoint requires additional data\n");
851         return 5;
852       }
853     } else {
854       log_Printf(LogWARN, "%s: Unrecognised endpoint type\n",
855                 arg->argv[arg->argn]);
856       return 6;
857     }
858   }
859 
860   return 0;
861 }
862 
863 static int
864 mpserver_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e,
865                    int *n)
866 {
867   struct mpserver *s = descriptor2mpserver(d);
868   int result;
869 
870   result = 0;
871   if (s->send.dl != NULL) {
872     /* We've connect()ed */
873     if (!link_QueueLen(&s->send.dl->physical->link) &&
874         !s->send.dl->physical->out) {
875       /* Only send if we've transmitted all our data (i.e. the ConfigAck) */
876       result -= datalink_RemoveFromSet(s->send.dl, r, w, e);
877       bundle_SendDatalink(s->send.dl, s->fd, &s->socket);
878       s->send.dl = NULL;
879       s->fd = -1;
880     } else
881       /* Never read from a datalink that's on death row ! */
882       result -= datalink_RemoveFromSet(s->send.dl, r, NULL, NULL);
883   } else if (r && s->fd >= 0) {
884     if (*n < s->fd + 1)
885       *n = s->fd + 1;
886     FD_SET(s->fd, r);
887     log_Printf(LogTIMER, "mp: fdset(r) %d\n", s->fd);
888     result++;
889   }
890   return result;
891 }
892 
893 static int
894 mpserver_IsSet(struct descriptor *d, const fd_set *fdset)
895 {
896   struct mpserver *s = descriptor2mpserver(d);
897   return s->fd >= 0 && FD_ISSET(s->fd, fdset);
898 }
899 
900 static void
901 mpserver_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
902 {
903   struct mpserver *s = descriptor2mpserver(d);
904   struct sockaddr in;
905   int fd, size;
906 
907   size = sizeof in;
908   fd = accept(s->fd, &in, &size);
909   if (fd < 0) {
910     log_Printf(LogERROR, "mpserver_Read: accept(): %s\n", strerror(errno));
911     return;
912   }
913 
914   if (in.sa_family == AF_LOCAL)
915     bundle_ReceiveDatalink(bundle, fd, (struct sockaddr_un *)&in);
916   else
917     close(fd);
918 }
919 
920 static int
921 mpserver_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
922 {
923   /* We never want to write here ! */
924   log_Printf(LogALERT, "mpserver_Write: Internal error: Bad call !\n");
925   return 0;
926 }
927 
928 void
929 mpserver_Init(struct mpserver *s)
930 {
931   s->desc.type = MPSERVER_DESCRIPTOR;
932   s->desc.UpdateSet = mpserver_UpdateSet;
933   s->desc.IsSet = mpserver_IsSet;
934   s->desc.Read = mpserver_Read;
935   s->desc.Write = mpserver_Write;
936   s->send.dl = NULL;
937   s->fd = -1;
938   memset(&s->socket, '\0', sizeof s->socket);
939 }
940 
941 int
942 mpserver_Open(struct mpserver *s, struct peerid *peer)
943 {
944   int f, l;
945   mode_t mask;
946 
947   if (s->fd != -1) {
948     log_Printf(LogALERT, "Internal error !  mpserver already open\n");
949     mpserver_Close(s);
950   }
951 
952   l = snprintf(s->socket.sun_path, sizeof s->socket.sun_path, "%sppp-%s-%02x-",
953                _PATH_VARRUN, peer->authname, peer->enddisc.class);
954 
955   for (f = 0; f < peer->enddisc.len && l < sizeof s->socket.sun_path - 2; f++) {
956     snprintf(s->socket.sun_path + l, sizeof s->socket.sun_path - l,
957              "%02x", *(u_char *)(peer->enddisc.address+f));
958     l += 2;
959   }
960 
961   s->socket.sun_family = AF_LOCAL;
962   s->socket.sun_len = sizeof s->socket;
963   s->fd = ID0socket(PF_LOCAL, SOCK_STREAM, 0);
964   if (s->fd < 0) {
965     log_Printf(LogERROR, "mpserver: socket: %s\n", strerror(errno));
966     return MPSERVER_FAILED;
967   }
968 
969   setsockopt(s->fd, SOL_SOCKET, SO_REUSEADDR, (struct sockaddr *)&s->socket,
970              sizeof s->socket);
971   mask = umask(0177);
972   if (ID0bind_un(s->fd, &s->socket) < 0) {
973     if (errno != EADDRINUSE) {
974       log_Printf(LogPHASE, "mpserver: can't create bundle socket %s (%s)\n",
975                 s->socket.sun_path, strerror(errno));
976       umask(mask);
977       close(s->fd);
978       s->fd = -1;
979       return MPSERVER_FAILED;
980     }
981     umask(mask);
982     if (ID0connect_un(s->fd, &s->socket) < 0) {
983       log_Printf(LogPHASE, "mpserver: can't connect to bundle socket %s (%s)\n",
984                 s->socket.sun_path, strerror(errno));
985       if (errno == ECONNREFUSED)
986         log_Printf(LogPHASE, "          Has the previous server died badly ?\n");
987       close(s->fd);
988       s->fd = -1;
989       return MPSERVER_FAILED;
990     }
991 
992     /* Donate our link to the other guy */
993     return MPSERVER_CONNECTED;
994   }
995 
996   /* Listen for other ppp invocations that want to donate links */
997   if (listen(s->fd, 5) != 0) {
998     log_Printf(LogERROR, "mpserver: Unable to listen to socket"
999               " - BUNDLE overload?\n");
1000     mpserver_Close(s);
1001   }
1002 
1003   return MPSERVER_LISTENING;
1004 }
1005 
1006 void
1007 mpserver_Close(struct mpserver *s)
1008 {
1009   if (s->send.dl != NULL) {
1010     bundle_SendDatalink(s->send.dl, s->fd, &s->socket);
1011     s->send.dl = NULL;
1012     s->fd = -1;
1013   } else if (s->fd >= 0) {
1014     close(s->fd);
1015     if (ID0unlink(s->socket.sun_path) == -1)
1016       log_Printf(LogERROR, "%s: Failed to remove: %s\n", s->socket.sun_path,
1017                 strerror(errno));
1018     memset(&s->socket, '\0', sizeof s->socket);
1019     s->fd = -1;
1020   }
1021 }
1022 
1023 void
1024 mp_LinkLost(struct mp *mp, struct datalink *dl)
1025 {
1026   if (mp->seq.min_in == dl->mp.seq)
1027     /* We've lost the link that's holding everything up ! */
1028     mp_Input(mp, NULL, NULL);
1029 }
1030 
1031 void
1032 mp_DeleteQueue(struct mp *mp)
1033 {
1034   link_DeleteQueue(&mp->link);
1035 }
1036