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
find_if_type(const char * name)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
llp_list_free(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
initialize_llp(void)115 initialize_llp(void)
116 {
117 llp_list.q_forw = llp_list.q_back = &llp_list;
118 }
119
120 static llp_t *
llp_lookup(const char * link)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 *
llp_add(const char * name)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
parse_llp_config(void)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
upgrade_llp_config(void)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
nwamd_handle_upgrade(nwamd_event_t event)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