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
26 * $FreeBSD: src/usr.sbin/ppp/mp.c,v 1.36.2.9 2002/09/01 02:12:28 brian Exp $
27 * $DragonFly: src/usr.sbin/ppp/mp.c,v 1.3 2007/05/17 08:19:03 swildner Exp $
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <arpa/inet.h>
35 #include <net/if_dl.h>
36 #include <sys/socket.h>
62 #include "throughput.h"
63 #include "slcompress.h"
73 #include "descriptor.h"
93 peerid_Init(struct peerid
*peer
)
95 peer
->enddisc
.class = 0;
96 *peer
->enddisc
.address
= '\0';
97 peer
->enddisc
.len
= 0;
98 *peer
->authname
= '\0';
102 peerid_Equal(const struct peerid
*p1
, const struct peerid
*p2
)
104 return !strcmp(p1
->authname
, p2
->authname
) &&
105 p1
->enddisc
.class == p2
->enddisc
.class &&
106 p1
->enddisc
.len
== p2
->enddisc
.len
&&
107 !memcmp(p1
->enddisc
.address
, p2
->enddisc
.address
, p1
->enddisc
.len
);
111 inc_seq(unsigned is12bit
, u_int32_t seq
)
115 if (seq
& 0xfffff000)
117 } else if (seq
& 0xff000000)
123 isbefore(unsigned is12bit
, u_int32_t seq1
, u_int32_t seq2
)
125 u_int32_t max
= (is12bit
? 0xfff : 0xffffff) - 0x200;
128 if (seq2
< 0x200 || seq2
> seq1
)
130 } else if ((seq1
> 0x200 || seq2
<= max
) && seq1
< seq2
)
137 mp_ReadHeader(struct mp
*mp
, struct mbuf
*m
, struct mp_header
*header
)
139 if (mp
->local_is12bit
) {
142 ua_ntohs(MBUF_CTOP(m
), &val
);
144 log_Printf(LogWARN
, "Oops - MP header without required zero bits\n");
147 header
->begin
= val
& 0x8000 ? 1 : 0;
148 header
->end
= val
& 0x4000 ? 1 : 0;
149 header
->seq
= val
& 0x0fff;
152 ua_ntohl(MBUF_CTOP(m
), &header
->seq
);
153 if (header
->seq
& 0x3f000000) {
154 log_Printf(LogWARN
, "Oops - MP header without required zero bits\n");
157 header
->begin
= header
->seq
& 0x80000000 ? 1 : 0;
158 header
->end
= header
->seq
& 0x40000000 ? 1 : 0;
159 header
->seq
&= 0x00ffffff;
165 mp_LayerStart(void *v
, struct fsm
*fp
)
167 /* The given FSM (ccp) is about to start up ! */
171 mp_LayerUp(void *v
, struct fsm
*fp
)
173 /* The given fsm (ccp) is now up */
175 bundle_CalculateBandwidth(fp
->bundle
); /* Against ccp_MTUOverhead */
179 mp_LayerDown(void *v
, struct fsm
*fp
)
181 /* The given FSM (ccp) has been told to come down */
185 mp_LayerFinish(void *v
, struct fsm
*fp
)
187 /* The given fsm (ccp) is now down */
188 if (fp
->state
== ST_CLOSED
&& fp
->open_mode
== OPEN_PASSIVE
)
189 fsm_Open(fp
); /* CCP goes to ST_STOPPED */
195 struct mp
*mp
= (struct mp
*)v
;
198 percent
= MAX(mp
->link
.stats
.total
.in
.OctetsPerSecond
,
199 mp
->link
.stats
.total
.out
.OctetsPerSecond
) * 800 /
200 mp
->bundle
->bandwidth
;
201 if (percent
>= mp
->cfg
.autoload
.max
) {
202 log_Printf(LogDEBUG
, "%d%% saturation - bring a link up ?\n", percent
);
203 bundle_AutoAdjust(mp
->bundle
, percent
, AUTO_UP
);
204 } else if (percent
<= mp
->cfg
.autoload
.min
) {
205 log_Printf(LogDEBUG
, "%d%% saturation - bring a link down ?\n", percent
);
206 bundle_AutoAdjust(mp
->bundle
, percent
, AUTO_DOWN
);
211 mp_StopAutoloadTimer(struct mp
*mp
)
213 throughput_stop(&mp
->link
.stats
.total
);
217 mp_CheckAutoloadTimer(struct mp
*mp
)
219 if (mp
->link
.stats
.total
.SamplePeriod
!= mp
->cfg
.autoload
.period
) {
220 throughput_destroy(&mp
->link
.stats
.total
);
221 throughput_init(&mp
->link
.stats
.total
, mp
->cfg
.autoload
.period
);
222 throughput_callback(&mp
->link
.stats
.total
, mp_UpDown
, mp
);
225 if (bundle_WantAutoloadTimer(mp
->bundle
))
226 throughput_start(&mp
->link
.stats
.total
, "MP throughput", 1);
228 mp_StopAutoloadTimer(mp
);
232 mp_RestartAutoloadTimer(struct mp
*mp
)
234 if (mp
->link
.stats
.total
.SamplePeriod
!= mp
->cfg
.autoload
.period
)
235 mp_CheckAutoloadTimer(mp
);
237 throughput_clear(&mp
->link
.stats
.total
, THROUGHPUT_OVERALL
, NULL
);
241 mp_Init(struct mp
*mp
, struct bundle
*bundle
)
243 mp
->peer_is12bit
= mp
->local_is12bit
= 0;
244 mp
->peer_mrru
= mp
->local_mrru
= 0;
246 peerid_Init(&mp
->peer
);
250 mp
->out
.af
= AF_INET
;
256 mp
->link
.type
= LOGICAL_LINK
;
257 mp
->link
.name
= "mp";
258 mp
->link
.len
= sizeof *mp
;
260 mp
->cfg
.autoload
.period
= SAMPLE_PERIOD
;
261 mp
->cfg
.autoload
.min
= mp
->cfg
.autoload
.max
= 0;
262 throughput_init(&mp
->link
.stats
.total
, mp
->cfg
.autoload
.period
);
263 throughput_callback(&mp
->link
.stats
.total
, mp_UpDown
, mp
);
264 mp
->link
.stats
.parent
= NULL
;
265 mp
->link
.stats
.gather
= 0; /* Let the physical links gather stats */
266 memset(mp
->link
.Queue
, '\0', sizeof mp
->link
.Queue
);
267 memset(mp
->link
.proto_in
, '\0', sizeof mp
->link
.proto_in
);
268 memset(mp
->link
.proto_out
, '\0', sizeof mp
->link
.proto_out
);
270 mp
->fsmp
.LayerStart
= mp_LayerStart
;
271 mp
->fsmp
.LayerUp
= mp_LayerUp
;
272 mp
->fsmp
.LayerDown
= mp_LayerDown
;
273 mp
->fsmp
.LayerFinish
= mp_LayerFinish
;
274 mp
->fsmp
.object
= mp
;
276 mpserver_Init(&mp
->server
);
279 mp
->cfg
.shortseq
= NEG_ENABLED
|NEG_ACCEPTED
;
280 mp
->cfg
.negenddisc
= NEG_ENABLED
|NEG_ACCEPTED
;
281 mp
->cfg
.enddisc
.class = 0;
282 *mp
->cfg
.enddisc
.address
= '\0';
283 mp
->cfg
.enddisc
.len
= 0;
285 lcp_Init(&mp
->link
.lcp
, mp
->bundle
, &mp
->link
, NULL
);
286 ccp_Init(&mp
->link
.ccp
, mp
->bundle
, &mp
->link
, &mp
->fsmp
);
288 link_EmptyStack(&mp
->link
);
289 link_Stack(&mp
->link
, &protolayer
);
290 link_Stack(&mp
->link
, &ccplayer
);
291 link_Stack(&mp
->link
, &vjlayer
);
293 link_Stack(&mp
->link
, &natlayer
);
298 mp_Up(struct mp
*mp
, struct datalink
*dl
)
300 struct lcp
*lcp
= &dl
->physical
->link
.lcp
;
303 /* We're adding a link - do a last validation on our parameters */
304 if (!peerid_Equal(&dl
->peer
, &mp
->peer
)) {
305 log_Printf(LogPHASE
, "%s: Inappropriate peer !\n", dl
->name
);
306 log_Printf(LogPHASE
, " Attached to peer %s/%s\n", mp
->peer
.authname
,
307 mp_Enddisc(mp
->peer
.enddisc
.class, mp
->peer
.enddisc
.address
,
308 mp
->peer
.enddisc
.len
));
309 log_Printf(LogPHASE
, " New link is peer %s/%s\n", dl
->peer
.authname
,
310 mp_Enddisc(dl
->peer
.enddisc
.class, dl
->peer
.enddisc
.address
,
311 dl
->peer
.enddisc
.len
));
314 if (mp
->local_mrru
!= lcp
->want_mrru
||
315 mp
->peer_mrru
!= lcp
->his_mrru
||
316 mp
->local_is12bit
!= lcp
->want_shortseq
||
317 mp
->peer_is12bit
!= lcp
->his_shortseq
) {
318 log_Printf(LogPHASE
, "%s: Invalid MRRU/SHORTSEQ MP parameters !\n",
324 /* First link in multilink mode */
326 mp
->local_mrru
= lcp
->want_mrru
;
327 mp
->peer_mrru
= lcp
->his_mrru
;
328 mp
->local_is12bit
= lcp
->want_shortseq
;
329 mp
->peer_is12bit
= lcp
->his_shortseq
;
332 throughput_destroy(&mp
->link
.stats
.total
);
333 throughput_init(&mp
->link
.stats
.total
, mp
->cfg
.autoload
.period
);
334 throughput_callback(&mp
->link
.stats
.total
, mp_UpDown
, mp
);
335 memset(mp
->link
.Queue
, '\0', sizeof mp
->link
.Queue
);
336 memset(mp
->link
.proto_in
, '\0', sizeof mp
->link
.proto_in
);
337 memset(mp
->link
.proto_out
, '\0', sizeof mp
->link
.proto_out
);
339 /* Tell the link who it belongs to */
340 dl
->physical
->link
.stats
.parent
= &mp
->link
.stats
.total
;
344 mp
->out
.af
= AF_INET
;
349 * Now we create our server socket.
350 * If it already exists, join it. Otherwise, create and own it
352 switch (mpserver_Open(&mp
->server
, &mp
->peer
)) {
353 case MPSERVER_CONNECTED
:
354 log_Printf(LogPHASE
, "mp: Transfer link on %s\n",
355 mp
->server
.socket
.sun_path
);
356 mp
->server
.send
.dl
= dl
; /* Defer 'till it's safe to send */
358 case MPSERVER_FAILED
:
360 case MPSERVER_LISTENING
:
361 log_Printf(LogPHASE
, "mp: Listening on %s\n", mp
->server
.socket
.sun_path
);
362 log_Printf(LogPHASE
, " First link: %s\n", dl
->name
);
364 /* Re-point our NCP layers at our MP link */
365 ncp_SetLink(&mp
->bundle
->ncp
, &mp
->link
);
367 /* Our lcp's already up 'cos of the NULL parent */
368 if (ccp_SetOpenMode(&mp
->link
.ccp
)) {
369 fsm_Up(&mp
->link
.ccp
.fsm
);
370 fsm_Open(&mp
->link
.ccp
.fsm
);
382 mp_Down(struct mp
*mp
)
388 mp_StopAutoloadTimer(mp
);
390 /* Don't want any more of these */
391 mpserver_Close(&mp
->server
);
393 /* CCP goes down with a bang */
394 fsm2initial(&mp
->link
.ccp
.fsm
);
396 /* Received fragments go in the bit-bucket */
398 next
= mp
->inbufs
->m_nextpkt
;
403 peerid_Init(&mp
->peer
);
409 mp_linkInit(struct mp_link
*mplink
)
412 mplink
->bandwidth
= 0;
416 mp_Assemble(struct mp
*mp
, struct mbuf
*m
, struct physical
*p
)
418 struct mp_header mh
, h
;
419 struct mbuf
*q
, *last
;
423 * When `m' and `p' are NULL, it means our oldest link has gone down.
424 * We want to determine a new min, and process any intermediate stuff
428 if (m
&& mp_ReadHeader(mp
, m
, &mh
) == 0) {
435 p
->dl
->mp
.seq
= mh
.seq
;
437 seq
= mp
->seq
.min_in
;
439 if (mp
->seq
.min_in
== seq
) {
441 * We've received new data on the link that has our min (oldest) seq.
442 * Figure out which link now has the smallest (oldest) seq.
446 mp
->seq
.min_in
= (u_int32_t
)-1;
447 for (dl
= mp
->bundle
->links
; dl
; dl
= dl
->next
)
448 if (dl
->state
== DATALINK_OPEN
&&
449 (mp
->seq
.min_in
== -1 ||
450 isbefore(mp
->local_is12bit
, dl
->mp
.seq
, mp
->seq
.min_in
)))
451 mp
->seq
.min_in
= dl
->mp
.seq
;
455 * Now process as many of our fragments as we can, adding our new
456 * fragment in as we go, and ordering with the oldest at the top of
461 seq
= mp
->seq
.next_in
;
473 mp_ReadHeader(mp
, q
, &h
);
475 if (m
&& isbefore(mp
->local_is12bit
, mh
.seq
, h
.seq
)) {
476 /* Our received fragment fits in before this one, so link it in */
489 /* we're missing something :-( */
490 if (isbefore(mp
->local_is12bit
, seq
, mp
->seq
.min_in
)) {
491 /* we're never gonna get it */
494 /* Zap all older fragments */
495 while (mp
->inbufs
!= q
) {
496 log_Printf(LogDEBUG
, "Drop frag\n");
497 next
= mp
->inbufs
->m_nextpkt
;
503 * Zap everything until the next `end' fragment OR just before
504 * the next `begin' fragment OR 'till seq.min_in - whichever
508 mp_ReadHeader(mp
, mp
->inbufs
, &h
);
510 /* We might be able to process this ! */
511 h
.seq
--; /* We're gonna look for fragment with h.seq+1 */
514 next
= mp
->inbufs
->m_nextpkt
;
515 log_Printf(LogDEBUG
, "Drop frag %u\n", h
.seq
);
518 } while (mp
->inbufs
&& (isbefore(mp
->local_is12bit
, mp
->seq
.min_in
,
522 * Continue processing things from here.
523 * This deals with the possibility that we received a fragment
524 * on the slowest link that invalidates some of our data (because
525 * of the hole at `q'), but where there are subsequent `whole'
526 * packets that have already been received.
529 mp
->seq
.next_in
= seq
= inc_seq(mp
->local_is12bit
, h
.seq
);
533 /* we may still receive the missing fragment */
536 /* We've got something, reassemble */
537 struct mbuf
**frag
= &q
;
543 mp
->inbufs
= mp
->inbufs
->m_nextpkt
;
544 len
= mp_ReadHeader(mp
, *frag
, &h
);
547 if (frag
== &q
&& !h
.begin
) {
548 log_Printf(LogWARN
, "Oops - MP frag %lu should have a begin flag\n",
552 } else if (frag
!= &q
&& h
.begin
) {
553 log_Printf(LogWARN
, "Oops - MP frag %lu should have an end flag\n",
556 * Stuff our fragment back at the front of the queue and zap
557 * our half-assembled packet.
559 (*frag
)->m_nextpkt
= mp
->inbufs
;
565 h
.end
= 0; /* just in case it's a whole packet */
567 (*frag
)->m_offset
+= len
;
568 (*frag
)->m_len
-= len
;
569 (*frag
)->m_nextpkt
= NULL
;
571 frag
= &(*frag
)->m_next
;
572 while (*frag
!= NULL
);
578 log_Printf(LogDEBUG
, "MP: Reassembled frags %ld-%lu, length %d\n",
579 first
, (u_long
)h
.seq
, m_length(q
));
580 link_PullPacket(&mp
->link
, MBUF_CTOP(q
), q
->m_len
, mp
->bundle
);
584 mp
->seq
.next_in
= seq
= inc_seq(mp
->local_is12bit
, h
.seq
);
588 /* Look for the next fragment */
589 seq
= inc_seq(mp
->local_is12bit
, seq
);
596 /* We still have to find a home for our new fragment */
598 for (q
= mp
->inbufs
; q
; last
= q
, q
= q
->m_nextpkt
) {
599 mp_ReadHeader(mp
, q
, &h
);
600 if (isbefore(mp
->local_is12bit
, mh
.seq
, h
.seq
))
603 /* Our received fragment fits in here */
613 mp_Input(struct bundle
*bundle
, struct link
*l
, struct mbuf
*bp
)
615 struct physical
*p
= link2physical(l
);
617 if (!bundle
->ncp
.mp
.active
)
618 /* Let someone else deal with it ! */
622 log_Printf(LogWARN
, "DecodePacket: Can't do MP inside MP !\n");
625 m_settype(bp
, MB_MPIN
);
626 mp_Assemble(&bundle
->ncp
.mp
, bp
, p
);
633 mp_Output(struct mp
*mp
, struct bundle
*bundle
, struct link
*l
,
634 struct mbuf
*m
, u_int32_t begin
, u_int32_t end
)
638 /* Stuff an MP header on the front of our packet and send it */
640 if (mp
->peer_is12bit
) {
643 val
= (begin
<< 15) | (end
<< 14) | (u_int16_t
)mp
->out
.seq
;
644 ua_htons(&val
, prepend
);
645 m
= m_prepend(m
, prepend
, 2, 0);
649 val
= (begin
<< 31) | (end
<< 30) | (u_int32_t
)mp
->out
.seq
;
650 ua_htonl(&val
, prepend
);
651 m
= m_prepend(m
, prepend
, 4, 0);
653 if (log_IsKept(LogDEBUG
))
654 log_Printf(LogDEBUG
, "MP[frag %d]: Send %d bytes on link `%s'\n",
655 mp
->out
.seq
, m_length(m
), l
->name
);
656 mp
->out
.seq
= inc_seq(mp
->peer_is12bit
, mp
->out
.seq
);
658 if (l
->ccp
.fsm
.state
!= ST_OPENED
&& ccp_Required(&l
->ccp
)) {
659 log_Printf(LogPHASE
, "%s: Not transmitting... waiting for CCP\n", l
->name
);
663 link_PushPacket(l
, m
, bundle
, LINK_QUEUES(l
) - 1, PROTO_MP
);
667 mp_FillPhysicalQueues(struct bundle
*bundle
)
669 struct mp
*mp
= &bundle
->ncp
.mp
;
670 struct datalink
*dl
, *fdl
;
671 size_t total
, add
, len
;
672 int thislink
, nlinks
, nopenlinks
, sendasip
;
673 u_int32_t begin
, end
;
675 struct link
*bestlink
;
677 thislink
= nlinks
= nopenlinks
= 0;
678 for (fdl
= NULL
, dl
= bundle
->links
; dl
; dl
= dl
->next
) {
679 /* Include non-open links here as mp->out.link will stay more correct */
681 if (thislink
== mp
->out
.link
)
687 if (dl
->state
== DATALINK_OPEN
)
699 for (dl
= fdl
; nlinks
> 0; dl
= dl
->next
, nlinks
--, thislink
++) {
705 if (dl
->state
!= DATALINK_OPEN
)
708 if (dl
->physical
->out
)
709 /* this link has suffered a short write. Let it continue */
712 add
= link_QueueLen(&dl
->physical
->link
);
714 /* this link has got stuff already queued. Let it continue */
719 if (!mp_QueueLen(mp
)) {
723 * If there's only a single open link in our bundle and we haven't got
724 * MP level link compression, queue outbound traffic directly via that
725 * link's protocol stack rather than using the MP link. This results
726 * in the outbound traffic going out as PROTO_IP or PROTO_IPV6 rather
731 sendasip
= nopenlinks
< 2;
733 if (dl
->physical
->link
.lcp
.his_mru
< mp
->peer_mrru
) {
735 * Actually, forget it. This test is done against the MRRU rather
736 * than the packet size so that we don't end up sending some data
737 * in MP fragments and some data in PROTO_IP packets. That's just
738 * too likely to upset some ppp implementations.
745 bestlink
= sendasip
? &dl
->physical
->link
: &mp
->link
;
746 if (!ncp_PushPacket(&bundle
->ncp
, &mp
->out
.af
, bestlink
))
747 break; /* Nothing else to send */
750 log_Printf(LogDEBUG
, "Don't send data as PROTO_IP, MRU < MRRU\n");
752 log_Printf(LogDEBUG
, "Sending data as PROTO_IP, not PROTO_MP\n");
755 add
= link_QueueLen(&dl
->physical
->link
);
757 /* this link has got stuff already queued. Let it continue */
764 m
= link_Dequeue(&mp
->link
);
771 if (dl
->state
== DATALINK_OPEN
) {
772 /* Write at most his_mru bytes to the physical link */
773 if (len
<= dl
->physical
->link
.lcp
.his_mru
) {
776 m_settype(mo
, MB_MPOUT
);
778 /* It's > his_mru, chop the packet (`m') into bits */
779 mo
= m_get(dl
->physical
->link
.lcp
.his_mru
, MB_MPOUT
);
781 m
= mbuf_Read(m
, MBUF_CTOP(mo
), mo
->m_len
);
783 mp_Output(mp
, bundle
, &dl
->physical
->link
, mo
, begin
, end
);
799 mp
->out
.link
= thislink
; /* Start here next time */
805 mp_SetDatalinkBandwidth(struct cmdargs
const *arg
)
809 if (arg
->argc
!= arg
->argn
+1)
812 val
= atoi(arg
->argv
[arg
->argn
]);
814 log_Printf(LogWARN
, "The link bandwidth must be greater than zero\n");
817 arg
->cx
->mp
.bandwidth
= val
;
819 if (arg
->cx
->state
== DATALINK_OPEN
)
820 bundle_CalculateBandwidth(arg
->bundle
);
826 mp_ShowStatus(struct cmdargs
const *arg
)
828 struct mp
*mp
= &arg
->bundle
->ncp
.mp
;
830 prompt_Printf(arg
->prompt
, "Multilink is %sactive\n", mp
->active
? "" : "in");
836 prompt_Printf(arg
->prompt
, "Socket: %s\n",
837 mp
->server
.socket
.sun_path
);
838 for (m
= mp
->inbufs
; m
; m
= m
->m_nextpkt
) {
842 prompt_Printf(arg
->prompt
, "Pending frags: %d", bufs
);
845 unsigned long first
, last
;
847 first
= mp_ReadHeader(mp
, mp
->inbufs
, &mh
) ? mh
.seq
: 0;
848 last
= mp_ReadHeader(mp
, lm
, &mh
) ? mh
.seq
: 0;
849 prompt_Printf(arg
->prompt
, " (Have %lu - %lu, want %lu, lowest %lu)\n",
850 first
, last
, (unsigned long)mp
->seq
.next_in
,
851 (unsigned long)mp
->seq
.min_in
);
852 prompt_Printf(arg
->prompt
, " First has %sbegin bit and "
853 "%send bit", mh
.begin
? "" : "no ", mh
.end
? "" : "no ");
855 prompt_Printf(arg
->prompt
, "\n");
858 prompt_Printf(arg
->prompt
, "\nMy Side:\n");
860 prompt_Printf(arg
->prompt
, " Output SEQ: %u\n", mp
->out
.seq
);
861 prompt_Printf(arg
->prompt
, " MRRU: %u\n", mp
->local_mrru
);
862 prompt_Printf(arg
->prompt
, " Short Seq: %s\n",
863 mp
->local_is12bit
? "on" : "off");
865 prompt_Printf(arg
->prompt
, " Discriminator: %s\n",
866 mp_Enddisc(mp
->cfg
.enddisc
.class, mp
->cfg
.enddisc
.address
,
867 mp
->cfg
.enddisc
.len
));
869 prompt_Printf(arg
->prompt
, "\nHis Side:\n");
871 prompt_Printf(arg
->prompt
, " Auth Name: %s\n", mp
->peer
.authname
);
872 prompt_Printf(arg
->prompt
, " Input SEQ: %u\n", mp
->seq
.next_in
);
873 prompt_Printf(arg
->prompt
, " MRRU: %u\n", mp
->peer_mrru
);
874 prompt_Printf(arg
->prompt
, " Short Seq: %s\n",
875 mp
->peer_is12bit
? "on" : "off");
877 prompt_Printf(arg
->prompt
, " Discriminator: %s\n",
878 mp_Enddisc(mp
->peer
.enddisc
.class, mp
->peer
.enddisc
.address
,
879 mp
->peer
.enddisc
.len
));
881 prompt_Printf(arg
->prompt
, "\nDefaults:\n");
883 prompt_Printf(arg
->prompt
, " MRRU: ");
885 prompt_Printf(arg
->prompt
, "%d (multilink enabled)\n", mp
->cfg
.mrru
);
887 prompt_Printf(arg
->prompt
, "disabled\n");
888 prompt_Printf(arg
->prompt
, " Short Seq: %s\n",
889 command_ShowNegval(mp
->cfg
.shortseq
));
890 prompt_Printf(arg
->prompt
, " Discriminator: %s\n",
891 command_ShowNegval(mp
->cfg
.negenddisc
));
892 prompt_Printf(arg
->prompt
, " AutoLoad: min %d%%, max %d%%,"
893 " period %d secs\n", mp
->cfg
.autoload
.min
,
894 mp
->cfg
.autoload
.max
, mp
->cfg
.autoload
.period
);
900 mp_Enddisc(u_char c
, const char *address
, int len
)
902 static char result
[100]; /* Used immediately after it's returned */
907 sprintf(result
, "Null Class");
911 snprintf(result
, sizeof result
, "Local Addr: %.*s", len
, address
);
916 snprintf(result
, sizeof result
, "IP %s",
917 inet_ntoa(*(const struct in_addr
*)address
));
919 sprintf(result
, "IP[%d] ???", 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[%d] ???", len
);
932 sprintf(result
, "Magic: 0x");
933 header
= strlen(result
);
934 if (len
> sizeof result
- header
- 1)
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", len
, address
);
945 sprintf(result
, "%d: ", (int)c
);
946 header
= strlen(result
);
947 if (len
> sizeof result
- header
- 1)
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 changeable before"
969 " LCP negotiations\n");
974 log_Printf(LogWARN
, "enddisc: Only changeable 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
;
999 if (arg
->bundle
->ncp
.ipcp
.my_ip
.s_addr
== INADDR_ANY
)
1000 ncprange_getip4addr(&arg
->bundle
->ncp
.ipcp
.cfg
.my_range
, &addr
);
1002 addr
= arg
->bundle
->ncp
.ipcp
.my_ip
;
1004 s
= ID0socket(PF_INET
, SOCK_DGRAM
, 0);
1006 log_Printf(LogERROR
, "set enddisc: socket(): %s\n", strerror(errno
));
1009 if (arp_EtherAddr(s
, addr
, &hwaddr
, 1)) {
1010 mp
->cfg
.enddisc
.class = ENDDISC_MAC
;
1011 memcpy(mp
->cfg
.enddisc
.address
, hwaddr
.sdl_data
+ hwaddr
.sdl_nlen
,
1013 mp
->cfg
.enddisc
.len
= hwaddr
.sdl_alen
;
1015 log_Printf(LogWARN
, "set enddisc: Can't locate MAC address for %s\n",
1021 } else if (!strcasecmp(arg
->argv
[arg
->argn
], "magic")) {
1025 for (f
= 0; f
< 20; f
+= sizeof(long))
1026 *(long *)(mp
->cfg
.enddisc
.address
+ f
) = random();
1027 mp
->cfg
.enddisc
.class = ENDDISC_MAGIC
;
1028 mp
->cfg
.enddisc
.len
= 20;
1029 } else if (!strcasecmp(arg
->argv
[arg
->argn
], "psn")) {
1030 if (arg
->argc
> arg
->argn
+1) {
1031 mp
->cfg
.enddisc
.class = ENDDISC_PSN
;
1032 strcpy(mp
->cfg
.enddisc
.address
, arg
->argv
[arg
->argn
+1]);
1033 mp
->cfg
.enddisc
.len
= strlen(mp
->cfg
.enddisc
.address
);
1035 log_Printf(LogWARN
, "PSN endpoint requires additional data\n");
1039 log_Printf(LogWARN
, "%s: Unrecognised endpoint type\n",
1040 arg
->argv
[arg
->argn
]);
1049 mpserver_UpdateSet(struct fdescriptor
*d
, fd_set
*r
, fd_set
*w
, fd_set
*e
,
1052 struct mpserver
*s
= descriptor2mpserver(d
);
1056 if (s
->send
.dl
!= NULL
) {
1057 /* We've connect()ed */
1058 if (!link_QueueLen(&s
->send
.dl
->physical
->link
) &&
1059 !s
->send
.dl
->physical
->out
) {
1060 /* Only send if we've transmitted all our data (i.e. the ConfigAck) */
1061 result
-= datalink_RemoveFromSet(s
->send
.dl
, r
, w
, e
);
1062 bundle_SendDatalink(s
->send
.dl
, s
->fd
, &s
->socket
);
1066 /* Never read from a datalink that's on death row ! */
1067 result
-= datalink_RemoveFromSet(s
->send
.dl
, r
, NULL
, NULL
);
1068 } else if (r
&& s
->fd
>= 0) {
1072 log_Printf(LogTIMER
, "mp: fdset(r) %d\n", s
->fd
);
1079 mpserver_IsSet(struct fdescriptor
*d
, const fd_set
*fdset
)
1081 struct mpserver
*s
= descriptor2mpserver(d
);
1082 return s
->fd
>= 0 && FD_ISSET(s
->fd
, fdset
);
1086 mpserver_Read(struct fdescriptor
*d
, struct bundle
*bundle
, const fd_set
*fdset
)
1088 struct mpserver
*s
= descriptor2mpserver(d
);
1090 bundle_ReceiveDatalink(bundle
, s
->fd
);
1094 mpserver_Write(struct fdescriptor
*d
, struct bundle
*bundle
,
1095 const fd_set
*fdset
)
1097 /* We never want to write here ! */
1098 log_Printf(LogALERT
, "mpserver_Write: Internal error: Bad call !\n");
1103 mpserver_Init(struct mpserver
*s
)
1105 s
->desc
.type
= MPSERVER_DESCRIPTOR
;
1106 s
->desc
.UpdateSet
= mpserver_UpdateSet
;
1107 s
->desc
.IsSet
= mpserver_IsSet
;
1108 s
->desc
.Read
= mpserver_Read
;
1109 s
->desc
.Write
= mpserver_Write
;
1112 memset(&s
->socket
, '\0', sizeof s
->socket
);
1116 mpserver_Open(struct mpserver
*s
, struct peerid
*peer
)
1122 log_Printf(LogALERT
, "Internal error ! mpserver already open\n");
1126 l
= snprintf(s
->socket
.sun_path
, sizeof s
->socket
.sun_path
, "%sppp-%s-%02x-",
1127 _PATH_VARRUN
, peer
->authname
, peer
->enddisc
.class);
1129 log_Printf(LogERROR
, "mpserver: snprintf(): %s\n", strerror(errno
));
1130 return MPSERVER_FAILED
;
1133 for (f
= 0; f
< peer
->enddisc
.len
&& l
< sizeof s
->socket
.sun_path
- 2; f
++) {
1134 snprintf(s
->socket
.sun_path
+ l
, sizeof s
->socket
.sun_path
- l
,
1135 "%02x", *(u_char
*)(peer
->enddisc
.address
+f
));
1139 s
->socket
.sun_family
= AF_LOCAL
;
1140 s
->socket
.sun_len
= sizeof s
->socket
;
1141 s
->fd
= ID0socket(PF_LOCAL
, SOCK_DGRAM
, 0);
1143 log_Printf(LogERROR
, "mpserver: socket(): %s\n", strerror(errno
));
1144 return MPSERVER_FAILED
;
1147 setsockopt(s
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (struct sockaddr
*)&s
->socket
,
1152 * Try to bind the socket. If we succeed we play server, if we fail
1153 * we connect() and hand the link off.
1156 if (ID0bind_un(s
->fd
, &s
->socket
) < 0) {
1157 if (errno
!= EADDRINUSE
) {
1158 log_Printf(LogPHASE
, "mpserver: can't create bundle socket %s (%s)\n",
1159 s
->socket
.sun_path
, strerror(errno
));
1163 return MPSERVER_FAILED
;
1166 /* So we're the sender */
1168 if (ID0connect_un(s
->fd
, &s
->socket
) < 0) {
1169 log_Printf(LogPHASE
, "mpserver: can't connect to bundle socket %s (%s)\n",
1170 s
->socket
.sun_path
, strerror(errno
));
1171 if (errno
== ECONNREFUSED
)
1172 log_Printf(LogPHASE
, " The previous server died badly !\n");
1175 return MPSERVER_FAILED
;
1178 /* Donate our link to the other guy */
1179 return MPSERVER_CONNECTED
;
1182 return MPSERVER_LISTENING
;
1186 mpserver_Close(struct mpserver
*s
)
1188 if (s
->send
.dl
!= NULL
) {
1189 bundle_SendDatalink(s
->send
.dl
, s
->fd
, &s
->socket
);
1192 } else if (s
->fd
>= 0) {
1194 if (ID0unlink(s
->socket
.sun_path
) == -1)
1195 log_Printf(LogERROR
, "%s: Failed to remove: %s\n", s
->socket
.sun_path
,
1197 memset(&s
->socket
, '\0', sizeof s
->socket
);
1203 mp_LinkLost(struct mp
*mp
, struct datalink
*dl
)
1205 if (mp
->seq
.min_in
== dl
->mp
.seq
)
1206 /* We've lost the link that's holding everything up ! */
1207 mp_Assemble(mp
, NULL
, NULL
);
1211 mp_QueueLen(struct mp
*mp
)
1213 return link_QueueLen(&mp
->link
);