2 * multilink.c - support routines for multilink.
4 * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
7 * Copyright (c) 2000 Paul Mackerras.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms. The name of the author may not be
13 * used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 #pragma ident "%Z%%M% %I% %E% SMI"
21 #define RCSID "$Id: $"
29 #include <netinet/in.h>
38 static const char rcsid
[] = RCSID
;
40 #define set_ip_epdisc(ep, addr) ( \
42 ep->value[0] = addr >> 24, \
43 ep->value[1] = addr >> 16, \
44 ep->value[2] = addr >> 8, \
49 bool endpoint_specified
; /* user gave explicit endpoint discriminator */
50 char *bundle_id
; /* identifier for our bundle */
52 static int get_default_epdisc
__P((struct epdisc
*));
53 static int parse_num
__P((char *str
, const char *key
, int *valp
));
54 static int owns_unit
__P((TDB_DATA pid
, int unit
));
56 #define process_exists(n) (kill(0, (n)) == 0 || errno != ESRCH)
61 lcp_options
*wo
= &lcp_wantoptions
[0];
62 lcp_options
*ao
= &lcp_allowoptions
[0];
66 /* if we're doing multilink, we have to negotiate MRRU */
68 /* mrru not specified, default to mru */
75 if (!wo
->neg_endpoint
&& !noendpoint
) {
76 /* get a default endpoint value */
77 wo
->neg_endpoint
= get_default_epdisc(&wo
->endpoint
);
79 dbglog("using default endpoint %s",
80 epdisc_to_str(&wo
->endpoint
));
85 * Make a new bundle or join us to an existing bundle
86 * if we are doing multilink.
91 lcp_options
*go
= &lcp_gotoptions
[0];
92 lcp_options
*ho
= &lcp_hisoptions
[0];
96 TDB_DATA key
, pid
, rec
;
98 if (!go
->neg_mrru
|| !ho
->neg_mrru
) {
99 /* not doing multilink */
101 notice("oops, multilink negotiated only for receive");
104 /* already have a bundle */
105 cfg_bundle(0, 0, 0, 0);
108 make_new_bundle(0, 0, 0, 0);
114 * Find the appropriate bundle or join a new one.
115 * First we make up a name for the bundle.
116 * The length estimate is worst-case assuming every
117 * character has to be quoted.
119 * Note - RFC 1990 requires that an unnegotiated endpoint
120 * discriminator value be equivalent to negotiating with class
121 * zero. Do not test ho->neg_endpoint here.
123 l
= 4 * strlen(peer_authname
) + 10;
124 l
+= 3 * ho
->endpoint
.length
+ 8;
126 l
+= 3 * strlen(bundle_name
) + 2;
127 bundle_id
= malloc(l
);
128 if (bundle_id
== NULL
)
129 novm("bundle identifier");
132 p
+= slprintf(p
, l
-1, "BUNDLE=\"%q\"", peer_authname
);
134 p
+= slprintf(p
, bundle_id
+l
-p
, "%s", epdisc_to_str(&ho
->endpoint
));
136 p
+= slprintf(p
, bundle_id
+l
-p
, "/%v", bundle_name
);
137 dbglog("bundle_id = %s", bundle_id
+7);
140 * For demand mode, we only need to configure the bundle
141 * and attach the link.
144 cfg_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
145 script_setenv("BUNDLE", bundle_id
+ 7, 1);
150 * Check if the bundle ID is already in the database.
153 tdb_writelock(pppdb
);
154 key
.dptr
= bundle_id
;
155 key
.dsize
= p
- bundle_id
;
156 pid
= tdb_fetch(pppdb
, key
);
157 if (pid
.dptr
!= NULL
) {
158 /* bundle ID exists, see if the pppd record exists */
159 rec
= tdb_fetch(pppdb
, pid
);
160 if (rec
.dptr
!= NULL
) {
161 /* it does, parse the interface number */
162 parse_num(rec
.dptr
, "IFNAME=ppp", &unit
);
163 /* check the pid value */
164 if (!parse_num(rec
.dptr
, "PPPD_PID=", &pppd_pid
)
165 || !process_exists(pppd_pid
)
166 || !owns_unit(pid
, unit
))
174 /* attach to existing unit */
175 if (bundle_attach(unit
)) {
177 script_setenv("BUNDLE", bundle_id
+ 7, 0);
178 tdb_writeunlock(pppdb
);
179 info("Link attached to %s", ifname
);
182 /* attach failed because bundle doesn't exist */
185 /* we have to make a new bundle */
186 make_new_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
188 script_setenv("BUNDLE", bundle_id
+ 7, 1);
189 tdb_writeunlock(pppdb
);
190 info("New bundle %s created", ifname
);
195 parse_num(str
, key
, valp
)
203 p
= strstr(str
, key
);
206 i
= strtol(p
, &endp
, 10);
207 if (endp
!= p
&& (*endp
== 0 || *endp
== ';')) {
216 * Check whether the pppd identified by `key' still owns ppp unit `unit'.
227 (void) slprintf(ifkey
, sizeof(ifkey
), "IFNAME=ppp%d", unit
);
229 kd
.dsize
= strlen(ifkey
);
230 vd
= tdb_fetch(pppdb
, kd
);
231 if (vd
.dptr
!= NULL
) {
232 ret
= vd
.dsize
== key
.dsize
233 && memcmp(vd
.dptr
, key
.dptr
, vd
.dsize
) == 0;
240 get_default_epdisc(ep
)
246 if (get_first_hwaddr(ep
->value
, sizeof(ep
->value
))) {
252 /* see if our hostname corresponds to a reasonable IP address */
253 hp
= gethostbyname(hostname
);
255 addr
= *(u_int32_t
*)hp
->h_addr
;
256 if (!bad_ip_adrs(addr
)) {
258 if (!LOCAL_IP_ADDR(addr
)) {
260 set_ip_epdisc(ep
, addr
);
268 #endif /* HAVE_MULTILINK */
271 * epdisc_to_str - make a printable string from an endpoint discriminator.
274 static char *endp_class_names
[] = {
275 "null", "local", "IP", "MAC", "magic", "phone"
282 static char str
[MAX_ENDP_LEN
*3+8];
283 u_char
*p
= ep
->value
;
287 if (ep
->class == EPD_NULL
&& ep
->length
== 0)
289 if (ep
->class == EPD_IP
&& ep
->length
== 4) {
293 (void) slprintf(str
, sizeof(str
), "IP:%I", htonl(addr
));
299 if (ep
->class == EPD_MAC
&& ep
->length
== 6)
301 else if (ep
->class == EPD_MAGIC
&& (ep
->length
% 4) == 0)
304 if (ep
->class <= EPD_PHONENUM
)
305 q
+= slprintf(q
, sizeof(str
)-1, "%s",
306 endp_class_names
[ep
->class]);
308 q
+= slprintf(q
, sizeof(str
)-1, "%d", ep
->class);
310 for (i
= 0; i
< ep
->length
&& i
< MAX_ENDP_LEN
; ++i
) {
311 if ((i
& mask
) == 0) {
315 q
+= slprintf(q
, str
+ sizeof(str
) - q
, "%.2x", ep
->value
[i
]);
320 static int hexc_val(int c
)
330 str_to_epdisc(ep
, str
)
337 for (i
= EPD_NULL
; i
<= EPD_PHONENUM
; ++i
) {
338 int sl
= strlen(endp_class_names
[i
]);
339 if (strncasecmp(str
, endp_class_names
[i
], sl
) == 0) {
344 if (i
> EPD_PHONENUM
) {
345 /* not a class name, try a decimal class number */
346 i
= strtol(str
, &endp
, 10);
348 option_error("cannot parse endpoint class in \"%s\"",
350 return 0; /* can't parse class number */
359 if (*str
!= ':' && *str
!= '.') {
360 option_error("invalid class/value separator '%c'", *str
);
367 i
= parse_dotted_ip(str
, &addr
);
368 if (i
== 0 || str
[i
] != 0)
370 set_ip_epdisc(ep
, addr
);
371 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));
375 get_if_hwaddr(ep
->value
, sizeof(ep
->value
), str
) >= 0) {
377 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));
382 for (l
= 0; l
< MAX_ENDP_LEN
; ++l
) {
386 for (p
= str
; isxdigit(*p
); ++p
)
390 option_error("no valid hex digits in \"%s\"", str
);
393 ep
->value
[l
] = hexc_val(*str
++);
395 ep
->value
[l
] = (ep
->value
[l
] << 4) + hexc_val(*str
++);
396 if (*str
== ':' || *str
== '.')
400 option_error("too many bytes in value; max is %d",
404 if (ep
->class == EPD_MAC
&& l
!= 6) {
405 option_error("bad endpoint; MAC address must have 6 bytes");
409 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));