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