2 * multilink.c - support routines for multilink.
4 * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. The name(s) of the authors of this software must not be used to
14 * endorse or promote products derived from this software without
15 * prior written permission.
17 * 3. Redistributions of any form whatsoever must retain the following
19 * "This product includes software developed by Paul Mackerras
20 * <paulus@samba.org>".
22 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 #include "netif/ppp/ppp_opts.h"
32 #if PPP_SUPPORT && defined(HAVE_MULTILINK) /* don't build if not configured for use in lwipopts.h */
36 * Multilink uses Samba TDB (Trivial Database Library), which
37 * we cannot port, because it needs a filesystem.
39 * We have to choose between doing a memory-shared TDB-clone,
40 * or dropping multilink support at all.
49 #include <netinet/in.h>
52 #include "netif/ppp/ppp_impl.h"
54 #include "netif/ppp/fsm.h"
55 #include "netif/ppp/lcp.h"
56 #include "netif/ppp/tdb.h"
58 bool endpoint_specified
; /* user gave explicit endpoint discriminator */
59 char *bundle_id
; /* identifier for our bundle */
60 char *blinks_id
; /* key for the list of links */
61 bool doing_multilink
; /* multilink was enabled and agreed to */
62 bool multilink_master
; /* we own the multilink bundle */
64 extern TDB_CONTEXT
*pppdb
;
67 static void make_bundle_links (int append
);
68 static void remove_bundle_link (void);
69 static void iterate_bundle_links (void (*func
) (char *));
71 static int get_default_epdisc (struct epdisc
*);
72 static int parse_num (char *str
, const char *key
, int *valp
);
73 static int owns_unit (TDB_DATA pid
, int unit
);
75 #define set_ip_epdisc(ep, addr) do { \
77 ep->value[0] = addr >> 24; \
78 ep->value[1] = addr >> 16; \
79 ep->value[2] = addr >> 8; \
80 ep->value[3] = addr; \
83 #define LOCAL_IP_ADDR(addr) \
84 (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \
85 || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \
86 || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */
88 #define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH)
93 lcp_options
*wo
= &lcp_wantoptions
[0];
94 lcp_options
*ao
= &lcp_allowoptions
[0];
99 /* if we're doing multilink, we have to negotiate MRRU */
101 /* mrru not specified, default to mru */
108 if (!wo
->neg_endpoint
&& !noendpoint
) {
109 /* get a default endpoint value */
110 wo
->neg_endpoint
= get_default_epdisc(&wo
->endpoint
);
115 * Make a new bundle or join us to an existing bundle
116 * if we are doing multilink.
121 lcp_options
*go
= &lcp_gotoptions
[0];
122 lcp_options
*ho
= &lcp_hisoptions
[0];
123 lcp_options
*ao
= &lcp_allowoptions
[0];
127 TDB_DATA key
, pid
, rec
;
129 if (doing_multilink
) {
130 /* have previously joined a bundle */
131 if (!go
->neg_mrru
|| !ho
->neg_mrru
) {
132 notice("oops, didn't get multilink on renegotiation");
133 lcp_close(pcb
, "multilink required");
136 /* XXX should check the peer_authname and ho->endpoint
137 are the same as previously */
141 if (!go
->neg_mrru
|| !ho
->neg_mrru
) {
142 /* not doing multilink */
144 notice("oops, multilink negotiated only for receive");
145 mtu
= ho
->neg_mru
? ho
->mru
: PPP_MRU
;
149 /* already have a bundle */
150 cfg_bundle(0, 0, 0, 0);
151 netif_set_mtu(pcb
, mtu
);
154 make_new_bundle(0, 0, 0, 0);
156 netif_set_mtu(pcb
, mtu
);
163 * Find the appropriate bundle or join a new one.
164 * First we make up a name for the bundle.
165 * The length estimate is worst-case assuming every
166 * character has to be quoted.
168 l
= 4 * strlen(peer_authname
) + 10;
169 if (ho
->neg_endpoint
)
170 l
+= 3 * ho
->endpoint
.length
+ 8;
172 l
+= 3 * strlen(bundle_name
) + 2;
173 bundle_id
= malloc(l
);
175 novm("bundle identifier");
178 p
+= slprintf(p
, l
-1, "BUNDLE=\"%q\"", peer_authname
);
179 if (ho
->neg_endpoint
|| bundle_name
)
181 if (ho
->neg_endpoint
)
182 p
+= slprintf(p
, bundle_id
+l
-p
, "%s",
183 epdisc_to_str(&ho
->endpoint
));
185 p
+= slprintf(p
, bundle_id
+l
-p
, "/%v", bundle_name
);
187 /* Make the key for the list of links belonging to the bundle */
189 blinks_id
= malloc(l
+ 7);
190 if (blinks_id
== NULL
)
191 novm("bundle links key");
192 slprintf(blinks_id
, l
+ 7, "BUNDLE_LINKS=%s", bundle_id
+ 7);
195 * For demand mode, we only need to configure the bundle
196 * and attach the link.
198 mtu
= LWIP_MIN(ho
->mrru
, ao
->mru
);
200 cfg_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
201 netif_set_mtu(pcb
, mtu
);
202 script_setenv("BUNDLE", bundle_id
+ 7, 1);
207 * Check if the bundle ID is already in the database.
211 key
.dptr
= bundle_id
;
212 key
.dsize
= p
- bundle_id
;
213 pid
= tdb_fetch(pppdb
, key
);
214 if (pid
.dptr
!= NULL
) {
215 /* bundle ID exists, see if the pppd record exists */
216 rec
= tdb_fetch(pppdb
, pid
);
217 if (rec
.dptr
!= NULL
&& rec
.dsize
> 0) {
218 /* make sure the string is null-terminated */
219 rec
.dptr
[rec
.dsize
-1] = 0;
220 /* parse the interface number */
221 parse_num(rec
.dptr
, "IFNAME=ppp", &unit
);
222 /* check the pid value */
223 if (!parse_num(rec
.dptr
, "PPPD_PID=", &pppd_pid
)
224 || !process_exists(pppd_pid
)
225 || !owns_unit(pid
, unit
))
233 /* attach to existing unit */
234 if (bundle_attach(unit
)) {
236 script_setenv("BUNDLE", bundle_id
+ 7, 0);
237 make_bundle_links(1);
239 info("Link attached to %s", ifname
);
242 /* attach failed because bundle doesn't exist */
245 /* we have to make a new bundle */
246 make_new_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
248 netif_set_mtu(pcb
, mtu
);
249 script_setenv("BUNDLE", bundle_id
+ 7, 1);
250 make_bundle_links(pcb
);
252 info("New bundle %s created", ifname
);
253 multilink_master
= 1;
257 void mp_exit_bundle()
260 remove_bundle_link();
264 static void sendhup(char *str
)
268 if (parse_num(str
, "PPPD_PID=", &pid
) && pid
!= getpid()) {
270 dbglog("sending SIGHUP to process %d", pid
);
275 void mp_bundle_terminated()
279 bundle_terminating
= 1;
280 upper_layers_down(pcb
);
281 notice("Connection terminated.");
282 #if PPP_STATS_SUPPORT
284 #endif /* PPP_STATS_SUPPORT */
287 script_unsetenv("IFNAME");
292 iterate_bundle_links(sendhup
);
293 key
.dptr
= blinks_id
;
294 key
.dsize
= strlen(blinks_id
);
295 tdb_delete(pppdb
, key
);
298 new_phase(PPP_PHASE_DEAD
);
301 multilink_master
= 0;
304 static void make_bundle_links(int append
)
311 key
.dptr
= blinks_id
;
312 key
.dsize
= strlen(blinks_id
);
313 slprintf(entry
, sizeof(entry
), "%s;", db_key
);
316 rec
= tdb_fetch(pppdb
, key
);
317 if (rec
.dptr
!= NULL
&& rec
.dsize
> 0) {
318 rec
.dptr
[rec
.dsize
-1] = 0;
319 if (strstr(rec
.dptr
, db_key
) != NULL
) {
320 /* already in there? strange */
321 warn("link entry already exists in tdb");
324 l
= rec
.dsize
+ strlen(entry
);
327 novm("bundle link list");
328 slprintf(p
, l
, "%s%s", rec
.dptr
, entry
);
330 warn("bundle link list not found");
332 if (rec
.dptr
!= NULL
)
336 rec
.dsize
= strlen(p
) + 1;
337 if (tdb_store(pppdb
, key
, rec
, TDB_REPLACE
))
338 error("couldn't %s bundle link list",
339 append
? "update": "create");
344 static void remove_bundle_link()
351 key
.dptr
= blinks_id
;
352 key
.dsize
= strlen(blinks_id
);
353 slprintf(entry
, sizeof(entry
), "%s;", db_key
);
355 rec
= tdb_fetch(pppdb
, key
);
356 if (rec
.dptr
== NULL
|| rec
.dsize
<= 0) {
357 if (rec
.dptr
!= NULL
)
361 rec
.dptr
[rec
.dsize
-1] = 0;
362 p
= strstr(rec
.dptr
, entry
);
364 q
= p
+ strlen(entry
);
367 rec
.dsize
= p
- rec
.dptr
+ l
;
368 if (tdb_store(pppdb
, key
, rec
, TDB_REPLACE
))
369 error("couldn't update bundle link list (removal)");
374 static void iterate_bundle_links(void (*func
)(char *))
376 TDB_DATA key
, rec
, pp
;
379 key
.dptr
= blinks_id
;
380 key
.dsize
= strlen(blinks_id
);
381 rec
= tdb_fetch(pppdb
, key
);
382 if (rec
.dptr
== NULL
|| rec
.dsize
<= 0) {
383 error("bundle link list not found (iterating list)");
384 if (rec
.dptr
!= NULL
)
390 while ((q
= strchr(p
, ';')) != NULL
) {
394 pp
= tdb_fetch(pppdb
, key
);
395 if (pp
.dptr
!= NULL
&& pp
.dsize
> 0) {
396 pp
.dptr
[pp
.dsize
-1] = 0;
407 parse_num(str
, key
, valp
)
415 p
= strstr(str
, key
);
418 i
= strtol(p
, &endp
, 10);
419 if (endp
!= p
&& (*endp
== 0 || *endp
== ';')) {
428 * Check whether the pppd identified by `key' still owns ppp unit `unit'.
439 slprintf(ifkey
, sizeof(ifkey
), "IFNAME=ppp%d", unit
);
441 kd
.dsize
= strlen(ifkey
);
442 vd
= tdb_fetch(pppdb
, kd
);
443 if (vd
.dptr
!= NULL
) {
444 ret
= vd
.dsize
== key
.dsize
445 && memcmp(vd
.dptr
, key
.dptr
, vd
.dsize
) == 0;
452 get_default_epdisc(ep
)
459 /* First try for an ethernet MAC address */
460 p
= get_first_ethernet();
461 if (p
!= 0 && get_if_hwaddr(ep
->value
, p
) >= 0) {
467 /* see if our hostname corresponds to a reasonable IP address */
468 hp
= gethostbyname(hostname
);
470 addr
= *(u32_t
*)hp
->h_addr
;
471 if (!bad_ip_adrs(addr
)) {
472 addr
= lwip_ntohl(addr
);
473 if (!LOCAL_IP_ADDR(addr
)) {
475 set_ip_epdisc(ep
, addr
);
485 * epdisc_to_str - make a printable string from an endpoint discriminator.
488 static char *endp_class_names
[] = {
489 "null", "local", "IP", "MAC", "magic", "phone"
496 static char str
[MAX_ENDP_LEN
*3+8];
497 u_char
*p
= ep
->value
;
501 if (ep
->class == EPD_NULL
&& ep
->length
== 0)
503 if (ep
->class == EPD_IP
&& ep
->length
== 4) {
507 slprintf(str
, sizeof(str
), "IP:%I", lwip_htonl(addr
));
513 if (ep
->class == EPD_MAC
&& ep
->length
== 6)
515 else if (ep
->class == EPD_MAGIC
&& (ep
->length
% 4) == 0)
518 if (ep
->class <= EPD_PHONENUM
)
519 q
+= slprintf(q
, sizeof(str
)-1, "%s",
520 endp_class_names
[ep
->class]);
522 q
+= slprintf(q
, sizeof(str
)-1, "%d", ep
->class);
524 for (i
= 0; i
< ep
->length
&& i
< MAX_ENDP_LEN
; ++i
) {
525 if ((i
& mask
) == 0) {
529 q
+= slprintf(q
, str
+ sizeof(str
) - q
, "%.2x", ep
->value
[i
]);
534 static int hexc_val(int c
)
544 str_to_epdisc(ep
, str
)
551 for (i
= EPD_NULL
; i
<= EPD_PHONENUM
; ++i
) {
552 int sl
= strlen(endp_class_names
[i
]);
553 if (strncasecmp(str
, endp_class_names
[i
], sl
) == 0) {
558 if (i
> EPD_PHONENUM
) {
559 /* not a class name, try a decimal class number */
560 i
= strtol(str
, &endp
, 10);
562 return 0; /* can't parse class number */
570 if (*str
!= ':' && *str
!= '.')
576 i
= parse_dotted_ip(str
, &addr
);
577 if (i
== 0 || str
[i
] != 0)
579 set_ip_epdisc(ep
, addr
);
582 if (i
== EPD_MAC
&& get_if_hwaddr(ep
->value
, str
) >= 0) {
588 for (l
= 0; l
< MAX_ENDP_LEN
; ++l
) {
592 for (p
= str
; isxdigit(*p
); ++p
)
597 ep
->value
[l
] = hexc_val(*str
++);
599 ep
->value
[l
] = (ep
->value
[l
] << 4) + hexc_val(*str
++);
600 if (*str
== ':' || *str
== '.')
603 if (*str
!= 0 || (ep
->class == EPD_MAC
&& l
!= 6))
609 #endif /* PPP_SUPPORT && HAVE_MULTILINK */