OpenGrok

Cross Reference: llp.c
xref: /nwam/nwam1/usr/src/cmd/cmd-inet/lib/nwamd/llp.c
Home | History | Annotate | Line # | Download | only in nwamd
      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