parser.c revision 7492:2387323b838f
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 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27/*
28 * Descriptor parsing functions
29 */
30#define	USBA_FRAMEWORK
31#include <sys/usb/usba/usba_impl.h>
32#include <sys/strsun.h>
33
34#define	INCREMENT_BUF(buf) \
35		if ((buf)[0] == 0) { \
36			break; \
37		} else { \
38			(buf) += (buf)[0]; \
39		}
40#define	isdigit(ch) ((ch >= '0') && (ch <= '9'))
41
42extern usba_cfg_pwr_descr_t default_cfg_power;
43extern usba_if_pwr_descr_t default_if_power;
44
45size_t
46usb_parse_data(char	*format,
47	uchar_t 	*data,
48	size_t		datalen,
49	void		*structure,
50	size_t		structlen)
51{
52	int	fmt;
53	int	counter = 1;
54	int	multiplier = 0;
55	uchar_t	*dataend = data + datalen;
56	char	*structstart = (char *)structure;
57	void	*structend = (void *)((intptr_t)structstart + structlen);
58
59	if ((format == NULL) || (data == NULL) || (structure == NULL)) {
60
61		return (USB_PARSE_ERROR);
62	}
63
64	while ((fmt = *format) != '\0') {
65
66		/*
67		 * Could some one pass a "format" that is greater than
68		 * the structlen? Conversely, one could pass a ret_buf_len
69		 * that is less than the "format" length.
70		 * If so, we need to protect against writing over memory.
71		 */
72		if (counter++ > structlen) {
73			break;
74		}
75
76		if (fmt == 'c') {
77			uint8_t	*cp = (uint8_t *)structure;
78
79			cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
80			    ~(_CHAR_ALIGNMENT - 1));
81			if (((data + 1) > dataend) ||
82			    ((cp + 1) > (uint8_t *)structend))
83				break;
84
85			*cp++ = *data++;
86			structure = (void *)cp;
87			if (multiplier) {
88				multiplier--;
89			}
90			if (multiplier == 0) {
91				format++;
92			}
93		} else if (fmt == 's') {
94			uint16_t	*sp = (uint16_t *)structure;
95
96			sp = (uint16_t *)
97			    (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
98			    ~(_SHORT_ALIGNMENT - 1));
99			if (((data + 2) > dataend) ||
100			    ((sp + 1) > (uint16_t *)structend))
101				break;
102
103			*sp++ = (data[1] << 8) + data[0];
104			data += 2;
105			structure = (void *)sp;
106			if (multiplier) {
107				multiplier--;
108			}
109			if (multiplier == 0) {
110				format++;
111			}
112		} else if (fmt == 'l') {
113			uint32_t	*lp = (uint32_t *)structure;
114
115			lp = (uint32_t *)
116			    (((uintptr_t)lp + _INT_ALIGNMENT - 1) &
117			    ~(_INT_ALIGNMENT - 1));
118			if (((data + 4) > dataend) ||
119			    ((lp + 1) > (uint32_t *)structend))
120				break;
121
122			*lp++ = (((((
123			    (uint32_t)data[3] << 8) | data[2]) << 8) |
124			    data[1]) << 8) | data[0];
125			data += 4;
126			structure = (void *)lp;
127			if (multiplier) {
128				multiplier--;
129			}
130			if (multiplier == 0) {
131				format++;
132			}
133		} else if (fmt == 'L') {
134			uint64_t	*llp = (uint64_t *)structure;
135
136			llp = (uint64_t *)
137			    (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) &
138			    ~(_LONG_LONG_ALIGNMENT - 1));
139			if (((data + 8) > dataend) ||
140			    ((llp + 1) >= (uint64_t *)structend))
141				break;
142
143			*llp++ = (((((((((((((data[7] << 8) |
144			    data[6]) << 8) | data[5]) << 8) |
145			    data[4]) << 8) | data[3]) << 8) |
146			    data[2]) << 8) | data[1]) << 8) |
147			    data[0];
148			data += 8;
149			structure = (void *)llp;
150			if (multiplier) {
151				multiplier--;
152			}
153			if (multiplier == 0) {
154				format++;
155			}
156		} else if (isdigit(fmt)) {
157			multiplier = (multiplier * 10) + (fmt - '0');
158			format++;
159			counter--;
160		} else {
161			multiplier = 0;
162			break;
163		}
164	}
165
166	return ((intptr_t)structure - (intptr_t)structstart);
167}
168
169
170size_t
171usb_parse_CV_descr(char *format,
172	uchar_t *data,
173	size_t	datalen,
174	void	*structure,
175	size_t	structlen)
176{
177	return (usb_parse_data(format, data, datalen, structure,
178	    structlen));
179}
180
181
182/*
183 *	Helper function: returns pointer to n-th descriptor of
184 *	type descr_type, unless the end of the buffer or a descriptor
185 *	of type	stop_descr_type1 or stop_descr_type2 is encountered first.
186 */
187static uchar_t *
188usb_nth_descr(uchar_t	*buf,
189	size_t		buflen,
190	int		descr_type,
191	uint_t		n,
192	int		stop_descr_type1,
193	int		stop_descr_type2)
194{
195	uchar_t	*bufstart = buf;
196	uchar_t *bufend = buf + buflen;
197
198	if (buf == NULL) {
199
200		return (NULL);
201	}
202
203	while (buf + 2 <= bufend) {
204		if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
205		    (buf[1] == stop_descr_type2))) {
206
207			return (NULL);
208		}
209
210		if ((descr_type == USB_DESCR_TYPE_ANY) ||
211		    (buf[1] == descr_type)) {
212			if (n-- == 0) {
213
214				return (buf);
215			}
216		}
217
218		/*
219		 * Check for a bad buffer.
220		 * If buf[0] is 0, then this will be an infite loop
221		 */
222		INCREMENT_BUF(buf);
223	}
224
225	return (NULL);
226}
227
228
229size_t
230usb_parse_dev_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(DEVICE) */
231	size_t			buflen,
232	usb_dev_descr_t		*ret_descr,
233	size_t			ret_buf_len)
234{
235	if ((buf == NULL) || (ret_descr == NULL) ||
236	    (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
237
238		return (USB_PARSE_ERROR);
239	}
240
241	return (usb_parse_data("ccsccccssscccc",
242	    buf, buflen, ret_descr, ret_buf_len));
243}
244
245
246size_t
247usb_parse_cfg_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
248	size_t			buflen,
249	usb_cfg_descr_t		*ret_descr,
250	size_t			ret_buf_len)
251{
252	if ((buf == NULL) || (ret_descr == NULL) ||
253	    (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
254
255		return (USB_PARSE_ERROR);
256	}
257
258	return (usb_parse_data("ccsccccc",
259	    buf, buflen, ret_descr, ret_buf_len));
260}
261
262
263size_t
264usba_parse_cfg_pwr_descr(
265	uchar_t			*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
266	size_t			buflen,
267	usba_cfg_pwr_descr_t	*ret_descr,
268	size_t			ret_buf_len)
269{
270	uchar_t *bufend = buf + buflen;
271
272	if ((buf == NULL) || (ret_descr == NULL)) {
273
274		return (USB_PARSE_ERROR);
275	}
276	while (buf + 2 <= bufend) {
277
278		if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
279			return (usb_parse_data("ccsccccccccsss",
280			    buf, buflen, ret_descr, ret_buf_len));
281		}
282
283		/*
284		 * Check for a bad buffer.
285		 * If buf[0] is 0, then this will be an infinite loop
286		 */
287		INCREMENT_BUF(buf);
288	}
289
290	/* return the default configuration power descriptor */
291	bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
292
293	return (ret_descr->bLength);
294
295}
296
297
298size_t
299usb_parse_ia_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
300	size_t			buflen,
301	size_t			first_if,
302	usb_ia_descr_t		*ret_descr,
303	size_t			ret_buf_len)
304{
305	uchar_t *bufend = buf + buflen;
306
307	if ((buf == NULL) || (ret_descr == NULL)) {
308
309		return (USB_PARSE_ERROR);
310	}
311
312	while (buf + USB_IA_DESCR_SIZE <= bufend) {
313		if ((buf[1] == USB_DESCR_TYPE_IA) &&
314		    (buf[2] == first_if)) {
315
316			return (usb_parse_data("cccccccc",
317			    buf, _PTRDIFF(bufend, buf),
318			    ret_descr, ret_buf_len));
319		}
320
321		/*
322		 * Check for a bad buffer.
323		 * If buf[0] is 0, then this will be an infinite loop
324		 */
325		INCREMENT_BUF(buf);
326	}
327
328	return (USB_PARSE_ERROR);
329}
330
331
332size_t
333usb_parse_if_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
334	size_t			buflen,
335	uint_t			if_number,
336	uint_t			alt_if_setting,
337	usb_if_descr_t		*ret_descr,
338	size_t			ret_buf_len)
339{
340	uchar_t *bufend = buf + buflen;
341
342	if ((buf == NULL) || (ret_descr == NULL)) {
343
344		return (USB_PARSE_ERROR);
345	}
346
347	while (buf + 4 <= bufend) {
348		if ((buf[1] == USB_DESCR_TYPE_IF) &&
349		    (buf[2] == if_number) &&
350		    (buf[3] == alt_if_setting)) {
351
352			return (usb_parse_data("ccccccccc",
353			    buf, _PTRDIFF(bufend, buf),
354			    ret_descr, ret_buf_len));
355		}
356
357		/*
358		 * Check for a bad buffer.
359		 * If buf[0] is 0, then this will be an infinite loop
360		 */
361		INCREMENT_BUF(buf);
362	}
363
364	return (USB_PARSE_ERROR);
365}
366
367size_t
368usba_parse_if_pwr_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
369	size_t			buflen,
370	uint_t			if_number,
371	uint_t			alt_if_setting,
372	usba_if_pwr_descr_t	*ret_descr,
373	size_t			ret_buf_len)
374{
375	uchar_t *bufend = buf + buflen;
376
377	if ((buf == NULL) || (ret_descr == NULL)) {
378
379		return (USB_PARSE_ERROR);
380	}
381
382	while (buf + 4 <= bufend) {
383		if ((buf[1] == USB_DESCR_TYPE_IF) &&
384		    (buf[2] == if_number) &&
385		    (buf[3] == alt_if_setting)) {
386
387			buf += buf[0];
388
389			if (buf + 2 <= bufend) {
390				if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
391
392					return (
393					    usb_parse_data("cccccccccsss", buf,
394					    _PTRDIFF(bufend, buf), ret_descr,
395					    ret_buf_len));
396				} else {
397					break;
398				}
399			} else {
400				break;
401			}
402		}
403
404		/*
405		 * Check for a bad buffer.
406		 * If buf[0] is 0, then this will be an infinite loop
407		 */
408		INCREMENT_BUF(buf);
409	}
410
411	/* return the default interface power descriptor */
412	bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
413
414	return (ret_descr->bLength);
415}
416
417
418/*
419 * the endpoint index is relative to the interface. index 0 is
420 * the first endpoint
421 */
422size_t
423usb_parse_ep_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
424	size_t			buflen,
425	uint_t			if_number,
426	uint_t			alt_if_setting,
427	uint_t			ep_index,
428	usb_ep_descr_t		*ret_descr,
429	size_t			ret_buf_len)
430{
431	uchar_t *bufend = buf + buflen;
432
433	if ((buf == NULL) || (ret_descr == NULL)) {
434
435		return (USB_PARSE_ERROR);
436	}
437
438	while ((buf + 4) <= bufend) {
439		if (buf[1] == USB_DESCR_TYPE_IF &&
440		    buf[2] == if_number &&
441		    buf[3] == alt_if_setting) {
442			if ((buf = usb_nth_descr(buf,
443			    _PTRDIFF(bufend, buf),
444			    USB_DESCR_TYPE_EP, ep_index,
445			    USB_DESCR_TYPE_IF, -1)) == NULL) {
446
447				break;
448			}
449
450			return (usb_parse_data("ccccsc",
451			    buf, _PTRDIFF(bufend, buf),
452			    ret_descr, ret_buf_len));
453		}
454
455		/*
456		 * Check for a bad buffer.
457		 * If buf[0] is 0, then this will be an infinite loop
458		 */
459		INCREMENT_BUF(buf);
460	}
461
462	return (USB_PARSE_ERROR);
463}
464
465
466/*
467 * Returns (at ret_descr) a null-terminated string.  Null termination is
468 * guaranteed, even if the string is longer than the buffer.  Thus, a
469 * maximum of (ret_buf_len - 1) characters are returned.
470 * Stops silently on first character not in UNICODE format.
471 */
472/*ARGSUSED*/
473size_t
474usba_ascii_string_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(STRING) */
475	size_t			buflen,
476	char			*ret_descr,
477	size_t			ret_buf_len)
478{
479	int	i = 1;
480	char	*retstart = ret_descr;
481	uchar_t *bufend = buf + buflen;
482
483	if ((buf == NULL) || (ret_descr == NULL) ||
484	    (ret_buf_len == 0) || (buflen < 2) ||
485	    (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
486
487		return (USB_PARSE_ERROR);
488	}
489
490	for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
491	    buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
492		*ret_descr++ = buf[0];
493	}
494
495	*ret_descr++ = 0;
496
497	return (_PTRDIFF(ret_descr, retstart));
498}
499
500
501size_t
502usb_parse_CV_cfg_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
503	size_t			buflen,
504	char			*fmt,
505	uint_t			descr_type,
506	uint_t			descr_index,
507	void			*ret_descr,
508	size_t			ret_buf_len)
509{
510	uchar_t *bufend = buf + buflen;
511
512	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
513	    (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
514	    descr_index, -1, -1)) == NULL)) {
515
516		return (USB_PARSE_ERROR);
517	}
518
519	return (usb_parse_data(fmt, buf,
520	    _PTRDIFF(bufend, buf), ret_descr,
521	    ret_buf_len));
522}
523
524
525size_t
526usb_parse_CV_if_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
527	size_t			buflen,
528	char			*fmt,
529	uint_t			if_number,
530	uint_t			alt_if_setting,
531	uint_t			descr_type,
532	uint_t			descr_index,
533	void			*ret_descr,
534	size_t			ret_buf_len)
535{
536	uchar_t *bufend = buf + buflen;
537
538	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
539
540		return (USB_PARSE_ERROR);
541	}
542
543	while (buf + 4 <= bufend) {
544		if ((buf[1] == USB_DESCR_TYPE_IF) &&
545		    (buf[2] == if_number) &&
546		    (buf[3] == alt_if_setting)) {
547			if ((buf = usb_nth_descr(buf,
548			    _PTRDIFF(bufend, buf), descr_type,
549			    descr_index, USB_DESCR_TYPE_IF, -1)) ==
550			    NULL) {
551				break;
552			}
553
554			return (usb_parse_data(fmt, buf,
555			    _PTRDIFF(bufend, buf),
556			    ret_descr, ret_buf_len));
557		}
558
559		/*
560		 * Check for a bad buffer.
561		 * If buf[0] is 0, then this will be an infinite loop
562		 */
563		INCREMENT_BUF(buf);
564	}
565
566	return (USB_PARSE_ERROR);
567}
568
569
570size_t
571usb_parse_CV_ep_descr(uchar_t	*buf,	/* from GET_DESCRIPTOR(CONFIGURATION) */
572	size_t			buflen,
573	char			*fmt,
574	uint_t			if_number,
575	uint_t			alt_if_setting,
576	uint_t			ep_index,
577	uint_t			descr_type,
578	uint_t			descr_index,
579	void			*ret_descr,
580	size_t			ret_buf_len)
581{
582	uchar_t *bufend = buf + buflen;
583
584	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
585
586		return (USB_PARSE_ERROR);
587	}
588
589	while (buf + 4 <= bufend) {
590		if ((buf[1] == USB_DESCR_TYPE_IF) &&
591		    (buf[2] == if_number) &&
592		    (buf[3] == alt_if_setting)) {
593			if ((buf = usb_nth_descr(buf,
594			    _PTRDIFF(bufend, buf),
595			    USB_DESCR_TYPE_EP, ep_index,
596			    USB_DESCR_TYPE_IF, -1)) == NULL) {
597
598				break;
599			}
600
601			if ((buf = usb_nth_descr(buf,
602			    _PTRDIFF(bufend, buf),
603			    descr_type, descr_index,
604			    USB_DESCR_TYPE_EP,
605			    USB_DESCR_TYPE_IF)) == NULL) {
606
607				break;
608			}
609
610			return (usb_parse_data(fmt, buf,
611			    _PTRDIFF(bufend, buf),
612			    ret_descr, ret_buf_len));
613		}
614
615		/*
616		 * Check for a bad buffer.
617		 * If buf[0] is 0, then this will be an infite loop
618		 */
619		INCREMENT_BUF(buf);
620	}
621
622	return (USB_PARSE_ERROR);
623}
624