2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/param.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>
61 #include "throughput.h"
62 #include "slcompress.h"
72 #include "descriptor.h"
92 peerid_Init(struct peerid
*peer
)
94 peer
->enddisc
.class = 0;
95 *peer
->enddisc
.address
= '\0';
96 peer
->enddisc
.len
= 0;
97 *peer
->authname
= '\0';
101 peerid_Equal(const struct peerid
*p1
, const struct peerid
*p2
)
103 return !strcmp(p1
->authname
, p2
->authname
) &&
104 p1
->enddisc
.class == p2
->enddisc
.class &&
105 p1
->enddisc
.len
== p2
->enddisc
.len
&&
106 !memcmp(p1
->enddisc
.address
, p2
->enddisc
.address
, p1
->enddisc
.len
);
110 inc_seq(unsigned is12bit
, u_int32_t seq
)
114 if (seq
& 0xfffff000)
116 } else if (seq
& 0xff000000)
122 isbefore(unsigned is12bit
, u_int32_t seq1
, u_int32_t seq2
)
124 u_int32_t max
= (is12bit
? 0xfff : 0xffffff) - 0x200;
127 if (seq2
< 0x200 || seq2
> seq1
)
129 } else if ((seq1
> 0x200 || seq2
<= max
) && seq1
< seq2
)
136 mp_ReadHeader(struct mp
*mp
, struct mbuf
*m
, struct mp_header
*header
)
138 if (mp
->local_is12bit
) {
141 ua_ntohs(MBUF_CTOP(m
), &val
);
143 log_Printf(LogWARN
, "Oops - MP header without required zero bits\n");
146 header
->begin
= val
& 0x8000 ? 1 : 0;
147 header
->end
= val
& 0x4000 ? 1 : 0;
148 header
->seq
= val
& 0x0fff;
151 ua_ntohl(MBUF_CTOP(m
), &header
->seq
);
152 if (header
->seq
& 0x3f000000) {
153 log_Printf(LogWARN
, "Oops - MP header without required zero bits\n");
156 header
->begin
= header
->seq
& 0x80000000 ? 1 : 0;
157 header
->end
= header
->seq
& 0x40000000 ? 1 : 0;
158 header
->seq
&= 0x00ffffff;
164 mp_LayerStart(void *v __unused
, struct fsm
*fp __unused
)
166 /* The given FSM (ccp) is about to start up ! */
170 mp_LayerUp(void *v __unused
, struct fsm
*fp
)
172 /* The given fsm (ccp) is now up */
174 bundle_CalculateBandwidth(fp
->bundle
); /* Against ccp_MTUOverhead */
178 mp_LayerDown(void *v __unused
, struct fsm
*fp __unused
)
180 /* The given FSM (ccp) has been told to come down */
184 mp_LayerFinish(void *v __unused
, struct fsm
*fp
)
186 /* The given fsm (ccp) is now down */
187 if (fp
->state
== ST_CLOSED
&& fp
->open_mode
== OPEN_PASSIVE
)
188 fsm_Open(fp
); /* CCP goes to ST_STOPPED */
194 struct mp
*mp
= (struct mp
*)v
;
197 percent
= MAX(mp
->link
.stats
.total
.in
.OctetsPerSecond
,
198 mp
->link
.stats
.total
.out
.OctetsPerSecond
) * 800 /
199 mp
->bundle
->bandwidth
;
200 if (percent
>= mp
->cfg
.autoload
.max
) {
201 log_Printf(LogDEBUG
, "%d%% saturation - bring a link up ?\n", percent
);
202 bundle_AutoAdjust(mp
->bundle
, percent
, AUTO_UP
);
203 } else if (percent
<= mp
->cfg
.autoload
.min
) {
204 log_Printf(LogDEBUG
, "%d%% saturation - bring a link down ?\n", percent
);
205 bundle_AutoAdjust(mp
->bundle
, percent
, AUTO_DOWN
);
210 mp_StopAutoloadTimer(struct mp
*mp
)
212 throughput_stop(&mp
->link
.stats
.total
);
216 mp_CheckAutoloadTimer(struct mp
*mp
)
218 if (mp
->link
.stats
.total
.SamplePeriod
!= mp
->cfg
.autoload
.period
) {
219 throughput_destroy(&mp
->link
.stats
.total
);
220 throughput_init(&mp
->link
.stats
.total
, mp
->cfg
.autoload
.period
);
221 throughput_callback(&mp
->link
.stats
.total
, mp_UpDown
, mp
);
224 if (bundle_WantAutoloadTimer(mp
->bundle
))
225 throughput_start(&mp
->link
.stats
.total
, "MP throughput", 1);
227 mp_StopAutoloadTimer(mp
);
231 mp_RestartAutoloadTimer(struct mp
*mp
)
233 if (mp
->link
.stats
.total
.SamplePeriod
!= mp
->cfg
.autoload
.period
)
234 mp_CheckAutoloadTimer(mp
);
236 throughput_clear(&mp
->link
.stats
.total
, THROUGHPUT_OVERALL
, NULL
);
240 mp_Init(struct mp
*mp
, struct bundle
*bundle
)
242 mp
->peer_is12bit
= mp
->local_is12bit
= 0;
243 mp
->peer_mrru
= mp
->local_mrru
= 0;
245 peerid_Init(&mp
->peer
);
249 mp
->out
.af
= AF_INET
;
255 mp
->link
.type
= LOGICAL_LINK
;
256 mp
->link
.name
= "mp";
257 mp
->link
.len
= sizeof *mp
;
259 mp
->cfg
.autoload
.period
= SAMPLE_PERIOD
;
260 mp
->cfg
.autoload
.min
= mp
->cfg
.autoload
.max
= 0;
261 throughput_init(&mp
->link
.stats
.total
, mp
->cfg
.autoload
.period
);
262 throughput_callback(&mp
->link
.stats
.total
, mp_UpDown
, mp
);
263 mp
->link
.stats
.parent
= NULL
;
264 mp
->link
.stats
.gather
= 0; /* Let the physical links gather stats */
265 memset(mp
->link
.Queue
, '\0', sizeof mp
->link
.Queue
);
266 memset(mp
->link
.proto_in
, '\0', sizeof mp
->link
.proto_in
);
267 memset(mp
->link
.proto_out
, '\0', sizeof mp
->link
.proto_out
);
269 mp
->fsmp
.LayerStart
= mp_LayerStart
;
270 mp
->fsmp
.LayerUp
= mp_LayerUp
;
271 mp
->fsmp
.LayerDown
= mp_LayerDown
;
272 mp
->fsmp
.LayerFinish
= mp_LayerFinish
;
273 mp
->fsmp
.object
= mp
;
275 mpserver_Init(&mp
->server
);
278 mp
->cfg
.shortseq
= NEG_ENABLED
|NEG_ACCEPTED
;
279 mp
->cfg
.negenddisc
= NEG_ENABLED
|NEG_ACCEPTED
;
280 mp
->cfg
.enddisc
.class = 0;
281 *mp
->cfg
.enddisc
.address
= '\0';
282 mp
->cfg
.enddisc
.len
= 0;
284 lcp_Init(&mp
->link
.lcp
, mp
->bundle
, &mp
->link
, NULL
);
285 ccp_Init(&mp
->link
.ccp
, mp
->bundle
, &mp
->link
, &mp
->fsmp
);
287 link_EmptyStack(&mp
->link
);
288 link_Stack(&mp
->link
, &protolayer
);
289 link_Stack(&mp
->link
, &ccplayer
);
290 link_Stack(&mp
->link
, &vjlayer
);
292 link_Stack(&mp
->link
, &natlayer
);
297 mp_Up(struct mp
*mp
, struct datalink
*dl
)
299 struct lcp
*lcp
= &dl
->physical
->link
.lcp
;
302 /* We're adding a link - do a last validation on our parameters */
303 if (!peerid_Equal(&dl
->peer
, &mp
->peer
)) {
304 log_Printf(LogPHASE
, "%s: Inappropriate peer !\n", dl
->name
);
305 log_Printf(LogPHASE
, " Attached to peer %s/%s\n", mp
->peer
.authname
,
306 mp_Enddisc(mp
->peer
.enddisc
.class, mp
->peer
.enddisc
.address
,
307 mp
->peer
.enddisc
.len
));
308 log_Printf(LogPHASE
, " New link is peer %s/%s\n", dl
->peer
.authname
,
309 mp_Enddisc(dl
->peer
.enddisc
.class, dl
->peer
.enddisc
.address
,
310 dl
->peer
.enddisc
.len
));
313 if (mp
->local_mrru
!= lcp
->want_mrru
||
314 mp
->peer_mrru
!= lcp
->his_mrru
||
315 mp
->local_is12bit
!= lcp
->want_shortseq
||
316 mp
->peer_is12bit
!= lcp
->his_shortseq
) {
317 log_Printf(LogPHASE
, "%s: Invalid MRRU/SHORTSEQ MP parameters !\n",
323 /* First link in multilink mode */
325 mp
->local_mrru
= lcp
->want_mrru
;
326 mp
->peer_mrru
= lcp
->his_mrru
;
327 mp
->local_is12bit
= lcp
->want_shortseq
;
328 mp
->peer_is12bit
= lcp
->his_shortseq
;
331 throughput_destroy(&mp
->link
.stats
.total
);
332 throughput_init(&mp
->link
.stats
.total
, mp
->cfg
.autoload
.period
);
333 throughput_callback(&mp
->link
.stats
.total
, mp_UpDown
, mp
);
334 memset(mp
->link
.Queue
, '\0', sizeof mp
->link
.Queue
);
335 memset(mp
->link
.proto_in
, '\0', sizeof mp
->link
.proto_in
);
336 memset(mp
->link
.proto_out
, '\0', sizeof mp
->link
.proto_out
);
338 /* Tell the link who it belongs to */
339 dl
->physical
->link
.stats
.parent
= &mp
->link
.stats
.total
;
343 mp
->out
.af
= AF_INET
;
348 * Now we create our server socket.
349 * If it already exists, join it. Otherwise, create and own it
351 switch (mpserver_Open(&mp
->server
, &mp
->peer
)) {
352 case MPSERVER_CONNECTED
:
353 log_Printf(LogPHASE
, "mp: Transfer link on %s\n",
354 mp
->server
.socket
.sun_path
);
355 mp
->server
.send
.dl
= dl
; /* Defer 'till it's safe to send */
357 case MPSERVER_FAILED
:
359 case MPSERVER_LISTENING
:
360 log_Printf(LogPHASE
, "mp: Listening on %s\n", mp
->server
.socket
.sun_path
);
361 log_Printf(LogPHASE
, " First link: %s\n", dl
->name
);
363 /* Re-point our NCP layers at our MP link */
364 ncp_SetLink(&mp
->bundle
->ncp
, &mp
->link
);
366 /* Our lcp's already up 'cos of the NULL parent */
367 if (ccp_SetOpenMode(&mp
->link
.ccp
)) {
368 fsm_Up(&mp
->link
.ccp
.fsm
);
369 fsm_Open(&mp
->link
.ccp
.fsm
);
381 mp_Down(struct mp
*mp
)
387 mp_StopAutoloadTimer(mp
);
389 /* Don't want any more of these */
390 mpserver_Close(&mp
->server
);
392 /* CCP goes down with a bang */
393 fsm2initial(&mp
->link
.ccp
.fsm
);
395 /* Received fragments go in the bit-bucket */
397 next
= mp
->inbufs
->m_nextpkt
;
402 peerid_Init(&mp
->peer
);
408 mp_linkInit(struct mp_link
*mplink
)
411 mplink
->bandwidth
= 0;
415 mp_Assemble(struct mp
*mp
, struct mbuf
*m
, struct physical
*p
)
417 struct mp_header mh
, h
;
418 struct mbuf
*q
, *last
;
422 * When `m' and `p' are NULL, it means our oldest link has gone down.
423 * We want to determine a new min, and process any intermediate stuff
427 if (m
&& mp_ReadHeader(mp
, m
, &mh
) == 0) {
434 p
->dl
->mp
.seq
= mh
.seq
;
436 seq
= mp
->seq
.min_in
;
438 if (mp
->seq
.min_in
== seq
) {
440 * We've received new data on the link that has our min (oldest) seq.
441 * Figure out which link now has the smallest (oldest) seq.
445 mp
->seq
.min_in
= (u_int32_t
)-1;
446 for (dl
= mp
->bundle
->links
; dl
; dl
= dl
->next
)
447 if (dl
->state
== DATALINK_OPEN
&&
448 (mp
->seq
.min_in
== (u_int32_t
)-1 ||
449 isbefore(mp
->local_is12bit
, dl
->mp
.seq
, mp
->seq
.min_in
)))
450 mp
->seq
.min_in
= dl
->mp
.seq
;
454 * Now process as many of our fragments as we can, adding our new
455 * fragment in as we go, and ordering with the oldest at the top of
460 seq
= mp
->seq
.next_in
;
472 mp_ReadHeader(mp
, q
, &h
);
474 if (m
&& isbefore(mp
->local_is12bit
, mh
.seq
, h
.seq
)) {
475 /* Our received fragment fits in before this one, so link it in */
488 /* we're missing something :-( */
489 if (isbefore(mp
->local_is12bit
, seq
, mp
->seq
.min_in
)) {
490 /* we're never gonna get it */
493 /* Zap all older fragments */
494 while (mp
->inbufs
!= q
) {
495 log_Printf(LogDEBUG
, "Drop frag\n");
496 next
= mp
->inbufs
->m_nextpkt
;
502 * Zap everything until the next `end' fragment OR just before
503 * the next `begin' fragment OR 'till seq.min_in - whichever
507 mp_ReadHeader(mp
, mp
->inbufs
, &h
);
509 /* We might be able to process this ! */
510 h
.seq
--; /* We're gonna look for fragment with h.seq+1 */
513 next
= mp
->inbufs
->m_nextpkt
;
514 log_Printf(LogDEBUG
, "Drop frag %u\n", h
.seq
);
517 } while (mp
->inbufs
&& (isbefore(mp
->local_is12bit
, mp
->seq
.min_in
,
521 * Continue processing things from here.
522 * This deals with the possibility that we received a fragment
523 * on the slowest link that invalidates some of our data (because
524 * of the hole at `q'), but where there are subsequent `whole'
525 * packets that have already been received.
528 mp
->seq
.next_in
= seq
= inc_seq(mp
->local_is12bit
, h
.seq
);
532 /* we may still receive the missing fragment */
535 /* We've got something, reassemble */
536 struct mbuf
**frag
= &q
;
538 long long first
= -1;
542 mp
->inbufs
= mp
->inbufs
->m_nextpkt
;
543 len
= mp_ReadHeader(mp
, *frag
, &h
);
546 if (frag
== &q
&& !h
.begin
) {
547 log_Printf(LogWARN
, "Oops - MP frag %lu should have a begin flag\n",
551 } else if (frag
!= &q
&& h
.begin
) {
552 log_Printf(LogWARN
, "Oops - MP frag %lu should have an end flag\n",
555 * Stuff our fragment back at the front of the queue and zap
556 * our half-assembled packet.
558 (*frag
)->m_nextpkt
= mp
->inbufs
;
564 h
.end
= 0; /* just in case it's a whole packet */
566 (*frag
)->m_offset
+= len
;
567 (*frag
)->m_len
-= len
;
568 (*frag
)->m_nextpkt
= NULL
;
570 frag
= &(*frag
)->m_next
;
571 while (*frag
!= NULL
);
577 log_Printf(LogDEBUG
, "MP: Reassembled frags %lu-%lu, length %zd\n",
578 (u_long
)first
, (u_long
)h
.seq
, m_length(q
));
579 link_PullPacket(&mp
->link
, MBUF_CTOP(q
), q
->m_len
, mp
->bundle
);
583 mp
->seq
.next_in
= seq
= inc_seq(mp
->local_is12bit
, h
.seq
);
587 /* Look for the next fragment */
588 seq
= inc_seq(mp
->local_is12bit
, seq
);
595 /* We still have to find a home for our new fragment */
597 for (q
= mp
->inbufs
; q
; last
= q
, q
= q
->m_nextpkt
) {
598 mp_ReadHeader(mp
, q
, &h
);
599 if (isbefore(mp
->local_is12bit
, mh
.seq
, h
.seq
))
602 /* Our received fragment fits in here */
612 mp_Input(struct bundle
*bundle
, struct link
*l
, struct mbuf
*bp
)
614 struct physical
*p
= link2physical(l
);
616 if (!bundle
->ncp
.mp
.active
)
617 /* Let someone else deal with it ! */
621 log_Printf(LogWARN
, "DecodePacket: Can't do MP inside MP !\n");
624 m_settype(bp
, MB_MPIN
);
625 mp_Assemble(&bundle
->ncp
.mp
, bp
, p
);
632 mp_Output(struct mp
*mp
, struct bundle
*bundle
, struct link
*l
,
633 struct mbuf
*m
, u_int32_t begin
, u_int32_t end
)
637 /* Stuff an MP header on the front of our packet and send it */
639 if (mp
->peer_is12bit
) {
642 val
= (begin
<< 15) | (end
<< 14) | (u_int16_t
)mp
->out
.seq
;
643 ua_htons(&val
, prepend
);
644 m
= m_prepend(m
, prepend
, 2, 0);
648 val
= (begin
<< 31) | (end
<< 30) | (u_int32_t
)mp
->out
.seq
;
649 ua_htonl(&val
, prepend
);
650 m
= m_prepend(m
, prepend
, 4, 0);
652 if (log_IsKept(LogDEBUG
))
653 log_Printf(LogDEBUG
, "MP[frag %d]: Send %zd bytes on link `%s'\n",
654 mp
->out
.seq
, m_length(m
), l
->name
);
655 mp
->out
.seq
= inc_seq(mp
->peer_is12bit
, mp
->out
.seq
);
657 if (l
->ccp
.fsm
.state
!= ST_OPENED
&& ccp_Required(&l
->ccp
)) {
658 log_Printf(LogPHASE
, "%s: Not transmitting... waiting for CCP\n", l
->name
);
662 link_PushPacket(l
, m
, bundle
, LINK_QUEUES(l
) - 1, PROTO_MP
);
666 mp_FillPhysicalQueues(struct bundle
*bundle
)
668 struct mp
*mp
= &bundle
->ncp
.mp
;
669 struct datalink
*dl
, *fdl
;
670 size_t total
, add
, len
;
671 int thislink
, nlinks
, nopenlinks
, sendasip
;
672 u_int32_t begin
, end
;
674 struct link
*bestlink
;
676 thislink
= nlinks
= nopenlinks
= 0;
677 for (fdl
= NULL
, dl
= bundle
->links
; dl
; dl
= dl
->next
) {
678 /* Include non-open links here as mp->out.link will stay more correct */
680 if (thislink
== mp
->out
.link
)
686 if (dl
->state
== DATALINK_OPEN
)
698 for (dl
= fdl
; nlinks
> 0; dl
= dl
->next
, nlinks
--, thislink
++) {
704 if (dl
->state
!= DATALINK_OPEN
)
707 if (dl
->physical
->out
)
708 /* this link has suffered a short write. Let it continue */
711 add
= link_QueueLen(&dl
->physical
->link
);
713 /* this link has got stuff already queued. Let it continue */
718 if (!mp_QueueLen(mp
)) {
722 * If there's only a single open link in our bundle and we haven't got
723 * MP level link compression, queue outbound traffic directly via that
724 * link's protocol stack rather than using the MP link. This results
725 * in the outbound traffic going out as PROTO_IP or PROTO_IPV6 rather
730 sendasip
= nopenlinks
< 2;
732 if (dl
->physical
->link
.lcp
.his_mru
< mp
->peer_mrru
) {
734 * Actually, forget it. This test is done against the MRRU rather
735 * than the packet size so that we don't end up sending some data
736 * in MP fragments and some data in PROTO_IP packets. That's just
737 * too likely to upset some ppp implementations.
744 bestlink
= sendasip
? &dl
->physical
->link
: &mp
->link
;
745 if (!ncp_PushPacket(&bundle
->ncp
, &mp
->out
.af
, bestlink
))
746 break; /* Nothing else to send */
749 log_Printf(LogDEBUG
, "Don't send data as PROTO_IP, MRU < MRRU\n");
751 log_Printf(LogDEBUG
, "Sending data as PROTO_IP, not PROTO_MP\n");
754 add
= link_QueueLen(&dl
->physical
->link
);
756 /* this link has got stuff already queued. Let it continue */
763 m
= link_Dequeue(&mp
->link
);
770 if (dl
->state
== DATALINK_OPEN
) {
771 /* Write at most his_mru bytes to the physical link */
772 if (len
<= dl
->physical
->link
.lcp
.his_mru
) {
775 m_settype(mo
, MB_MPOUT
);
777 /* It's > his_mru, chop the packet (`m') into bits */
778 mo
= m_get(dl
->physical
->link
.lcp
.his_mru
, MB_MPOUT
);
780 m
= mbuf_Read(m
, MBUF_CTOP(mo
), mo
->m_len
);
782 mp_Output(mp
, bundle
, &dl
->physical
->link
, mo
, begin
, end
);
798 mp
->out
.link
= thislink
; /* Start here next time */
804 mp_SetDatalinkBandwidth(struct cmdargs
const *arg
)
808 if (arg
->argc
!= arg
->argn
+1)
811 val
= atoi(arg
->argv
[arg
->argn
]);
813 log_Printf(LogWARN
, "The link bandwidth must be greater than zero\n");
816 arg
->cx
->mp
.bandwidth
= val
;
818 if (arg
->cx
->state
== DATALINK_OPEN
)
819 bundle_CalculateBandwidth(arg
->bundle
);
825 mp_ShowStatus(struct cmdargs
const *arg
)
827 struct mp
*mp
= &arg
->bundle
->ncp
.mp
;
829 prompt_Printf(arg
->prompt
, "Multilink is %sactive\n", mp
->active
? "" : "in");
835 prompt_Printf(arg
->prompt
, "Socket: %s\n",
836 mp
->server
.socket
.sun_path
);
837 for (m
= mp
->inbufs
; m
; m
= m
->m_nextpkt
) {
841 prompt_Printf(arg
->prompt
, "Pending frags: %d", bufs
);
844 unsigned long first
, last
;
846 first
= mp_ReadHeader(mp
, mp
->inbufs
, &mh
) ? mh
.seq
: 0;
847 last
= mp_ReadHeader(mp
, lm
, &mh
) ? mh
.seq
: 0;
848 prompt_Printf(arg
->prompt
, " (Have %lu - %lu, want %lu, lowest %lu)\n",
849 first
, last
, (unsigned long)mp
->seq
.next_in
,
850 (unsigned long)mp
->seq
.min_in
);
851 prompt_Printf(arg
->prompt
, " First has %sbegin bit and "
852 "%send bit", mh
.begin
? "" : "no ", mh
.end
? "" : "no ");
854 prompt_Printf(arg
->prompt
, "\n");
857 prompt_Printf(arg
->prompt
, "\nMy Side:\n");
859 prompt_Printf(arg
->prompt
, " Output SEQ: %u\n", mp
->out
.seq
);
860 prompt_Printf(arg
->prompt
, " MRRU: %u\n", mp
->local_mrru
);
861 prompt_Printf(arg
->prompt
, " Short Seq: %s\n",
862 mp
->local_is12bit
? "on" : "off");
864 prompt_Printf(arg
->prompt
, " Discriminator: %s\n",
865 mp_Enddisc(mp
->cfg
.enddisc
.class, mp
->cfg
.enddisc
.address
,
866 mp
->cfg
.enddisc
.len
));
868 prompt_Printf(arg
->prompt
, "\nHis Side:\n");
870 prompt_Printf(arg
->prompt
, " Auth Name: %s\n", mp
->peer
.authname
);
871 prompt_Printf(arg
->prompt
, " Input SEQ: %u\n", mp
->seq
.next_in
);
872 prompt_Printf(arg
->prompt
, " MRRU: %u\n", mp
->peer_mrru
);
873 prompt_Printf(arg
->prompt
, " Short Seq: %s\n",
874 mp
->peer_is12bit
? "on" : "off");
876 prompt_Printf(arg
->prompt
, " Discriminator: %s\n",
877 mp_Enddisc(mp
->peer
.enddisc
.class, mp
->peer
.enddisc
.address
,
878 mp
->peer
.enddisc
.len
));
880 prompt_Printf(arg
->prompt
, "\nDefaults:\n");
882 prompt_Printf(arg
->prompt
, " MRRU: ");
884 prompt_Printf(arg
->prompt
, "%d (multilink enabled)\n", mp
->cfg
.mrru
);
886 prompt_Printf(arg
->prompt
, "disabled\n");
887 prompt_Printf(arg
->prompt
, " Short Seq: %s\n",
888 command_ShowNegval(mp
->cfg
.shortseq
));
889 prompt_Printf(arg
->prompt
, " Discriminator: %s\n",
890 command_ShowNegval(mp
->cfg
.negenddisc
));
891 prompt_Printf(arg
->prompt
, " AutoLoad: min %d%%, max %d%%,"
892 " period %d secs\n", mp
->cfg
.autoload
.min
,
893 mp
->cfg
.autoload
.max
, mp
->cfg
.autoload
.period
);
899 mp_Enddisc(u_char c
, const char *address
, size_t len
)
901 static char result
[100]; /* Used immediately after it's returned */
906 sprintf(result
, "Null Class");
910 snprintf(result
, sizeof result
, "Local Addr: %.*s", (int)len
,
916 snprintf(result
, sizeof result
, "IP %s",
917 inet_ntoa(*(const struct in_addr
*)address
));
919 sprintf(result
, "IP[%zd] ???", len
);
924 const u_char
*m
= (const u_char
*)address
;
925 snprintf(result
, sizeof result
, "MAC %02x:%02x:%02x:%02x:%02x:%02x",
926 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
928 sprintf(result
, "MAC[%zd] ???", len
);
932 sprintf(result
, "Magic: 0x");
933 header
= strlen(result
);
934 if (len
+ header
+ 1 > sizeof result
)
935 len
= sizeof result
- header
- 1;
936 for (f
= 0; f
< len
; f
++)
937 sprintf(result
+ header
+ 2 * f
, "%02x", address
[f
]);
941 snprintf(result
, sizeof result
, "PSN: %.*s", (int)len
, address
);
945 sprintf(result
, "%d: ", (int)c
);
946 header
= strlen(result
);
947 if (len
+ header
+ 1 > sizeof result
)
948 len
= sizeof result
- header
- 1;
949 for (f
= 0; f
< len
; f
++)
950 sprintf(result
+ header
+ 2 * f
, "%02x", address
[f
]);
957 mp_SetEnddisc(struct cmdargs
const *arg
)
959 struct mp
*mp
= &arg
->bundle
->ncp
.mp
;
962 switch (bundle_Phase(arg
->bundle
)) {
965 case PHASE_ESTABLISH
:
966 /* Make sure none of our links are DATALINK_LCP or greater */
967 if (bundle_HighestState(arg
->bundle
) >= DATALINK_LCP
) {
968 log_Printf(LogWARN
, "enddisc: Only changable before"
969 " LCP negotiations\n");
974 log_Printf(LogWARN
, "enddisc: Only changable at phase DEAD/ESTABLISH\n");
978 if (arg
->argc
== arg
->argn
) {
979 mp
->cfg
.enddisc
.class = 0;
980 *mp
->cfg
.enddisc
.address
= '\0';
981 mp
->cfg
.enddisc
.len
= 0;
982 } else if (arg
->argc
> arg
->argn
) {
983 if (!strcasecmp(arg
->argv
[arg
->argn
], "label")) {
984 mp
->cfg
.enddisc
.class = ENDDISC_LOCAL
;
985 strcpy(mp
->cfg
.enddisc
.address
, arg
->bundle
->cfg
.label
);
986 mp
->cfg
.enddisc
.len
= strlen(mp
->cfg
.enddisc
.address
);
987 } else if (!strcasecmp(arg
->argv
[arg
->argn
], "ip")) {
988 if (arg
->bundle
->ncp
.ipcp
.my_ip
.s_addr
== INADDR_ANY
)
989 ncprange_getip4addr(&arg
->bundle
->ncp
.ipcp
.cfg
.my_range
, &addr
);
991 addr
= arg
->bundle
->ncp
.ipcp
.my_ip
;
992 memcpy(mp
->cfg
.enddisc
.address
, &addr
.s_addr
, sizeof addr
.s_addr
);
993 mp
->cfg
.enddisc
.class = ENDDISC_IP
;
994 mp
->cfg
.enddisc
.len
= sizeof arg
->bundle
->ncp
.ipcp
.my_ip
.s_addr
;
995 } else if (!strcasecmp(arg
->argv
[arg
->argn
], "mac")) {
996 struct sockaddr_dl hwaddr
;
998 if (arg
->bundle
->ncp
.ipcp
.my_ip
.s_addr
== INADDR_ANY
)
999 ncprange_getip4addr(&arg
->bundle
->ncp
.ipcp
.cfg
.my_range
, &addr
);
1001 addr
= arg
->bundle
->ncp
.ipcp
.my_ip
;
1003 if (arp_EtherAddr(addr
, &hwaddr
, 1)) {
1004 mp
->cfg
.enddisc
.class = ENDDISC_MAC
;
1005 memcpy(mp
->cfg
.enddisc
.address
, hwaddr
.sdl_data
+ hwaddr
.sdl_nlen
,
1007 mp
->cfg
.enddisc
.len
= hwaddr
.sdl_alen
;
1009 log_Printf(LogWARN
, "set enddisc: Can't locate MAC address for %s\n",
1013 } else if (!strcasecmp(arg
->argv
[arg
->argn
], "magic")) {
1017 for (f
= 0; f
< 20; f
+= sizeof(long))
1018 *(long *)(mp
->cfg
.enddisc
.address
+ f
) = random();
1019 mp
->cfg
.enddisc
.class = ENDDISC_MAGIC
;
1020 mp
->cfg
.enddisc
.len
= 20;
1021 } else if (!strcasecmp(arg
->argv
[arg
->argn
], "psn")) {
1022 if (arg
->argc
> arg
->argn
+1) {
1023 mp
->cfg
.enddisc
.class = ENDDISC_PSN
;
1024 strcpy(mp
->cfg
.enddisc
.address
, arg
->argv
[arg
->argn
+1]);
1025 mp
->cfg
.enddisc
.len
= strlen(mp
->cfg
.enddisc
.address
);
1027 log_Printf(LogWARN
, "PSN endpoint requires additional data\n");
1031 log_Printf(LogWARN
, "%s: Unrecognised endpoint type\n",
1032 arg
->argv
[arg
->argn
]);
1041 mpserver_UpdateSet(struct fdescriptor
*d
, fd_set
*r
, fd_set
*w
, fd_set
*e
,
1044 struct mpserver
*s
= descriptor2mpserver(d
);
1048 if (s
->send
.dl
!= NULL
) {
1049 /* We've connect()ed */
1050 if (!link_QueueLen(&s
->send
.dl
->physical
->link
) &&
1051 !s
->send
.dl
->physical
->out
) {
1052 /* Only send if we've transmitted all our data (i.e. the ConfigAck) */
1053 result
-= datalink_RemoveFromSet(s
->send
.dl
, r
, w
, e
);
1054 bundle_SendDatalink(s
->send
.dl
, s
->fd
, &s
->socket
);
1058 /* Never read from a datalink that's on death row ! */
1059 result
-= datalink_RemoveFromSet(s
->send
.dl
, r
, NULL
, NULL
);
1060 } else if (r
&& s
->fd
>= 0) {
1064 log_Printf(LogTIMER
, "mp: fdset(r) %d\n", s
->fd
);
1071 mpserver_IsSet(struct fdescriptor
*d
, const fd_set
*fdset
)
1073 struct mpserver
*s
= descriptor2mpserver(d
);
1074 return s
->fd
>= 0 && FD_ISSET(s
->fd
, fdset
);
1078 mpserver_Read(struct fdescriptor
*d
, struct bundle
*bundle
,
1079 const fd_set
*fdset __unused
)
1081 struct mpserver
*s
= descriptor2mpserver(d
);
1083 bundle_ReceiveDatalink(bundle
, s
->fd
);
1087 mpserver_Write(struct fdescriptor
*d __unused
, struct bundle
*bundle __unused
,
1088 const fd_set
*fdset __unused
)
1090 /* We never want to write here ! */
1091 log_Printf(LogALERT
, "mpserver_Write: Internal error: Bad call !\n");
1096 mpserver_Init(struct mpserver
*s
)
1098 s
->desc
.type
= MPSERVER_DESCRIPTOR
;
1099 s
->desc
.UpdateSet
= mpserver_UpdateSet
;
1100 s
->desc
.IsSet
= mpserver_IsSet
;
1101 s
->desc
.Read
= mpserver_Read
;
1102 s
->desc
.Write
= mpserver_Write
;
1105 memset(&s
->socket
, '\0', sizeof s
->socket
);
1109 mpserver_Open(struct mpserver
*s
, struct peerid
*peer
)
1115 log_Printf(LogALERT
, "Internal error ! mpserver already open\n");
1119 l
= snprintf(s
->socket
.sun_path
, sizeof s
->socket
.sun_path
, "%sppp-%s-%02x-",
1120 _PATH_VARRUN
, peer
->authname
, peer
->enddisc
.class);
1122 log_Printf(LogERROR
, "mpserver: snprintf(): %s\n", strerror(errno
));
1123 return MPSERVER_FAILED
;
1127 f
< peer
->enddisc
.len
&& (size_t)l
< sizeof s
->socket
.sun_path
- 2;
1129 snprintf(s
->socket
.sun_path
+ l
, sizeof s
->socket
.sun_path
- l
,
1130 "%02x", *(u_char
*)(peer
->enddisc
.address
+f
));
1134 s
->socket
.sun_family
= AF_LOCAL
;
1135 s
->socket
.sun_len
= sizeof s
->socket
;
1136 s
->fd
= ID0socket(PF_LOCAL
, SOCK_DGRAM
, 0);
1138 log_Printf(LogERROR
, "mpserver: socket(): %s\n", strerror(errno
));
1139 return MPSERVER_FAILED
;
1142 setsockopt(s
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (struct sockaddr
*)&s
->socket
,
1147 * Try to bind the socket. If we succeed we play server, if we fail
1148 * we connect() and hand the link off.
1151 if (ID0bind_un(s
->fd
, &s
->socket
) < 0) {
1152 if (errno
!= EADDRINUSE
) {
1153 log_Printf(LogPHASE
, "mpserver: can't create bundle socket %s (%s)\n",
1154 s
->socket
.sun_path
, strerror(errno
));
1158 return MPSERVER_FAILED
;
1161 /* So we're the sender */
1163 if (ID0connect_un(s
->fd
, &s
->socket
) < 0) {
1164 log_Printf(LogPHASE
, "mpserver: can't connect to bundle socket %s (%s)\n",
1165 s
->socket
.sun_path
, strerror(errno
));
1166 if (errno
== ECONNREFUSED
)
1167 log_Printf(LogPHASE
, " The previous server died badly !\n");
1170 return MPSERVER_FAILED
;
1173 /* Donate our link to the other guy */
1174 return MPSERVER_CONNECTED
;
1177 return MPSERVER_LISTENING
;
1181 mpserver_Close(struct mpserver
*s
)
1183 if (s
->send
.dl
!= NULL
) {
1184 bundle_SendDatalink(s
->send
.dl
, s
->fd
, &s
->socket
);
1187 } else if (s
->fd
>= 0) {
1189 if (ID0unlink(s
->socket
.sun_path
) == -1)
1190 log_Printf(LogERROR
, "%s: Failed to remove: %s\n", s
->socket
.sun_path
,
1192 memset(&s
->socket
, '\0', sizeof s
->socket
);
1198 mp_LinkLost(struct mp
*mp
, struct datalink
*dl
)
1200 if (mp
->seq
.min_in
== dl
->mp
.seq
)
1201 /* We've lost the link that's holding everything up ! */
1202 mp_Assemble(mp
, NULL
, NULL
);
1206 mp_QueueLen(struct mp
*mp
)
1208 return link_QueueLen(&mp
->link
);