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 2009 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 
  42 extern usba_cfg_pwr_descr_t default_cfg_power;
  43 extern usba_if_pwr_descr_t default_if_power;
  44 
  45 size_t
  46 usb_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 
 170 size_t
 171 usb_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  */
 187 static uchar_t *
 188 usb_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 
 229 size_t
 230 usb_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 
 246 size_t
 247 usb_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 
 263 size_t
 264 usba_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 
 298 size_t
 299 usb_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 
 332 size_t
 333 usb_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 
 367 size_t
 368 usba_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  */
 422 size_t
 423 usb_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*/
 473 size_t
 474 usba_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 
 501 size_t
 502 usb_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 
 525 size_t
 526 usb_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 
 570 size_t
 571 usb_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 
 625 size_t
 626 usb_parse_bos_descr(uchar_t     *buf,   /* from GET_DESCRIPTOR(BOS) */
 627         size_t                  buflen,
 628         usb_bos_descr_t         *ret_descr,
 629         size_t                  ret_buf_len)
 630 {
 631         if ((buf == NULL) || (ret_descr == NULL) ||
 632             (buflen < 2) || (buf[1] != USB_DESCR_TYPE_BOS)) {
 633 
 634                 return (USB_PARSE_ERROR);
 635         }
 636 
 637         return (usb_parse_data("ccsc",
 638             buf, buflen, ret_descr, ret_buf_len));
 639 }
 640 
 641 size_t
 642 usb_parse_uwb_bos_descr(uchar_t *buf,   /* from GET_DESCRIPTOR(BOS) */
 643         size_t                  buflen,
 644         usb_uwb_cap_descr_t     *ret_descr,
 645         size_t                  ret_buf_len)
 646 {
 647         uchar_t *bufend = buf + buflen;
 648 
 649         if ((buf == NULL) || (ret_descr == NULL)) {
 650 
 651                 return (USB_PARSE_ERROR);
 652         }
 653 
 654         while (buf + 3 <= bufend) {
 655                 if ((buf[1] == USB_DESCR_TYPE_DEV_CAPABILITY) &&
 656                     (buf[2] == USB_CAP_TYPE_WUSB)) {
 657 
 658                         return (usb_parse_data("ccccsccsc",
 659                             buf, _PTRDIFF(bufend, buf), ret_descr,
 660                             ret_buf_len));
 661                 }
 662 
 663                 INCREMENT_BUF(buf);
 664         }
 665 
 666         return (USB_PARSE_ERROR);
 667 }
 668 
 669 size_t
 670 usb_parse_comp_ep_descr(uchar_t *buf,   /* from GET_DESCRIPTOR(CONFIGURATION) */
 671         size_t                  buflen,
 672         uint_t                  if_number,
 673         uint_t                  alt_if_setting,
 674         uint_t                  ep_index,
 675         usb_ep_comp_descr_t     *ret_descr,
 676         size_t                  ret_buf_len)
 677 {
 678         return (usb_parse_CV_ep_descr(buf, buflen, "ccccsscc",
 679             if_number, alt_if_setting, ep_index,
 680             USB_DESCR_TYPE_WIRELESS_EP_COMP, 0,
 681             ret_descr, ret_buf_len));
 682 }