Print this page
10324 topo_usb_parse_port_type() gets value check wrong
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/fm/topo/modules/common/usb/topo_usb_metadata.c
+++ new/usr/src/lib/fm/topo/modules/common/usb/topo_usb_metadata.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright (c) 2018, Joyent, Inc.
14 14 */
15 15
16 16 /*
17 17 * This module parses the private file format used for describing
18 18 * platform-specific USB overrides.
19 19 *
20 20 * FILE FORMAT
21 21 * -----------
22 22 *
23 23 * A USB topology file contains a series of lines which are separated by new
24 24 * lines. Leading and trailing whitespace on a line are ignored and empty lines
25 25 * are ignored as well. The '#' character is used as a comment character. There
26 26 * are a series of keywords that are supported which are used to indicate
27 27 * different control aspects. These keywords are all treated in a
28 28 * case-insensitive fashion. There are both top-level keywords and keywords that
29 29 * are only accepted within the context of a scope.
30 30 *
31 31 * Top-level keywords
32 32 * ------------------
33 33 *
34 34 * The following keywords are accepted, but must not be found inside a nested
35 35 * scope:
36 36 *
37 37 * 'disable-acpi' Disables the use of ACPI for this platform. This
38 38 * includes getting information about the port's
39 39 * type and visibility. This implies
40 40 * 'disable-acpi-match'.
41 41 *
42 42 * 'disable-acpi-match' Disables the act of trying to match ports based
43 43 * on ACPI.
44 44 *
45 45 *
46 46 * 'enable-acpi-match' Explicitly enables ACPI port matching on the
47 47 * platform based on ACPI.
48 48 *
49 49 * 'enable-metadata-match' Enables port matching based on metadata. This is
50 50 * most commonly used on platforms that have ehci
51 51 * and xhci controllers that share ports.
52 52 *
53 53 * 'port' Begins a port stanza that describes a single
54 54 * physical port. This stanza will continue until
55 55 * the 'end-port' keyword is encountered.
56 56 *
57 57 * Port Keywords
58 58 * -------------
59 59 *
60 60 * Some port keywords take arguments and others do not. When an argument exists,
61 61 * will occur on the subsequent line. Ports have a series of directives that
62 62 * describe metadata as well as directives that describe how to determine the
63 63 * port.
64 64 *
65 65 * 'label' Indicates that the next line contains the
66 66 * human-readable label for the port.
67 67 *
68 68 * 'chassis' Indicates that this port is part of the chassis
69 69 * and should not be enumerated elsewhere.
70 70 *
71 71 * 'external' Indicates that this port is externally visible.
72 72 *
73 73 * 'internal' Indicates that this port is internal to the
74 74 * chassis and cannot be accessed without opening
75 75 * the chassis.
76 76 *
77 77 * 'port-type' Indicates that the next line contains a number
78 78 * which corresponds to the type of the port. The
79 79 * port numbers are based on the ACPI table and
80 80 * may be in either base 10 or hexadecimal.
81 81 *
82 82 * 'acpi-path' Indicates that the next line contains an ACPI
83 83 * based name that matches the port.
84 84 *
85 85 * 'end-port' Closes the port-clause.
86 86 */
87 87
88 88 #include <libnvpair.h>
89 89 #include <sys/types.h>
90 90 #include <sys/stat.h>
91 91 #include <fcntl.h>
92 92 #include <fm/topo_list.h>
93 93 #include <fm/topo_mod.h>
94 94 #include <stdio.h>
95 95 #include <string.h>
96 96 #include <strings.h>
97 97 #include <libnvpair.h>
98 98 #include <sys/debug.h>
99 99 #include <ctype.h>
100 100 #include <unistd.h>
101 101
102 102 #include "topo_usb.h"
103 103 #include "topo_usb_int.h"
104 104
105 105 /*
106 106 * Maximum number of characters we expect to encounter in a line.
107 107 */
108 108 #define TOPO_USB_META_LINE_MAX 1000
109 109
110 110 /*
111 111 * This constant is the default set of flags that we'd like to apply when there
112 112 * is no configuration file present to determine the desired behavior. If one is
113 113 * present, we always defer to what it asks for.
114 114 *
115 115 * It's a difficult decision to enable ACPI by default or not. Unfortunately,
116 116 * we've encountered some systems where the ACPI information is wrong. However,
117 117 * we've encountered a larger number where it is correct. When it's correct,
118 118 * this greatly simplifies some of the work that we have to do. Our default
119 119 * disposition at the moment is to opt to decide its correct as that ends up
120 120 * giving us much better information.
121 121 */
122 122 #define USB_TOPO_META_DEFAULT_FLAGS TOPO_USB_M_ACPI_MATCH
123 123
124 124 typedef enum {
125 125 TOPO_USB_P_START,
126 126 TOPO_USB_P_PORT,
127 127 TOPO_USB_P_LABEL,
128 128 TOPO_USB_P_PORT_TYPE,
129 129 TOPO_USB_P_ACPI_PATH
130 130 } topo_usb_parse_state_t;
131 131
132 132 typedef struct topo_usb_parse {
133 133 topo_usb_parse_state_t tp_state;
134 134 topo_list_t *tp_ports;
135 135 topo_usb_meta_port_t *tp_cport;
136 136 topo_usb_meta_flags_t tp_flags;
137 137 } topo_usb_parse_t;
138 138
139 139 /*
140 140 * Read the next line in the file with content. Trim trailing and leading
141 141 * whitespace and trim comments out. If this results in an empty line, read the
142 142 * next. Returns zero if we hit EOF. Otherwise, returns one if data, or negative
143 143 * one if an error occurred.
144 144 */
145 145 static int
146 146 topo_usb_getline(topo_mod_t *mod, char *buf, size_t len, FILE *f, char **first)
147 147 {
148 148 while (fgets(buf, len, f) != NULL) {
149 149 char *c;
150 150 size_t i;
151 151
152 152 if ((c = strrchr(buf, '\n')) == NULL) {
153 153 topo_mod_dprintf(mod, "failed to find new line in "
154 154 "metadata file");
155 155 return (-1);
156 156 }
157 157
158 158 while (isspace(*c) != 0 && c >= buf) {
159 159 *c = '\0';
160 160 c--;
161 161 continue;
162 162 }
163 163
164 164 if ((c = strchr(buf, '#')) != 0) {
165 165 *c = '\0';
166 166 }
167 167
168 168 for (i = 0; buf[i] != '\0'; i++) {
169 169 if (isspace(buf[i]) == 0)
170 170 break;
171 171 }
172 172
173 173 if (buf[i] == '\0')
174 174 continue;
175 175 *first = &buf[i];
176 176 return (1);
177 177 }
178 178
179 179 return (0);
180 180 }
181 181
182 182 static boolean_t
183 183 topo_usb_parse_start(topo_mod_t *mod, topo_usb_parse_t *parse, const char *line)
184 184 {
185 185 topo_usb_meta_port_t *port;
186 186
187 187 VERIFY3S(parse->tp_state, ==, TOPO_USB_P_START);
188 188 VERIFY3P(parse->tp_cport, ==, NULL);
189 189
190 190 if (strcasecmp(line, "disable-acpi") == 0) {
191 191 parse->tp_flags |= TOPO_USB_M_NO_ACPI;
192 192 parse->tp_flags &= ~TOPO_USB_M_ACPI_MATCH;
193 193 return (B_TRUE);
194 194 } else if (strcasecmp(line, "disable-acpi-match") == 0) {
195 195 parse->tp_flags &= ~TOPO_USB_M_ACPI_MATCH;
196 196 return (B_TRUE);
197 197 } else if (strcasecmp(line, "enable-acpi-match") == 0) {
198 198 parse->tp_flags |= TOPO_USB_M_ACPI_MATCH;
199 199 return (B_TRUE);
200 200 } else if (strcasecmp(line, "enable-metadata-match") == 0) {
201 201 parse->tp_flags |= TOPO_USB_M_METADATA_MATCH;
202 202 return (B_TRUE);
203 203 } else if (strcasecmp(line, "port") != 0) {
204 204 topo_mod_dprintf(mod, "expected 'port', encountered %s",
205 205 line);
206 206 return (B_FALSE);
207 207 }
208 208
209 209 if ((port = topo_mod_zalloc(mod, sizeof (topo_usb_meta_port_t))) ==
210 210 NULL) {
211 211 topo_mod_dprintf(mod, "failed to allocate metadata port");
212 212 return (B_FALSE);
213 213 }
214 214 port->tmp_port_type = 0xff;
215 215
216 216 parse->tp_cport = port;
217 217 parse->tp_state = TOPO_USB_P_PORT;
218 218 return (B_TRUE);
219 219 }
220 220
221 221 static boolean_t
222 222 topo_usb_parse_port(topo_mod_t *mod, topo_usb_parse_t *parse, const char *line)
223 223 {
224 224 VERIFY3S(parse->tp_state, ==, TOPO_USB_P_PORT);
225 225 VERIFY3P(parse->tp_cport, !=, NULL);
226 226
227 227 if (strcasecmp(line, "label") == 0) {
228 228 parse->tp_state = TOPO_USB_P_LABEL;
229 229 } else if (strcasecmp(line, "chassis") == 0) {
230 230 parse->tp_cport->tmp_flags |= TOPO_USB_F_CHASSIS;
231 231 } else if (strcasecmp(line, "external") == 0) {
232 232 parse->tp_cport->tmp_flags |= TOPO_USB_F_EXTERNAL;
233 233 } else if (strcasecmp(line, "internal") == 0) {
234 234 parse->tp_cport->tmp_flags |= TOPO_USB_F_INTERNAL;
235 235 } else if (strcasecmp(line, "port-type") == 0) {
236 236 parse->tp_state = TOPO_USB_P_PORT_TYPE;
237 237 } else if (strcasecmp(line, "acpi-path") == 0) {
238 238 parse->tp_state = TOPO_USB_P_ACPI_PATH;
239 239 } else if (strcasecmp(line, "end-port") == 0) {
240 240 topo_list_append(parse->tp_ports, parse->tp_cport);
241 241 parse->tp_cport = NULL;
242 242 parse->tp_state = TOPO_USB_P_START;
243 243 } else {
244 244 topo_mod_dprintf(mod, "illegal directive in port block: %s",
245 245 line);
246 246 return (B_FALSE);
247 247 }
248 248
249 249 return (B_TRUE);
250 250 }
251 251
252 252 static boolean_t
253 253 topo_usb_parse_label(topo_mod_t *mod, topo_usb_parse_t *parse, const char *line)
254 254 {
255 255 size_t i, len;
256 256
257 257 VERIFY3S(parse->tp_state, ==, TOPO_USB_P_LABEL);
258 258
259 259 len = strlen(line);
260 260 for (i = 0; i < len; i++) {
261 261 if (isascii(line[i]) == 0 || isprint(line[i]) == 0) {
262 262 topo_mod_dprintf(mod, "label character %llu is "
263 263 "invalid: 0x%x", i, line[i]);
264 264 return (B_FALSE);
265 265 }
266 266 }
267 267
268 268 if (parse->tp_cport->tmp_label != NULL) {
269 269 topo_mod_strfree(mod, parse->tp_cport->tmp_label);
270 270 }
271 271
272 272 if ((parse->tp_cport->tmp_label = topo_mod_strdup(mod, line)) == NULL) {
273 273 topo_mod_dprintf(mod, "failed to duplicate label for port");
274 274 return (B_FALSE);
275 275 }
276 276
277 277 parse->tp_state = TOPO_USB_P_PORT;
278 278
279 279 return (B_TRUE);
280 280 }
281 281
282 282 static boolean_t
↓ open down ↓ |
282 lines elided |
↑ open up ↑ |
283 283 topo_usb_parse_port_type(topo_mod_t *mod, topo_usb_parse_t *parse,
284 284 const char *line)
285 285 {
286 286 unsigned long val;
287 287 char *eptr;
288 288
289 289 VERIFY3S(parse->tp_state, ==, TOPO_USB_P_PORT_TYPE);
290 290
291 291 errno = 0;
292 292 val = strtoul(line, &eptr, 0);
293 - if (errno != 0 || *eptr != '\0' || val > UINT_MAX) {
293 + if (errno != 0 || *eptr != '\0' || val >= UINT_MAX) {
294 294 topo_mod_dprintf(mod, "encountered bad value for port-type "
295 295 "line: %s", line);
296 296 return (B_FALSE);
297 297 }
298 298
299 299 parse->tp_cport->tmp_port_type = (uint_t)val;
300 300
301 301 parse->tp_state = TOPO_USB_P_PORT;
302 302 return (B_TRUE);
303 303 }
304 304
305 305 static boolean_t
306 306 topo_usb_parse_path(topo_mod_t *mod, topo_usb_parse_t *parse,
307 307 topo_usb_path_type_t ptype, const char *line)
308 308 {
309 309 char *fspath;
310 310 topo_usb_meta_port_path_t *path;
311 311
312 312 VERIFY(parse->tp_state == TOPO_USB_P_ACPI_PATH);
313 313 VERIFY3P(parse->tp_cport, !=, NULL);
314 314
315 315 if ((fspath = topo_mod_strdup(mod, line)) == NULL) {
316 316 topo_mod_dprintf(mod, "failed to duplicate path");
317 317 return (B_FALSE);
318 318 }
319 319
320 320 if ((path = topo_mod_zalloc(mod, sizeof (topo_usb_meta_port_path_t))) ==
321 321 NULL) {
322 322 topo_mod_dprintf(mod, "failed to allocate meta port path "
323 323 "structure");
324 324 topo_mod_strfree(mod, fspath);
325 325 return (B_FALSE);
326 326 }
327 327
328 328 path->tmpp_type = ptype;
329 329 path->tmpp_path = fspath;
330 330
331 331 topo_list_append(&parse->tp_cport->tmp_paths, path);
332 332
333 333 parse->tp_state = TOPO_USB_P_PORT;
334 334 return (B_TRUE);
335 335 }
336 336
337 337
338 338 void
339 339 topo_usb_free_metadata(topo_mod_t *mod, topo_list_t *metadata)
340 340 {
341 341 topo_usb_meta_port_t *mp;
342 342
343 343 while ((mp = topo_list_next(metadata)) != NULL) {
344 344 topo_usb_meta_port_path_t *path;
345 345
346 346 while ((path = topo_list_next((&mp->tmp_paths))) != NULL) {
347 347 topo_list_delete(&mp->tmp_paths, path);
348 348 topo_mod_strfree(mod, path->tmpp_path);
349 349 topo_mod_free(mod, path,
350 350 sizeof (topo_usb_meta_port_path_t));
351 351 }
352 352
353 353 topo_list_delete(metadata, mp);
354 354 topo_mod_strfree(mod, mp->tmp_label);
355 355 topo_mod_free(mod, mp, sizeof (topo_usb_meta_port_t));
356 356 }
357 357 }
358 358
359 359 int
360 360 topo_usb_load_metadata(topo_mod_t *mod, tnode_t *pnode, topo_list_t *list,
361 361 topo_usb_meta_flags_t *flagsp)
362 362 {
363 363 int fd;
364 364 FILE *f = NULL;
365 365 char buf[TOPO_USB_META_LINE_MAX], *first, *prod;
366 366 int ret;
367 367 topo_usb_parse_t parse;
368 368 char pbuf[PATH_MAX];
369 369
370 370 *flagsp = USB_TOPO_META_DEFAULT_FLAGS;
371 371
372 372 /*
373 373 * If no product string, just leave it as is and don't attempt to get
374 374 * metadata.
375 375 */
376 376 if ((topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
377 377 FM_FMRI_AUTH_PRODUCT, &prod, &ret)) != 0) {
378 378 topo_mod_dprintf(mod, "skipping metadata load: failed to get "
379 379 "auth");
380 380 return (0);
381 381 }
382 382
383 383 if (snprintf(pbuf, sizeof (pbuf), "maps/%s-usb.usbtopo", prod) >=
384 384 sizeof (pbuf)) {
385 385 topo_mod_dprintf(mod, "skipping metadata load: product name "
386 386 "too long");
387 387 topo_mod_strfree(mod, prod);
388 388 return (0);
389 389 }
390 390 topo_mod_strfree(mod, prod);
391 391
392 392 if ((fd = topo_mod_file_search(mod, pbuf, O_RDONLY)) < 0) {
393 393 topo_mod_dprintf(mod, "skipping metadata load: couldn't find "
394 394 "%s", pbuf);
395 395 return (0);
396 396 }
397 397
398 398
399 399 if ((f = fdopen(fd, "r")) == NULL) {
400 400 topo_mod_dprintf(mod, "failed to fdopen metadata file %s: %s",
401 401 pbuf, strerror(errno));
402 402 VERIFY0(close(fd));
403 403 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
404 404 goto err;
405 405 }
406 406
407 407 bzero(&parse, sizeof (parse));
408 408 parse.tp_ports = list;
409 409 parse.tp_state = TOPO_USB_P_START;
410 410
411 411 while ((ret = topo_usb_getline(mod, buf, sizeof (buf), f, &first)) !=
412 412 0) {
413 413 if (ret == -1) {
414 414 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
415 415 goto err;
416 416 }
417 417
418 418 switch (parse.tp_state) {
419 419 case TOPO_USB_P_START:
420 420 if (!topo_usb_parse_start(mod, &parse, first)) {
421 421 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
422 422 goto err;
423 423 }
424 424 break;
425 425 case TOPO_USB_P_PORT:
426 426 if (!topo_usb_parse_port(mod, &parse, first)) {
427 427 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
428 428 goto err;
429 429 }
430 430 break;
431 431 case TOPO_USB_P_LABEL:
432 432 if (!topo_usb_parse_label(mod, &parse, first)) {
433 433 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
434 434 goto err;
435 435 }
436 436 break;
437 437 case TOPO_USB_P_PORT_TYPE:
438 438 if (!topo_usb_parse_port_type(mod, &parse, first)) {
439 439 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
440 440 goto err;
441 441 }
442 442 break;
443 443
444 444 case TOPO_USB_P_ACPI_PATH:
445 445 if (!topo_usb_parse_path(mod, &parse, TOPO_USB_T_ACPI,
446 446 first)) {
447 447 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
448 448 goto err;
449 449 }
450 450 break;
451 451 }
452 452 }
453 453
454 454 if (parse.tp_state != TOPO_USB_P_START) {
455 455 topo_mod_dprintf(mod, "metadata file didn't end in correct "
456 456 "state, failing");
457 457 ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
458 458 goto err;
459 459 }
460 460
461 461 topo_mod_dprintf(mod, "successfully loaded metadata %s", pbuf);
462 462 VERIFY0(fclose(f));
463 463 *flagsp = parse.tp_flags;
464 464 return (0);
465 465
466 466 err:
467 467 if (f != NULL)
468 468 VERIFY0(fclose(f));
469 469 topo_usb_free_metadata(mod, list);
470 470 return (ret);
471 471 }
↓ open down ↓ |
168 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX