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 #if !defined(lint) && !defined(_lint)
39 static const char rcsid
[] = RCSID
;
42 #define set_ip_epdisc(ep, addr) ( \
44 ep->value[0] = addr >> 24, \
45 ep->value[1] = addr >> 16, \
46 ep->value[2] = addr >> 8, \
51 bool endpoint_specified
; /* user gave explicit endpoint discriminator */
52 char *bundle_id
; /* identifier for our bundle */
54 static int get_default_epdisc
__P((struct epdisc
*));
55 static int parse_num
__P((char *str
, const char *key
, int *valp
));
56 static int owns_unit
__P((TDB_DATA pid
, int unit
));
58 #define process_exists(n) (kill(0, (n)) == 0 || errno != ESRCH)
63 lcp_options
*wo
= &lcp_wantoptions
[0];
64 lcp_options
*ao
= &lcp_allowoptions
[0];
68 /* if we're doing multilink, we have to negotiate MRRU */
70 /* mrru not specified, default to mru */
77 if (!wo
->neg_endpoint
&& !noendpoint
) {
78 /* get a default endpoint value */
79 wo
->neg_endpoint
= get_default_epdisc(&wo
->endpoint
);
81 dbglog("using default endpoint %s",
82 epdisc_to_str(&wo
->endpoint
));
87 * Make a new bundle or join us to an existing bundle
88 * if we are doing multilink.
93 lcp_options
*go
= &lcp_gotoptions
[0];
94 lcp_options
*ho
= &lcp_hisoptions
[0];
98 TDB_DATA key
, pid
, rec
;
100 if (!go
->neg_mrru
|| !ho
->neg_mrru
) {
101 /* not doing multilink */
103 notice("oops, multilink negotiated only for receive");
106 /* already have a bundle */
107 cfg_bundle(0, 0, 0, 0);
110 make_new_bundle(0, 0, 0, 0);
116 * Find the appropriate bundle or join a new one.
117 * First we make up a name for the bundle.
118 * The length estimate is worst-case assuming every
119 * character has to be quoted.
121 * Note - RFC 1990 requires that an unnegotiated endpoint
122 * discriminator value be equivalent to negotiating with class
123 * zero. Do not test ho->neg_endpoint here.
125 l
= 4 * strlen(peer_authname
) + 10;
126 l
+= 3 * ho
->endpoint
.length
+ 8;
128 l
+= 3 * strlen(bundle_name
) + 2;
129 bundle_id
= malloc(l
);
130 if (bundle_id
== NULL
)
131 novm("bundle identifier");
134 p
+= slprintf(p
, l
-1, "BUNDLE=\"%q\"", peer_authname
);
136 p
+= slprintf(p
, bundle_id
+l
-p
, "%s", epdisc_to_str(&ho
->endpoint
));
138 p
+= slprintf(p
, bundle_id
+l
-p
, "/%v", bundle_name
);
139 dbglog("bundle_id = %s", bundle_id
+7);
142 * For demand mode, we only need to configure the bundle
143 * and attach the link.
146 cfg_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
147 script_setenv("BUNDLE", bundle_id
+ 7, 1);
152 * Check if the bundle ID is already in the database.
155 tdb_writelock(pppdb
);
156 key
.dptr
= bundle_id
;
157 key
.dsize
= p
- bundle_id
;
158 pid
= tdb_fetch(pppdb
, key
);
159 if (pid
.dptr
!= NULL
) {
160 /* bundle ID exists, see if the pppd record exists */
161 rec
= tdb_fetch(pppdb
, pid
);
162 if (rec
.dptr
!= NULL
) {
163 /* it does, parse the interface number */
164 parse_num(rec
.dptr
, "IFNAME=ppp", &unit
);
165 /* check the pid value */
166 if (!parse_num(rec
.dptr
, "PPPD_PID=", &pppd_pid
)
167 || !process_exists(pppd_pid
)
168 || !owns_unit(pid
, unit
))
176 /* attach to existing unit */
177 if (bundle_attach(unit
)) {
179 script_setenv("BUNDLE", bundle_id
+ 7, 0);
180 tdb_writeunlock(pppdb
);
181 info("Link attached to %s", ifname
);
184 /* attach failed because bundle doesn't exist */
187 /* we have to make a new bundle */
188 make_new_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
190 script_setenv("BUNDLE", bundle_id
+ 7, 1);
191 tdb_writeunlock(pppdb
);
192 info("New bundle %s created", ifname
);
197 parse_num(str
, key
, valp
)
205 p
= strstr(str
, key
);
208 i
= strtol(p
, &endp
, 10);
209 if (endp
!= p
&& (*endp
== 0 || *endp
== ';')) {
218 * Check whether the pppd identified by `key' still owns ppp unit `unit'.
229 (void) slprintf(ifkey
, sizeof(ifkey
), "IFNAME=ppp%d", unit
);
231 kd
.dsize
= strlen(ifkey
);
232 vd
= tdb_fetch(pppdb
, kd
);
233 if (vd
.dptr
!= NULL
) {
234 ret
= vd
.dsize
== key
.dsize
235 && memcmp(vd
.dptr
, key
.dptr
, vd
.dsize
) == 0;
242 get_default_epdisc(ep
)
248 if (get_first_hwaddr(ep
->value
, sizeof(ep
->value
))) {
254 /* see if our hostname corresponds to a reasonable IP address */
255 hp
= gethostbyname(hostname
);
257 addr
= *(u_int32_t
*)hp
->h_addr
;
258 if (!bad_ip_adrs(addr
)) {
260 if (!LOCAL_IP_ADDR(addr
)) {
262 set_ip_epdisc(ep
, addr
);
270 #endif /* HAVE_MULTILINK */
273 * epdisc_to_str - make a printable string from an endpoint discriminator.
276 static char *endp_class_names
[] = {
277 "null", "local", "IP", "MAC", "magic", "phone"
284 static char str
[MAX_ENDP_LEN
*3+8];
285 u_char
*p
= ep
->value
;
289 if (ep
->class == EPD_NULL
&& ep
->length
== 0)
291 if (ep
->class == EPD_IP
&& ep
->length
== 4) {
295 (void) slprintf(str
, sizeof(str
), "IP:%I", htonl(addr
));
301 if (ep
->class == EPD_MAC
&& ep
->length
== 6)
303 else if (ep
->class == EPD_MAGIC
&& (ep
->length
% 4) == 0)
306 if (ep
->class <= EPD_PHONENUM
)
307 q
+= slprintf(q
, sizeof(str
)-1, "%s",
308 endp_class_names
[ep
->class]);
310 q
+= slprintf(q
, sizeof(str
)-1, "%d", ep
->class);
312 for (i
= 0; i
< ep
->length
&& i
< MAX_ENDP_LEN
; ++i
) {
313 if ((i
& mask
) == 0) {
317 q
+= slprintf(q
, str
+ sizeof(str
) - q
, "%.2x", ep
->value
[i
]);
322 static int hexc_val(int c
)
332 str_to_epdisc(ep
, str
)
339 for (i
= EPD_NULL
; i
<= EPD_PHONENUM
; ++i
) {
340 int sl
= strlen(endp_class_names
[i
]);
341 if (strncasecmp(str
, endp_class_names
[i
], sl
) == 0) {
346 if (i
> EPD_PHONENUM
) {
347 /* not a class name, try a decimal class number */
348 i
= strtol(str
, &endp
, 10);
350 option_error("cannot parse endpoint class in \"%s\"",
352 return 0; /* can't parse class number */
361 if (*str
!= ':' && *str
!= '.') {
362 option_error("invalid class/value separator '%c'", *str
);
369 i
= parse_dotted_ip(str
, &addr
);
370 if (i
== 0 || str
[i
] != 0)
372 set_ip_epdisc(ep
, addr
);
373 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));
377 get_if_hwaddr(ep
->value
, sizeof(ep
->value
), str
) >= 0) {
379 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));
384 for (l
= 0; l
< MAX_ENDP_LEN
; ++l
) {
388 for (p
= str
; isxdigit(*p
); ++p
)
392 option_error("no valid hex digits in \"%s\"", str
);
395 ep
->value
[l
] = hexc_val(*str
++);
397 ep
->value
[l
] = (ep
->value
[l
] << 4) + hexc_val(*str
++);
398 if (*str
== ':' || *str
== '.')
402 option_error("too many bytes in value; max is %d",
406 if (ep
->class == EPD_MAC
&& l
!= 6) {
407 option_error("bad endpoint; MAC address must have 6 bytes");
411 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));