1 /* 2 * Copyright (c) 2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "qdf_mem.h" 20 #include "qdf_module.h" 21 #include "qdf_status.h" 22 #include "qdf_str.h" 23 #include "qdf_trace.h" 24 #include "qdf_types.h" 25 26 static QDF_STATUS qdf_consume_char(const char **str, char c) 27 { 28 if ((*str)[0] != c) 29 return QDF_STATUS_E_FAILURE; 30 31 (*str)++; 32 33 return QDF_STATUS_SUCCESS; 34 } 35 36 static QDF_STATUS qdf_consume_dec(const char **str, uint8_t *out_digit) 37 { 38 uint8_t c = (*str)[0]; 39 40 if (c >= '0' && c <= '9') 41 *out_digit = c - '0'; 42 else 43 return QDF_STATUS_E_FAILURE; 44 45 (*str)++; 46 47 return QDF_STATUS_SUCCESS; 48 } 49 50 static QDF_STATUS qdf_consume_hex(const char **str, uint8_t *out_nibble) 51 { 52 uint8_t c = (*str)[0]; 53 54 if (c >= '0' && c <= '9') 55 *out_nibble = c - '0'; 56 else if (c >= 'a' && c <= 'f') 57 *out_nibble = c - 'a' + 10; 58 else if (c >= 'A' && c <= 'F') 59 *out_nibble = c - 'A' + 10; 60 else 61 return QDF_STATUS_E_FAILURE; 62 63 (*str)++; 64 65 return QDF_STATUS_SUCCESS; 66 } 67 68 static QDF_STATUS qdf_consume_octet_dec(const char **str, uint8_t *out_octet) 69 { 70 uint8_t len = 0; 71 uint16_t octet = 0; 72 int i; 73 74 /* consume up to 3 decimal digits */ 75 for (i = 0; i < 3; i++) { 76 uint8_t digit; 77 78 if (QDF_IS_STATUS_ERROR(qdf_consume_dec(str, &digit))) 79 break; 80 81 len++; 82 octet = octet * 10 + digit; 83 } 84 85 /* require at least 1 digit */ 86 if (!len) 87 return QDF_STATUS_E_FAILURE; 88 89 if (octet > 255) { 90 (*str) -= len; 91 return QDF_STATUS_E_FAILURE; 92 } 93 94 *out_octet = octet; 95 96 return QDF_STATUS_SUCCESS; 97 } 98 99 static QDF_STATUS qdf_consume_hex_pair(const char **str, uint8_t *out_byte) 100 { 101 QDF_STATUS status; 102 uint8_t hi, low; 103 104 status = qdf_consume_hex(str, &hi); 105 if (QDF_IS_STATUS_ERROR(status)) 106 return status; 107 108 status = qdf_consume_hex(str, &low); 109 if (QDF_IS_STATUS_ERROR(status)) { 110 (*str)--; 111 return status; 112 } 113 114 *out_byte = hi << 4 | low; 115 116 return QDF_STATUS_SUCCESS; 117 } 118 119 static QDF_STATUS qdf_consume_hextet(const char **str, uint16_t *out_hextet) 120 { 121 uint8_t len = 0; 122 uint16_t hextet = 0; 123 int i; 124 125 /* consume up to 4 hex digits */ 126 for (i = 0; i < 4; i++) { 127 uint8_t digit; 128 129 if (QDF_IS_STATUS_ERROR(qdf_consume_hex(str, &digit))) 130 break; 131 132 len++; 133 hextet = (hextet << 4) + digit; 134 } 135 136 /* require at least 1 digit */ 137 if (!len) 138 return QDF_STATUS_E_FAILURE; 139 140 /* no need to check for overflow */ 141 142 *out_hextet = hextet; 143 144 return QDF_STATUS_SUCCESS; 145 } 146 147 static QDF_STATUS qdf_consume_radix(const char **str, uint8_t *out_radix) 148 { 149 if ((*str)[0] == '0') { 150 switch ((*str)[1]) { 151 case 'b': 152 *out_radix = 2; 153 *str += 2; 154 break; 155 case 'o': 156 *out_radix = 8; 157 *str += 2; 158 break; 159 case 'x': 160 *out_radix = 16; 161 *str += 2; 162 break; 163 default: 164 *out_radix = 10; 165 break; 166 } 167 168 return QDF_STATUS_SUCCESS; 169 } 170 171 if (*str[0] >= '0' && *str[0] <= '9') { 172 *out_radix = 10; 173 return QDF_STATUS_SUCCESS; 174 } 175 176 return QDF_STATUS_E_FAILURE; 177 } 178 179 static QDF_STATUS 180 qdf_int_parse(const char *int_str, uint64_t *out_int, bool *out_negate) 181 { 182 QDF_STATUS status; 183 bool negate = false; 184 uint8_t radix; 185 uint8_t digit; 186 uint64_t value = 0; 187 uint64_t next_value; 188 189 QDF_BUG(int_str); 190 if (!int_str) 191 return QDF_STATUS_E_INVAL; 192 193 QDF_BUG(out_int); 194 if (!out_int) 195 return QDF_STATUS_E_INVAL; 196 197 int_str = qdf_str_left_trim(int_str); 198 199 status = qdf_consume_char(&int_str, '-'); 200 if (QDF_IS_STATUS_SUCCESS(status)) 201 negate = true; 202 else 203 qdf_consume_char(&int_str, '+'); 204 205 status = qdf_consume_radix(&int_str, &radix); 206 if (QDF_IS_STATUS_ERROR(status)) 207 return status; 208 209 while (QDF_IS_STATUS_SUCCESS(qdf_consume_hex(&int_str, &digit))) { 210 if (digit >= radix) 211 return QDF_STATUS_E_FAILURE; 212 213 next_value = value * radix + digit; 214 if (next_value < value) 215 return QDF_STATUS_E_RANGE; 216 217 value = next_value; 218 } 219 220 int_str = qdf_str_left_trim(int_str); 221 if (int_str[0] != '\0') 222 return QDF_STATUS_E_FAILURE; 223 224 *out_negate = negate; 225 *out_int = value; 226 227 return QDF_STATUS_SUCCESS; 228 } 229 230 QDF_STATUS qdf_int32_parse(const char *int_str, int32_t *out_int) 231 { 232 QDF_STATUS status; 233 int64_t value; 234 235 status = qdf_int64_parse(int_str, &value); 236 if (QDF_IS_STATUS_ERROR(status)) 237 return status; 238 239 if ((int32_t)value != value) 240 return QDF_STATUS_E_RANGE; 241 242 *out_int = value; 243 244 return QDF_STATUS_SUCCESS; 245 } 246 qdf_export_symbol(qdf_int32_parse); 247 248 QDF_STATUS qdf_uint32_parse(const char *int_str, uint32_t *out_int) 249 { 250 QDF_STATUS status; 251 uint64_t value; 252 253 status = qdf_uint64_parse(int_str, &value); 254 if (QDF_IS_STATUS_ERROR(status)) 255 return status; 256 257 if ((uint32_t)value != value) 258 return QDF_STATUS_E_RANGE; 259 260 *out_int = value; 261 262 return QDF_STATUS_SUCCESS; 263 } 264 qdf_export_symbol(qdf_uint32_parse); 265 266 QDF_STATUS qdf_int64_parse(const char *int_str, int64_t *out_int) 267 { 268 QDF_STATUS status; 269 bool negate; 270 uint64_t value; 271 int64_t signed_value; 272 273 status = qdf_int_parse(int_str, &value, &negate); 274 if (QDF_IS_STATUS_ERROR(status)) 275 return status; 276 277 if (negate) { 278 signed_value = -value; 279 if (signed_value > 0) 280 return QDF_STATUS_E_RANGE; 281 } else { 282 signed_value = value; 283 if (signed_value < 0) 284 return QDF_STATUS_E_RANGE; 285 } 286 287 *out_int = signed_value; 288 289 return QDF_STATUS_SUCCESS; 290 } 291 qdf_export_symbol(qdf_int64_parse); 292 293 QDF_STATUS qdf_uint64_parse(const char *int_str, uint64_t *out_int) 294 { 295 QDF_STATUS status; 296 bool negate; 297 uint64_t value; 298 299 status = qdf_int_parse(int_str, &value, &negate); 300 if (QDF_IS_STATUS_ERROR(status)) 301 return status; 302 303 if (negate) 304 return QDF_STATUS_E_RANGE; 305 306 *out_int = value; 307 308 return QDF_STATUS_SUCCESS; 309 } 310 qdf_export_symbol(qdf_uint64_parse); 311 312 QDF_STATUS qdf_bool_parse(const char *bool_str, bool *out_bool) 313 { 314 bool value; 315 316 QDF_BUG(bool_str); 317 if (!bool_str) 318 return QDF_STATUS_E_INVAL; 319 320 QDF_BUG(out_bool); 321 if (!out_bool) 322 return QDF_STATUS_E_INVAL; 323 324 bool_str = qdf_str_left_trim(bool_str); 325 326 switch (bool_str[0]) { 327 case '1': 328 case 'y': 329 case 'Y': 330 value = true; 331 break; 332 case '0': 333 case 'n': 334 case 'N': 335 value = false; 336 break; 337 default: 338 return QDF_STATUS_E_FAILURE; 339 } 340 341 bool_str++; 342 bool_str = qdf_str_left_trim(bool_str); 343 if (bool_str[0] != '\0') 344 return QDF_STATUS_E_FAILURE; 345 346 *out_bool = value; 347 348 return QDF_STATUS_SUCCESS; 349 } 350 qdf_export_symbol(qdf_bool_parse); 351 352 QDF_STATUS qdf_mac_parse(const char *mac_str, struct qdf_mac_addr *out_addr) 353 { 354 QDF_STATUS status; 355 struct qdf_mac_addr addr; 356 bool colons; 357 int i; 358 359 QDF_BUG(mac_str); 360 if (!mac_str) 361 return QDF_STATUS_E_INVAL; 362 363 QDF_BUG(out_addr); 364 if (!out_addr) 365 return QDF_STATUS_E_INVAL; 366 367 mac_str = qdf_str_left_trim(mac_str); 368 369 /* parse leading hex pair */ 370 status = qdf_consume_hex_pair(&mac_str, &addr.bytes[0]); 371 if (QDF_IS_STATUS_ERROR(status)) 372 return status; 373 374 /* dynamically detect colons */ 375 colons = mac_str[0] == ':'; 376 377 for (i = 1; i < QDF_MAC_ADDR_SIZE; i++) { 378 /* ensure colon separator if previously detected */ 379 if (colons) { 380 status = qdf_consume_char(&mac_str, ':'); 381 if (QDF_IS_STATUS_ERROR(status)) 382 return status; 383 } 384 385 /* parse next hex pair */ 386 status = qdf_consume_hex_pair(&mac_str, &addr.bytes[i]); 387 if (QDF_IS_STATUS_ERROR(status)) 388 return status; 389 } 390 391 mac_str = qdf_str_left_trim(mac_str); 392 if (mac_str[0] != '\0') 393 return QDF_STATUS_E_FAILURE; 394 395 *out_addr = addr; 396 397 return QDF_STATUS_SUCCESS; 398 } 399 qdf_export_symbol(qdf_mac_parse); 400 401 QDF_STATUS qdf_ipv4_parse(const char *ipv4_str, struct qdf_ipv4_addr *out_addr) 402 { 403 QDF_STATUS status; 404 struct qdf_ipv4_addr addr; 405 int i; 406 407 QDF_BUG(ipv4_str); 408 if (!ipv4_str) 409 return QDF_STATUS_E_INVAL; 410 411 QDF_BUG(out_addr); 412 if (!out_addr) 413 return QDF_STATUS_E_INVAL; 414 415 ipv4_str = qdf_str_left_trim(ipv4_str); 416 417 /* parse leading octet */ 418 status = qdf_consume_octet_dec(&ipv4_str, &addr.bytes[0]); 419 if (QDF_IS_STATUS_ERROR(status)) 420 return status; 421 422 for (i = 1; i < QDF_IPV4_ADDR_SIZE; i++) { 423 /* ensure dot separator */ 424 status = qdf_consume_char(&ipv4_str, '.'); 425 if (QDF_IS_STATUS_ERROR(status)) 426 return status; 427 428 /* parse next octet */ 429 status = qdf_consume_octet_dec(&ipv4_str, &addr.bytes[i]); 430 if (QDF_IS_STATUS_ERROR(status)) 431 return status; 432 } 433 434 ipv4_str = qdf_str_left_trim(ipv4_str); 435 if (ipv4_str[0] != '\0') 436 return QDF_STATUS_E_FAILURE; 437 438 *out_addr = addr; 439 440 return QDF_STATUS_SUCCESS; 441 } 442 qdf_export_symbol(qdf_ipv4_parse); 443 444 QDF_STATUS qdf_ipv6_parse(const char *ipv6_str, struct qdf_ipv6_addr *out_addr) 445 { 446 QDF_STATUS status; 447 struct qdf_ipv6_addr addr; 448 int8_t zero_comp = -1; 449 uint8_t hextets_found = 0; 450 451 QDF_BUG(ipv6_str); 452 if (!ipv6_str) 453 return QDF_STATUS_E_INVAL; 454 455 QDF_BUG(out_addr); 456 if (!out_addr) 457 return QDF_STATUS_E_INVAL; 458 459 ipv6_str = qdf_str_left_trim(ipv6_str); 460 461 /* check for leading zero-compression ("::") */ 462 status = qdf_consume_char(&ipv6_str, ':'); 463 if (QDF_IS_STATUS_SUCCESS(status)) { 464 status = qdf_consume_char(&ipv6_str, ':'); 465 if (QDF_IS_STATUS_SUCCESS(status)) 466 zero_comp = 0; 467 else 468 return QDF_STATUS_E_FAILURE; 469 } 470 471 while (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT) { 472 uint16_t hextet; 473 474 /* parse hextet */ 475 status = qdf_consume_hextet(&ipv6_str, &hextet); 476 if (QDF_IS_STATUS_ERROR(status)) { 477 /* we must end with hextet or zero compression */ 478 if (hextets_found != zero_comp) 479 return QDF_STATUS_E_FAILURE; 480 481 break; 482 } 483 484 addr.bytes[hextets_found * 2] = hextet >> 8; 485 addr.bytes[hextets_found * 2 + 1] = hextet; 486 hextets_found++; 487 488 /* parse ':' char */ 489 status = qdf_consume_char(&ipv6_str, ':'); 490 if (QDF_IS_STATUS_ERROR(status)) 491 break; 492 493 /* check for zero compression ("::") */ 494 status = qdf_consume_char(&ipv6_str, ':'); 495 if (QDF_IS_STATUS_SUCCESS(status)) { 496 /* only one zero compression is allowed */ 497 if (zero_comp >= 0) 498 return QDF_STATUS_E_FAILURE; 499 500 zero_comp = hextets_found; 501 } 502 } 503 504 /* we must have max hextets or a zero compression */ 505 if (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT && zero_comp == -1) 506 return QDF_STATUS_E_FAILURE; 507 508 ipv6_str = qdf_str_left_trim(ipv6_str); 509 if (ipv6_str[0] != '\0') 510 return QDF_STATUS_E_FAILURE; 511 512 /* shift lower hextets if zero compressed */ 513 if (zero_comp >= 0) { 514 uint8_t shift = QDF_IPV6_ADDR_HEXTET_COUNT - hextets_found; 515 void *to = &addr.bytes[(zero_comp + shift) * 2]; 516 void *from = &addr.bytes[zero_comp * 2]; 517 518 qdf_mem_move(to, from, (hextets_found - zero_comp) * 2); 519 qdf_mem_set(from, shift * 2, 0); 520 } 521 522 *out_addr = addr; 523 524 return QDF_STATUS_SUCCESS; 525 } 526 qdf_export_symbol(qdf_ipv6_parse); 527