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