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