1 /* 2 * multilink.c - support routines for multilink. 3 * 4 * Copyright (c) 2000-2001 by Sun Microsystems, Inc. 5 * All rights reserved. 6 * 7 * Copyright (c) 2000 Paul Mackerras. 8 * All rights reserved. 9 * 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. 18 */ 19 20 #include <string.h> 21 #include <ctype.h> 22 #include <stdlib.h> 23 #include <netdb.h> 24 #include <errno.h> 25 #include <signal.h> 26 #include <netinet/in.h> 27 28 #include "pppd.h" 29 #include "fsm.h" 30 #include "lcp.h" 31 32 #ifdef HAVE_MULTILINK 33 #include "tdb.h" 34 #endif 35 36 #define set_ip_epdisc(ep, addr) ( \ 37 ep->length = 4, \ 38 ep->value[0] = addr >> 24, \ 39 ep->value[1] = addr >> 16, \ 40 ep->value[2] = addr >> 8, \ 41 ep->value[3] = addr \ 42 ) 43 44 #ifdef HAVE_MULTILINK 45 bool endpoint_specified; /* user gave explicit endpoint discriminator */ 46 char *bundle_id; /* identifier for our bundle */ 47 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)); 51 52 #define process_exists(n) (kill(0, (n)) == 0 || errno != ESRCH) 53 54 void 55 mp_check_options() 56 { 57 lcp_options *wo = &lcp_wantoptions[0]; 58 lcp_options *ao = &lcp_allowoptions[0]; 59 60 if (!multilink) 61 return; 62 /* if we're doing multilink, we have to negotiate MRRU */ 63 if (!wo->neg_mrru) { 64 /* mrru not specified, default to mru */ 65 wo->mrru = wo->mru; 66 wo->neg_mrru = 1; 67 } 68 ao->mrru = ao->mru; 69 ao->neg_mrru = 1; 70 71 if (!wo->neg_endpoint && !noendpoint) { 72 /* get a default endpoint value */ 73 wo->neg_endpoint = get_default_epdisc(&wo->endpoint); 74 if (wo->neg_endpoint) 75 dbglog("using default endpoint %s", 76 epdisc_to_str(&wo->endpoint)); 77 } 78 } 79 80 /* 81 * Make a new bundle or join us to an existing bundle 82 * if we are doing multilink. 83 */ 84 int 85 mp_join_bundle() 86 { 87 lcp_options *go = &lcp_gotoptions[0]; 88 lcp_options *ho = &lcp_hisoptions[0]; 89 int unit, pppd_pid; 90 int l; 91 char *p; 92 TDB_DATA key, pid, rec; 93 94 if (!go->neg_mrru || !ho->neg_mrru) { 95 /* not doing multilink */ 96 if (go->neg_mrru) 97 notice("oops, multilink negotiated only for receive"); 98 multilink = 0; 99 if (demand) { 100 /* already have a bundle */ 101 cfg_bundle(0, 0, 0, 0); 102 return 0; 103 } 104 make_new_bundle(0, 0, 0, 0); 105 set_ifunit(1); 106 return 0; 107 } 108 109 /* 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. 114 * 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. 118 */ 119 l = 4 * strlen(peer_authname) + 10; 120 l += 3 * ho->endpoint.length + 8; 121 if (bundle_name) 122 l += 3 * strlen(bundle_name) + 2; 123 bundle_id = malloc(l); 124 if (bundle_id == NULL) 125 novm("bundle identifier"); 126 127 p = bundle_id; 128 p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); 129 *p++ = '/'; 130 p += slprintf(p, bundle_id+l-p, "%s", epdisc_to_str(&ho->endpoint)); 131 if (bundle_name) 132 p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); 133 dbglog("bundle_id = %s", bundle_id+7); 134 135 /* 136 * For demand mode, we only need to configure the bundle 137 * and attach the link. 138 */ 139 if (demand) { 140 cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); 141 script_setenv("BUNDLE", bundle_id + 7, 1); 142 return 0; 143 } 144 145 /* 146 * Check if the bundle ID is already in the database. 147 */ 148 unit = -1; 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)) 163 unit = -1; 164 free(rec.dptr); 165 } 166 free(pid.dptr); 167 } 168 169 if (unit >= 0) { 170 /* attach to existing unit */ 171 if (bundle_attach(unit)) { 172 set_ifunit(0); 173 script_setenv("BUNDLE", bundle_id + 7, 0); 174 tdb_writeunlock(pppdb); 175 info("Link attached to %s", ifname); 176 return 1; 177 } 178 /* attach failed because bundle doesn't exist */ 179 } 180 181 /* we have to make a new bundle */ 182 make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); 183 set_ifunit(1); 184 script_setenv("BUNDLE", bundle_id + 7, 1); 185 tdb_writeunlock(pppdb); 186 info("New bundle %s created", ifname); 187 return 0; 188 } 189 190 static int 191 parse_num(str, key, valp) 192 char *str; 193 const char *key; 194 int *valp; 195 { 196 char *p, *endp; 197 int i; 198 199 p = strstr(str, key); 200 if (p != 0) { 201 p += strlen(key); 202 i = strtol(p, &endp, 10); 203 if (endp != p && (*endp == 0 || *endp == ';')) { 204 *valp = i; 205 return 1; 206 } 207 } 208 return 0; 209 } 210 211 /* 212 * Check whether the pppd identified by `key' still owns ppp unit `unit'. 213 */ 214 static int 215 owns_unit(key, unit) 216 TDB_DATA key; 217 int unit; 218 { 219 char ifkey[32]; 220 TDB_DATA kd, vd; 221 int ret = 0; 222 223 (void) slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit); 224 kd.dptr = ifkey; 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; 230 free(vd.dptr); 231 } 232 return ret; 233 } 234 235 static int 236 get_default_epdisc(ep) 237 struct epdisc *ep; 238 { 239 struct hostent *hp; 240 u_int32_t addr; 241 242 if (get_first_hwaddr(ep->value, sizeof(ep->value))) { 243 ep->class = EPD_MAC; 244 ep->length = 6; 245 return 1; 246 } 247 248 /* see if our hostname corresponds to a reasonable IP address */ 249 hp = gethostbyname(hostname); 250 if (hp != NULL) { 251 addr = *(u_int32_t *)hp->h_addr; 252 if (!bad_ip_adrs(addr)) { 253 addr = ntohl(addr); 254 if (!LOCAL_IP_ADDR(addr)) { 255 ep->class = EPD_IP; 256 set_ip_epdisc(ep, addr); 257 return 1; 258 } 259 } 260 } 261 262 return 0; 263 } 264 #endif /* HAVE_MULTILINK */ 265 266 /* 267 * epdisc_to_str - make a printable string from an endpoint discriminator. 268 */ 269 270 static char *endp_class_names[] = { 271 "null", "local", "IP", "MAC", "magic", "phone" 272 }; 273 274 char * 275 epdisc_to_str(ep) 276 struct epdisc *ep; 277 { 278 static char str[MAX_ENDP_LEN*3+8]; 279 u_char *p = ep->value; 280 int i, mask = 0; 281 char *q, c, c2; 282 283 if (ep->class == EPD_NULL && ep->length == 0) 284 return "null"; 285 if (ep->class == EPD_IP && ep->length == 4) { 286 u_int32_t addr; 287 288 GETLONG(addr, p); 289 (void) slprintf(str, sizeof(str), "IP:%I", htonl(addr)); 290 return str; 291 } 292 293 c = ':'; 294 c2 = '.'; 295 if (ep->class == EPD_MAC && ep->length == 6) 296 c2 = ':'; 297 else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0) 298 mask = 3; 299 q = str; 300 if (ep->class <= EPD_PHONENUM) 301 q += slprintf(q, sizeof(str)-1, "%s", 302 endp_class_names[ep->class]); 303 else 304 q += slprintf(q, sizeof(str)-1, "%d", ep->class); 305 c = ':'; 306 for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) { 307 if ((i & mask) == 0) { 308 *q++ = c; 309 c = c2; 310 } 311 q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]); 312 } 313 return str; 314 } 315 316 static int hexc_val(int c) 317 { 318 if (c >= 'a') 319 return c - 'a' + 10; 320 if (c >= 'A') 321 return c - 'A' + 10; 322 return c - '0'; 323 } 324 325 int 326 str_to_epdisc(ep, str) 327 struct epdisc *ep; 328 char *str; 329 { 330 int i, l; 331 char *p, *endp; 332 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) { 336 str += sl; 337 break; 338 } 339 } 340 if (i > EPD_PHONENUM) { 341 /* not a class name, try a decimal class number */ 342 i = strtol(str, &endp, 10); 343 if (endp == str) { 344 option_error("cannot parse endpoint class in \"%s\"", 345 str); 346 return 0; /* can't parse class number */ 347 } 348 str = endp; 349 } 350 ep->class = i; 351 if (*str == 0) { 352 ep->length = 0; 353 return 1; 354 } 355 if (*str != ':' && *str != '.') { 356 option_error("invalid class/value separator '%c'", *str); 357 return 0; 358 } 359 ++str; 360 361 if (i == EPD_IP) { 362 u_int32_t addr; 363 i = parse_dotted_ip(str, &addr); 364 if (i == 0 || str[i] != 0) 365 return 0; 366 set_ip_epdisc(ep, addr); 367 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep)); 368 return 1; 369 } 370 if (i == EPD_MAC && 371 get_if_hwaddr(ep->value, sizeof(ep->value), str) >= 0) { 372 ep->length = 6; 373 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep)); 374 return 1; 375 } 376 377 p = str; 378 for (l = 0; l < MAX_ENDP_LEN; ++l) { 379 if (*str == 0) 380 break; 381 if (p <= str) 382 for (p = str; isxdigit(*p); ++p) 383 ; 384 i = p - str; 385 if (i == 0) { 386 option_error("no valid hex digits in \"%s\"", str); 387 return 0; 388 } 389 ep->value[l] = hexc_val(*str++); 390 if ((i & 1) == 0) 391 ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++); 392 if (*str == ':' || *str == '.') 393 ++str; 394 } 395 if (*str != 0) { 396 option_error("too many bytes in value; max is %d", 397 MAX_ENDP_LEN); 398 return 0; 399 } 400 if (ep->class == EPD_MAC && l != 6) { 401 option_error("bad endpoint; MAC address must have 6 bytes"); 402 return 0; 403 } 404 ep->length = l; 405 dbglog("str_to_epdisc -> %s", epdisc_to_str(ep)); 406 return 1; 407 } 408