1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This file is here for legacy support. 29 */ 30 31 #include <atomic.h> 32 #include <ctype.h> 33 #include <errno.h> 34 #include <limits.h> 35 #include <libdllink.h> 36 #include <libscf.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <strings.h> 41 42 #include <libnwam.h> 43 #include "known_wlans.h" 44 #include "llp.h" 45 #include "ncu.h" 46 #include "util.h" 47 48 /* 49 * This file formerly contained the routines that manipulate Link Layer 50 * Profiles (aka LLPs) and various support functions. Now only code 51 * necessary for parsing the legacy /etc/nwam/llp file on upgrade is included, 52 * since this legacy configuration needs to be translated into the User NCP. 53 */ 54 55 #define OUR_OLD_DHCP_WAIT_TIME_PROP_NAME "dhcp_wait_time" 56 #define OUR_OLD_USE_NET_SVC_PROP_NAME "use_net_svc" 57 #define OUR_OLD_IDLE_TIME_PROP_NAME "idle_time" 58 59 static struct qelem llp_list; 60 61 /* 62 * Global variable to hold the highest priority. Need to use the atomic 63 * integer arithmetic functions to update it. 64 */ 65 static uint32_t llp_highest_pri; 66 67 /* Specifies if static address has been configured in /etc/nwam/llp */ 68 static boolean_t static_configured = B_FALSE; 69 70 static enum interface_type 71 find_if_type(const char *name) 72 { 73 uint32_t media; 74 enum interface_type type; 75 76 if (name == NULL) { 77 nlog(LOG_DEBUG, "find_if_type: no ifname; " 78 "returning IF_UNKNOWN"); 79 return (IF_UNKNOWN); 80 } 81 82 type = IF_WIRED; 83 if (dladm_name2info(dld_handle, name, NULL, NULL, NULL, &media) != 84 DLADM_STATUS_OK) { 85 if (strncmp(name, "ip.tun", 6) == 0 || 86 strncmp(name, "ip6.tun", 7) == 0 || 87 strncmp(name, "ip.6to4tun", 10) == 0) 88 /* 89 * We'll need to update our tunnel detection once 90 * the clearview/tun project is integrated; tunnel 91 * names won't necessarily be ip.tunN. 92 */ 93 type = IF_TUN; 94 } else if (media == DL_WIFI) { 95 type = IF_WIRELESS; 96 } 97 98 return (type); 99 } 100 101 static void 102 llp_list_free(void) 103 { 104 llp_t *llp; 105 106 while (llp_list.q_forw != &llp_list) { 107 llp = (llp_t *)llp_list.q_forw; 108 remque(&llp->llp_links); 109 free(llp->llp_ipv6addrstr); 110 free(llp->llp_ipv4addrstr); 111 free(llp); 112 } 113 } 114 115 static void 116 initialize_llp(void) 117 { 118 llp_list.q_forw = llp_list.q_back = &llp_list; 119 } 120 121 static llp_t * 122 llp_lookup(const char *link) 123 { 124 llp_t *llp; 125 126 if (link == NULL) 127 return (NULL); 128 129 for (llp = (llp_t *)llp_list.q_forw; llp != (llp_t *)&llp_list; 130 llp = (llp_t *)llp->llp_links.q_forw) { 131 if (strcmp(link, llp->llp_lname) == 0) 132 break; 133 } 134 if (llp == (llp_t *)&llp_list) 135 llp = NULL; 136 return (llp); 137 } 138 139 /* 140 * Create the named LLP with default settings. Called only in main thread. 141 */ 142 static llp_t * 143 llp_add(const char *name) 144 { 145 llp_t *llp; 146 147 if ((llp = calloc(1, sizeof (llp_t))) == NULL) { 148 nlog(LOG_ERR, "llp_add: cannot allocate LLP: %m"); 149 return (NULL); 150 } 151 152 if (strlcpy(llp->llp_lname, name, sizeof (llp->llp_lname)) >= 153 sizeof (llp->llp_lname)) { 154 nlog(LOG_ERR, "llp_add: linkname '%s' too long; ignoring entry", 155 name); 156 free(llp); 157 return (NULL); 158 } 159 160 llp->llp_fileorder = llp->llp_pri = 161 atomic_add_32_nv(&llp_highest_pri, 1); 162 llp->llp_ipv4src = IPV4SRC_DHCP; 163 llp->llp_type = find_if_type(llp->llp_lname); 164 llp->llp_ipv6onlink = B_TRUE; 165 166 /* 167 * should be a no-op, but for now, make sure we only 168 * create llps for wired and wireless interfaces. 169 */ 170 if (llp->llp_type != IF_WIRED && llp->llp_type != IF_WIRELESS) { 171 nlog(LOG_ERR, "llp_add: wrong type of interface for %s", name); 172 free(llp); 173 return (NULL); 174 } 175 insque(&llp->llp_links, llp_list.q_back); 176 177 nlog(LOG_DEBUG, "llp_add: " 178 "created llp for link %s, priority %d", llp->llp_lname, 179 llp->llp_pri); 180 return (llp); 181 } 182 183 static int 184 parse_llp_config(void) 185 { 186 static const char STATICSTR[] = "static"; 187 static const char DHCP[] = "dhcp"; 188 static const char IPV6[] = "ipv6"; 189 static const char NOIPV6[] = "noipv6"; 190 static const char PRIORITY[] = "priority"; 191 FILE *fp; 192 char line[LINE_MAX]; 193 char *cp, *lasts, *lstr, *srcstr, *addrstr; 194 int lnum; 195 llp_t *llp; 196 197 initialize_llp(); 198 199 fp = fopen(LLPFILE, "r+"); 200 if (fp == NULL) { 201 if (errno == ENOENT) 202 return (errno); 203 nlog(LOG_ERR, "parse_llp_config: " 204 "open legacy LLP config file: %m"); 205 return (-1); 206 } 207 208 for (lnum = 1; fgets(line, sizeof (line), fp) != NULL; lnum++) { 209 if (line[strlen(line) - 1] == '\n') 210 line[strlen(line) - 1] = '\0'; 211 212 cp = line; 213 while (isspace(*cp)) 214 cp++; 215 216 if (*cp == '#' || *cp == '\0') 217 continue; 218 219 nlog(LOG_DEBUG, "parse_llp_config: " 220 "parsing legacy LLP conf file line %d...", lnum); 221 222 if (((lstr = strtok_r(cp, " \t", &lasts)) == NULL) || 223 ((srcstr = strtok_r(NULL, " \t", &lasts)) == NULL)) { 224 nlog(LOG_ERR, "parse_llp_config: line %d: " 225 "not enough tokens; ignoring entry", lnum); 226 continue; 227 } 228 229 if ((llp = llp_lookup(lstr)) == NULL && 230 (llp = llp_add(lstr)) == NULL) { 231 nlog(LOG_ERR, "parse_llp_config: line %d: " 232 "cannot add entry", lnum); 233 continue; 234 } 235 236 if (strcasecmp(srcstr, STATICSTR) == 0) { 237 if ((addrstr = strtok_r(NULL, " \t", &lasts)) == NULL || 238 atoi(addrstr) == 0) { /* crude check for number */ 239 nlog(LOG_ERR, "parse_llp_config: line %d: " 240 "missing ipaddr for static config", lnum); 241 } else if ((addrstr = strdup(addrstr)) == NULL) { 242 nlog(LOG_ERR, "parse_llp_config: line %d: " 243 "cannot save address", lnum); 244 } else { 245 free(llp->llp_ipv4addrstr); 246 llp->llp_ipv4src = IPV4SRC_STATIC; 247 llp->llp_ipv4addrstr = addrstr; 248 } 249 250 } else if (strcasecmp(srcstr, DHCP) == 0) { 251 llp->llp_ipv4src = IPV4SRC_DHCP; 252 253 } else if (strcasecmp(srcstr, IPV6) == 0) { 254 llp->llp_ipv6onlink = B_TRUE; 255 if ((addrstr = strtok_r(NULL, " \t", &lasts)) == NULL) { 256 (void) 0; 257 } else if ((addrstr = strdup(addrstr)) == NULL) { 258 nlog(LOG_ERR, "parse_llp_config: line %d: " 259 "cannot save address", lnum); 260 } else { 261 free(llp->llp_ipv6addrstr); 262 llp->llp_ipv6addrstr = addrstr; 263 } 264 265 } else if (strcasecmp(srcstr, NOIPV6) == 0) { 266 llp->llp_ipv6onlink = B_FALSE; 267 268 } else if (strcasecmp(srcstr, PRIORITY) == 0) { 269 if ((addrstr = strtok_r(NULL, " \t", &lasts)) == NULL) { 270 nlog(LOG_ERR, 271 "parse_llp_config: line %d: " 272 "missing priority value", lnum); 273 } else { 274 llp->llp_pri = atoi(addrstr); 275 } 276 277 } else { 278 nlog(LOG_ERR, "parse_llp_config: line %d: " 279 "unrecognized field '%s'", lnum, srcstr); 280 } 281 } 282 283 (void) fclose(fp); 284 return (0); 285 } 286 287 /* 288 * Translate legacy LLP config into the user NCP. 289 */ 290 static int 291 upgrade_llp_config(void) 292 { 293 llp_t *wp; 294 nwam_ncp_handle_t user_ncp; 295 nwam_ncu_handle_t phys_ncu = NULL, ip_ncu = NULL; 296 nwam_error_t err; 297 uint64_t uintval; 298 char *strval; 299 const char *prop; 300 301 switch (parse_llp_config()) { 302 case -1: 303 return (0); 304 case ENOENT: 305 return (ENOENT); 306 default: 307 break; 308 } 309 if ((err = nwam_ncp_create(NWAM_NCP_NAME_USER, 0, &user_ncp)) 310 != NWAM_SUCCESS) { 311 nlog(LOG_ERR, "upgrade_llp_config: " 312 "could not create user NCP: %s", nwam_strerror(err)); 313 llp_list_free(); 314 return (0); 315 } 316 317 nlog(LOG_DEBUG, "upgrade_llp_config: walking llp list"); 318 319 for (wp = (llp_t *)llp_list.q_forw; wp != (llp_t *)&llp_list; 320 wp = (llp_t *)wp->llp_links.q_forw) { 321 322 nlog(LOG_DEBUG, "upgrade_llp_config: " 323 "upgrading llp %s", wp->llp_lname); 324 325 if (nwam_ncu_create(user_ncp, wp->llp_lname, 326 NWAM_NCU_TYPE_INTERFACE, NWAM_NCU_CLASS_IP, &ip_ncu) 327 != NWAM_SUCCESS || 328 nwam_ncu_create(user_ncp, wp->llp_lname, NWAM_NCU_TYPE_LINK, 329 NWAM_NCU_CLASS_PHYS, &phys_ncu) != NWAM_SUCCESS) { 330 nlog(LOG_ERR, "upgrade_llp_config: llp %s: " 331 "could not create NCUs: %s", wp->llp_lname, 332 nwam_strerror(err)); 333 break; 334 } 335 336 /* Link NCU properties */ 337 prop = NWAM_NCU_PROP_ACTIVATION_MODE; 338 uintval = NWAM_ACTIVATION_MODE_PRIORITIZED; 339 if ((err = nwamd_set_ncu_uint(phys_ncu, &uintval, 1, prop)) 340 != NWAM_SUCCESS) 341 break; 342 343 prop = NWAM_NCU_PROP_PRIORITY_MODE; 344 uintval = NWAM_PRIORITY_MODE_EXCLUSIVE; 345 if ((err = nwamd_set_ncu_uint(phys_ncu, &uintval, 1, prop)) 346 != NWAM_SUCCESS) 347 break; 348 349 prop = NWAM_NCU_PROP_PRIORITY_GROUP; 350 uintval = wp->llp_pri; 351 if ((err = nwamd_set_ncu_uint(phys_ncu, &uintval, 1, prop)) 352 != NWAM_SUCCESS) 353 break; 354 355 /* IP NCU properties */ 356 if (wp->llp_ipv4addrstr != NULL) { 357 /* Set v4 address and specify static addrsrc */ 358 prop = NWAM_NCU_PROP_IPV4_ADDRSRC; 359 uintval = NWAM_ADDRSRC_STATIC; 360 if ((err = nwamd_set_ncu_uint(ip_ncu, &uintval, 1, 361 prop)) != NWAM_SUCCESS) 362 break; 363 364 prop = NWAM_NCU_PROP_IPV4_ADDR; 365 strval = wp->llp_ipv4addrstr; 366 if ((err = nwamd_set_ncu_string(ip_ncu, &strval, 1, 367 prop)) != NWAM_SUCCESS) 368 break; 369 370 static_configured = B_TRUE; 371 } 372 373 if (wp->llp_ipv6addrstr != NULL) { 374 /* Set v6 address and specify static addrsrc */ 375 prop = NWAM_NCU_PROP_IPV6_ADDRSRC; 376 uintval = NWAM_ADDRSRC_STATIC; 377 if ((err = nwamd_set_ncu_uint(ip_ncu, &uintval, 1, 378 prop)) != NWAM_SUCCESS) 379 break; 380 381 prop = NWAM_NCU_PROP_IPV6_ADDR; 382 strval = wp->llp_ipv6addrstr; 383 if ((err = nwamd_set_ncu_string(ip_ncu, &strval, 1, 384 prop)) != NWAM_SUCCESS) 385 break; 386 387 static_configured = B_TRUE; 388 } 389 390 if (!wp->llp_ipv6onlink) { 391 prop = NWAM_NCU_PROP_IP_VERSION; 392 uintval = IPV4_VERSION; 393 if ((err = nwamd_set_ncu_uint(ip_ncu, &uintval, 1, 394 prop)) != NWAM_SUCCESS) 395 break; 396 } 397 398 if ((err = nwam_ncu_commit(ip_ncu, 0)) != NWAM_SUCCESS || 399 (err = nwam_ncu_commit(phys_ncu, 0)) != NWAM_SUCCESS) { 400 nlog(LOG_ERR, "upgrade_llp_config: llp %s: " 401 "could not commit NCUs: %s", wp->llp_lname, 402 nwam_strerror(err)); 403 /* Schedule a retry - root filesystem may be readonly */ 404 llp_list_free(); 405 return (EAGAIN); 406 } 407 nwam_ncu_free(ip_ncu); 408 nwam_ncu_free(phys_ncu); 409 } 410 411 if (err != NWAM_SUCCESS) { 412 nlog(LOG_ERR, "upgrade_llp_config: llp %s: " 413 "could not set value for property %s: %s", wp->llp_lname, 414 prop, nwam_strerror(err)); 415 nwam_ncu_free(ip_ncu); 416 nwam_ncu_free(phys_ncu); 417 exit(EXIT_FAILURE); 418 } 419 llp_list_free(); 420 return (0); 421 } 422 423 /* 424 * Upgrade legacy llp and known_wifi_nets files. Note - it is possible that 425 * the root filesystem is not writable at this point, so we need to schedule 426 * a retry of the upgrade operation in the event that committing the new 427 * config fails. 428 */ 429 /* ARGSUSED0 */ 430 void 431 nwamd_handle_upgrade(nwamd_event_t event) 432 { 433 nwamd_event_t upgrade_event; 434 uint64_t dhcp_wait_time, idle_time; 435 boolean_t use_net_svc; 436 437 switch (upgrade_llp_config()) { 438 case -1: 439 case ENOENT: 440 /* Nothing readable to upgrade */ 441 break; 442 case EAGAIN: 443 /* 444 * Schedule retry in NWAMD_READONLY_RETRY_INTERVAL seconds 445 * as root fs may be readonly. 446 * 447 * The upgrade event is of type NCU, but has no associated 448 * object (we use the event type to map to the appropriate 449 * event/method mappings, so to find the NCU upgrade event 450 * method we specify type NCU while not specifying an 451 * object since all NCUs have to be upgraded. 452 */ 453 upgrade_event = nwamd_event_init(NWAM_EVENT_TYPE_UPGRADE, 454 NWAM_OBJECT_TYPE_NCP, 0, NULL); 455 if (upgrade_event == NULL) 456 return; 457 nwamd_event_enqueue_timed(upgrade_event, 458 NWAMD_READONLY_RETRY_INTERVAL); 459 return; 460 default: 461 break; 462 } 463 464 /* 465 * If static_configured is set, then at least one static address is 466 * configured in /etc/nwam/llp. Enable the User NCP in this case. 467 */ 468 if (static_configured) { 469 nlog(LOG_DEBUG, "nwamd_handle_upgrade: " 470 "static address configured, enabling User NCP"); 471 (void) pthread_mutex_lock(&active_ncp_mutex); 472 (void) strlcpy(active_ncp, NWAM_NCP_NAME_USER, 473 NWAM_MAX_NAME_LEN); 474 (void) pthread_mutex_unlock(&active_ncp_mutex); 475 } 476 477 /* upgrade /etc/nwam/known_wifi_nets */ 478 upgrade_known_wifi_nets_config(); 479 480 /* 481 * SMF property nwamd/dhcp_wait_time in Phase 0/0.5 has been 482 * replaced by nwamd/ncu_wait_time property. If the dhcp_wait_time 483 * property exists (which means it has been changed by the user), 484 * set its value to ncu_wait_time and remove the property. 485 */ 486 if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG, 487 OUR_OLD_DHCP_WAIT_TIME_PROP_NAME, &dhcp_wait_time) == 0) { 488 (void) nwamd_set_count_property(OUR_FMRI, OUR_PG, 489 OUR_NCU_WAIT_TIME_PROP_NAME, dhcp_wait_time); 490 (void) nwamd_delete_scf_property(OUR_FMRI, OUR_PG, 491 OUR_OLD_DHCP_WAIT_TIME_PROP_NAME); 492 nlog(LOG_DEBUG, "nwamd_handle_upgrade: " 493 "converted '%s' to '%s' with value of %lld", 494 OUR_OLD_DHCP_WAIT_TIME_PROP_NAME, 495 OUR_NCU_WAIT_TIME_PROP_NAME, dhcp_wait_time); 496 } 497 498 /* 499 * If the user has changed Phase 0/0.5 properties that don't exist in 500 * Phase 1, manifest-import reports a warning; but those properties are 501 * not removed. nwamd/use_net_svc and nwamd/idle_time are two 502 * properties that don't exist in Phase 1. If they exist, remove them. 503 */ 504 if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG, 505 OUR_OLD_IDLE_TIME_PROP_NAME, &idle_time) == 0) { 506 (void) nwamd_delete_scf_property(OUR_FMRI, OUR_PG, 507 OUR_OLD_IDLE_TIME_PROP_NAME); 508 } 509 if (nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG, 510 OUR_OLD_USE_NET_SVC_PROP_NAME, &use_net_svc) == 0) { 511 (void) nwamd_delete_scf_property(OUR_FMRI, OUR_PG, 512 OUR_OLD_USE_NET_SVC_PROP_NAME); 513 } 514 515 nlog(LOG_DEBUG, "nwamd_handle_upgrade: " 516 "creating version property, setting to 1\n"); 517 (void) nwamd_set_count_property(OUR_FMRI, OUR_PG, 518 OUR_VERSION_PROP_NAME, 1U); 519 (void) smf_refresh_instance(OUR_FMRI); 520 } 521