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.
26 #include <netinet/in.h>
36 #define set_ip_epdisc(ep, addr) ( \
38 ep->value[0] = addr >> 24, \
39 ep->value[1] = addr >> 16, \
40 ep->value[2] = addr >> 8, \
45 bool endpoint_specified
; /* user gave explicit endpoint discriminator */
46 char *bundle_id
; /* identifier for our bundle */
48 static int get_default_epdisc
__P((struct epdisc
*));
49 static int parse_num
__P((char *str
, const char *key
, int *valp
));
50 static int owns_unit
__P((TDB_DATA pid
, int unit
));
52 #define process_exists(n) (kill(0, (n)) == 0 || errno != ESRCH)
57 lcp_options
*wo
= &lcp_wantoptions
[0];
58 lcp_options
*ao
= &lcp_allowoptions
[0];
62 /* if we're doing multilink, we have to negotiate MRRU */
64 /* mrru not specified, default to mru */
71 if (!wo
->neg_endpoint
&& !noendpoint
) {
72 /* get a default endpoint value */
73 wo
->neg_endpoint
= get_default_epdisc(&wo
->endpoint
);
75 dbglog("using default endpoint %s",
76 epdisc_to_str(&wo
->endpoint
));
81 * Make a new bundle or join us to an existing bundle
82 * if we are doing multilink.
87 lcp_options
*go
= &lcp_gotoptions
[0];
88 lcp_options
*ho
= &lcp_hisoptions
[0];
92 TDB_DATA key
, pid
, rec
;
94 if (!go
->neg_mrru
|| !ho
->neg_mrru
) {
95 /* not doing multilink */
97 notice("oops, multilink negotiated only for receive");
100 /* already have a bundle */
101 cfg_bundle(0, 0, 0, 0);
104 make_new_bundle(0, 0, 0, 0);
110 * Find the appropriate bundle or join a new one.
111 * First we make up a name for the bundle.
112 * The length estimate is worst-case assuming every
113 * character has to be quoted.
115 * Note - RFC 1990 requires that an unnegotiated endpoint
116 * discriminator value be equivalent to negotiating with class
117 * zero. Do not test ho->neg_endpoint here.
119 l
= 4 * strlen(peer_authname
) + 10;
120 l
+= 3 * ho
->endpoint
.length
+ 8;
122 l
+= 3 * strlen(bundle_name
) + 2;
123 bundle_id
= malloc(l
);
124 if (bundle_id
== NULL
)
125 novm("bundle identifier");
128 p
+= slprintf(p
, l
-1, "BUNDLE=\"%q\"", peer_authname
);
130 p
+= slprintf(p
, bundle_id
+l
-p
, "%s", epdisc_to_str(&ho
->endpoint
));
132 p
+= slprintf(p
, bundle_id
+l
-p
, "/%v", bundle_name
);
133 dbglog("bundle_id = %s", bundle_id
+7);
136 * For demand mode, we only need to configure the bundle
137 * and attach the link.
140 cfg_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
141 script_setenv("BUNDLE", bundle_id
+ 7, 1);
146 * Check if the bundle ID is already in the database.
149 tdb_writelock(pppdb
);
150 key
.dptr
= bundle_id
;
151 key
.dsize
= p
- bundle_id
;
152 pid
= tdb_fetch(pppdb
, key
);
153 if (pid
.dptr
!= NULL
) {
154 /* bundle ID exists, see if the pppd record exists */
155 rec
= tdb_fetch(pppdb
, pid
);
156 if (rec
.dptr
!= NULL
) {
157 /* it does, parse the interface number */
158 parse_num(rec
.dptr
, "IFNAME=ppp", &unit
);
159 /* check the pid value */
160 if (!parse_num(rec
.dptr
, "PPPD_PID=", &pppd_pid
)
161 || !process_exists(pppd_pid
)
162 || !owns_unit(pid
, unit
))
170 /* attach to existing unit */
171 if (bundle_attach(unit
)) {
173 script_setenv("BUNDLE", bundle_id
+ 7, 0);
174 tdb_writeunlock(pppdb
);
175 info("Link attached to %s", ifname
);
178 /* attach failed because bundle doesn't exist */
181 /* we have to make a new bundle */
182 make_new_bundle(go
->mrru
, ho
->mrru
, go
->neg_ssnhf
, ho
->neg_ssnhf
);
184 script_setenv("BUNDLE", bundle_id
+ 7, 1);
185 tdb_writeunlock(pppdb
);
186 info("New bundle %s created", ifname
);
191 parse_num(str
, key
, valp
)
199 p
= strstr(str
, key
);
202 i
= strtol(p
, &endp
, 10);
203 if (endp
!= p
&& (*endp
== 0 || *endp
== ';')) {
212 * Check whether the pppd identified by `key' still owns ppp unit `unit'.
223 (void) slprintf(ifkey
, sizeof(ifkey
), "IFNAME=ppp%d", unit
);
225 kd
.dsize
= strlen(ifkey
);
226 vd
= tdb_fetch(pppdb
, kd
);
227 if (vd
.dptr
!= NULL
) {
228 ret
= vd
.dsize
== key
.dsize
229 && memcmp(vd
.dptr
, key
.dptr
, vd
.dsize
) == 0;
236 get_default_epdisc(ep
)
242 if (get_first_hwaddr(ep
->value
, sizeof(ep
->value
))) {
248 /* see if our hostname corresponds to a reasonable IP address */
249 hp
= gethostbyname(hostname
);
251 addr
= *(u_int32_t
*)hp
->h_addr
;
252 if (!bad_ip_adrs(addr
)) {
254 if (!LOCAL_IP_ADDR(addr
)) {
256 set_ip_epdisc(ep
, addr
);
264 #endif /* HAVE_MULTILINK */
267 * epdisc_to_str - make a printable string from an endpoint discriminator.
270 static char *endp_class_names
[] = {
271 "null", "local", "IP", "MAC", "magic", "phone"
278 static char str
[MAX_ENDP_LEN
*3+8];
279 u_char
*p
= ep
->value
;
283 if (ep
->class == EPD_NULL
&& ep
->length
== 0)
285 if (ep
->class == EPD_IP
&& ep
->length
== 4) {
289 (void) slprintf(str
, sizeof(str
), "IP:%I", htonl(addr
));
295 if (ep
->class == EPD_MAC
&& ep
->length
== 6)
297 else if (ep
->class == EPD_MAGIC
&& (ep
->length
% 4) == 0)
300 if (ep
->class <= EPD_PHONENUM
)
301 q
+= slprintf(q
, sizeof(str
)-1, "%s",
302 endp_class_names
[ep
->class]);
304 q
+= slprintf(q
, sizeof(str
)-1, "%d", ep
->class);
306 for (i
= 0; i
< ep
->length
&& i
< MAX_ENDP_LEN
; ++i
) {
307 if ((i
& mask
) == 0) {
311 q
+= slprintf(q
, str
+ sizeof(str
) - q
, "%.2x", ep
->value
[i
]);
316 static int hexc_val(int c
)
326 str_to_epdisc(ep
, str
)
333 for (i
= EPD_NULL
; i
<= EPD_PHONENUM
; ++i
) {
334 int sl
= strlen(endp_class_names
[i
]);
335 if (strncasecmp(str
, endp_class_names
[i
], sl
) == 0) {
340 if (i
> EPD_PHONENUM
) {
341 /* not a class name, try a decimal class number */
342 i
= strtol(str
, &endp
, 10);
344 option_error("cannot parse endpoint class in \"%s\"",
346 return 0; /* can't parse class number */
355 if (*str
!= ':' && *str
!= '.') {
356 option_error("invalid class/value separator '%c'", *str
);
363 i
= parse_dotted_ip(str
, &addr
);
364 if (i
== 0 || str
[i
] != 0)
366 set_ip_epdisc(ep
, addr
);
367 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));
371 get_if_hwaddr(ep
->value
, sizeof(ep
->value
), str
) >= 0) {
373 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));
378 for (l
= 0; l
< MAX_ENDP_LEN
; ++l
) {
382 for (p
= str
; isxdigit(*p
); ++p
)
386 option_error("no valid hex digits in \"%s\"", str
);
389 ep
->value
[l
] = hexc_val(*str
++);
391 ep
->value
[l
] = (ep
->value
[l
] << 4) + hexc_val(*str
++);
392 if (*str
== ':' || *str
== '.')
396 option_error("too many bytes in value; max is %d",
400 if (ep
->class == EPD_MAC
&& l
!= 6) {
401 option_error("bad endpoint; MAC address must have 6 bytes");
405 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep
));