VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/USBFilter.cpp@ 82968

Last change on this file since 82968 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.3 KB
Line 
1/* $Id: USBFilter.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VirtualBox USB filter abstraction.
4 */
5
6/*
7 * Copyright (C) 2007-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <VBox/usbfilter.h>
32#include <VBox/usblib.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <iprt/string.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38
39
40/** @todo split this up for the sake of device drivers and such. */
41
42
43/**
44 * Initializes an USBFILTER structure.
45 *
46 * @param pFilter The filter to initialize.
47 * @param enmType The filter type. If not valid, the filter will not
48 * be properly initialized and all other calls will fail.
49 */
50USBLIB_DECL(void) USBFilterInit(PUSBFILTER pFilter, USBFILTERTYPE enmType)
51{
52 memset(pFilter, 0, sizeof(*pFilter));
53 AssertReturnVoid(enmType > USBFILTERTYPE_INVALID && enmType < USBFILTERTYPE_END);
54 pFilter->u32Magic = USBFILTER_MAGIC;
55 pFilter->enmType = enmType;
56 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
57 pFilter->aFields[i].enmMatch = USBFILTERMATCH_IGNORE;
58}
59
60
61/**
62 * Make a clone of the specified filter.
63 *
64 * @param pFilter The target filter.
65 * @param pToClone The source filter.
66 */
67USBLIB_DECL(void) USBFilterClone(PUSBFILTER pFilter, PCUSBFILTER pToClone)
68{
69 memcpy(pFilter, pToClone, sizeof(*pToClone));
70}
71
72
73/**
74 * Deletes (invalidates) an USBFILTER structure.
75 *
76 * @param pFilter The filter to delete.
77 */
78USBLIB_DECL(void) USBFilterDelete(PUSBFILTER pFilter)
79{
80 pFilter->u32Magic = ~USBFILTER_MAGIC;
81 pFilter->enmType = USBFILTERTYPE_INVALID;
82 pFilter->offCurEnd = 0xfffff;
83}
84
85
86/**
87 * Skips blanks.
88 *
89 * @returns Next non-blank char in the string.
90 * @param psz The string.
91 */
92DECLINLINE(const char *) usbfilterSkipBlanks(const char *psz)
93{
94 while (RT_C_IS_BLANK(*psz))
95 psz++;
96 return psz;
97}
98
99
100/**
101 * Worker for usbfilterReadNumber that parses a hexadecimal number.
102 *
103 * @returns Same as usbfilterReadNumber, except for VERR_NO_DIGITS.
104 * @param pszExpr Where to start converting, first char is a valid digit.
105 * @param ppszExpr See usbfilterReadNumber.
106 * @param pu16Val See usbfilterReadNumber.
107 */
108static int usbfilterReadNumberHex(const char *pszExpr, const char **ppszExpr, uint16_t *pu16Val)
109{
110 int rc = VINF_SUCCESS;
111 uint32_t u32 = 0;
112 do
113 {
114 unsigned uDigit = *pszExpr >= 'a' && *pszExpr <= 'f'
115 ? *pszExpr - 'a' + 10
116 : *pszExpr >= 'A' && *pszExpr <= 'F'
117 ? *pszExpr - 'A' + 10
118 : *pszExpr - '0';
119 if (uDigit >= 16)
120 break;
121 u32 *= 16;
122 u32 += uDigit;
123 if (u32 > UINT16_MAX)
124 rc = VWRN_NUMBER_TOO_BIG;
125 } while (*++pszExpr);
126
127 *ppszExpr = usbfilterSkipBlanks(pszExpr);
128 *pu16Val = rc == VINF_SUCCESS ? u32 : UINT16_MAX;
129 return VINF_SUCCESS;
130}
131
132
133/**
134 * Worker for usbfilterReadNumber that parses a decimal number.
135 *
136 * @returns Same as usbfilterReadNumber, except for VERR_NO_DIGITS.
137 * @param pszExpr Where to start converting, first char is a valid digit.
138 * @param uBase The base - 8 or 16.
139 * @param ppszExpr See usbfilterReadNumber.
140 * @param pu16Val See usbfilterReadNumber.
141 */
142static int usbfilterReadNumberDecimal(const char *pszExpr, unsigned uBase, const char **ppszExpr, uint16_t *pu16Val)
143{
144 int rc = VINF_SUCCESS;
145 uint32_t u32 = 0;
146 do
147 {
148 unsigned uDigit = *pszExpr - '0';
149 if (uDigit >= uBase)
150 break;
151 u32 *= uBase;
152 u32 += uDigit;
153 if (u32 > UINT16_MAX)
154 rc = VWRN_NUMBER_TOO_BIG;
155 } while (*++pszExpr);
156
157 *ppszExpr = usbfilterSkipBlanks(pszExpr);
158 *pu16Val = rc == VINF_SUCCESS ? u32 : UINT16_MAX;
159 return rc;
160}
161
162
163/**
164 * Reads a number from a numeric expression.
165 *
166 * @returns IPRT status code.
167 * @retval VINF_SUCCESS if all is fine. *ppszExpr and *pu16Val are updated.
168 * @retval VWRN_NUMBER_TOO_BIG if the number exceeds unsigned 16-bit, both *ppszExpr and *pu16Val are updated.
169 * @retval VERR_NO_DIGITS if there aren't any digits.
170 *
171 * @param ppszExpr Pointer to the current expression pointer.
172 * This is advanced past the expression and trailing blanks on success.
173 * @param pu16Val Where to store the value on success.
174 */
175static int usbfilterReadNumber(const char **ppszExpr, uint16_t *pu16Val)
176{
177 const char *pszExpr = usbfilterSkipBlanks(*ppszExpr);
178 if (!RT_C_IS_DIGIT(*pszExpr))
179 return VERR_NO_DIGITS;
180
181 if (*pszExpr == '0')
182 {
183 if (pszExpr[1] == 'x' || pszExpr[1] == 'X')
184 {
185 if (!RT_C_IS_XDIGIT(pszExpr[2]))
186 return VERR_NO_DIGITS;
187 return usbfilterReadNumberHex(pszExpr + 2, ppszExpr, pu16Val);
188 }
189 if (RT_C_IS_ODIGIT(pszExpr[1]))
190 return usbfilterReadNumberDecimal(pszExpr + 1, 8, ppszExpr, pu16Val);
191 /* Solitary 0! */
192 if (RT_C_IS_DIGIT(pszExpr[1]))
193 return VERR_NO_DIGITS;
194 }
195 return usbfilterReadNumberDecimal(pszExpr, 10, ppszExpr, pu16Val);
196}
197
198
199/**
200 * Validates a numeric expression.
201 *
202 * @returns VBox status code.
203 * @retval VINF_SUCCESS if valid.
204 * @retval VERR_INVALID_PARAMETER if invalid.
205 * @retval VERR_NO_DIGITS if some expression is short of digits.
206 *
207 * @param pszExpr The numeric expression.
208 */
209static int usbfilterValidateNumExpression(const char *pszExpr)
210{
211 /*
212 * An empty expression is fine.
213 */
214 if (!*pszExpr)
215 return VINF_SUCCESS;
216
217 /*
218 * The string format is: "(<m>|([<m>]-[<n>]))|(<m>|([<m>]-[<n>]))+"
219 * where <m> and <n> are numbers in the decimal, hex (0xNNN) or octal (0NNN)
220 * form. Spaces are allowed around <m> and <n>.
221 */
222 unsigned cSubExpressions = 0;
223 while (*pszExpr)
224 {
225 /*
226 * Skip remnants of the previous expression and any empty expressions.
227 * ('|' is the expression separator.)
228 */
229 while (*pszExpr == '|' || RT_C_IS_BLANK(*pszExpr))
230 pszExpr++;
231 if (!*pszExpr)
232 break;
233
234 /*
235 * Parse the expression.
236 */
237 int rc;
238 uint16_t u16First = 0;
239 uint16_t u16Last = 0;
240 if (*pszExpr == '-')
241 {
242 /* -N */
243 pszExpr++;
244 rc = usbfilterReadNumber(&pszExpr, &u16Last);
245 }
246 else
247 {
248 /* M or M-N */
249 rc = usbfilterReadNumber(&pszExpr, &u16First);
250 if (RT_SUCCESS(rc))
251 {
252 if (*pszExpr == '-')
253 {
254 /* M-N */
255 pszExpr++;
256 rc = usbfilterReadNumber(&pszExpr, &u16Last);
257 }
258 else
259 {
260 /* M */
261 u16Last = u16First;
262 }
263 }
264 }
265 if (RT_FAILURE(rc))
266 return rc;
267
268 /*
269 * We should either be at the end of the string or at
270 * an expression separator (|).
271 */
272 if (*pszExpr && *pszExpr != '|' )
273 return VERR_INVALID_PARAMETER;
274
275 cSubExpressions++;
276 }
277
278 return cSubExpressions ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
279}
280
281
282/**
283 * Validates a string pattern.
284 *
285 * @returns VBox status code.
286 * @retval VINF_SUCCESS if valid.
287 * @retval VERR_INVALID_PARAMETER if invalid.
288 *
289 * @param psz The string pattern.
290 */
291static int usbfilterValidateStringPattern(const char *psz)
292{
293 /*
294 * This is only becomes important if we start doing
295 * sets ([0-9]) and such like.
296 */
297 RT_NOREF1(psz);
298 return VINF_SUCCESS;
299}
300
301
302/**
303 * Thoroughly validates the USB Filter.
304 *
305 * @returns Appropriate VBox status code.
306 * @param pFilter The filter to validate.
307 */
308USBLIB_DECL(int) USBFilterValidate(PCUSBFILTER pFilter)
309{
310 if (!VALID_PTR(pFilter))
311 return VERR_INVALID_POINTER;
312
313 if (pFilter->u32Magic != USBFILTER_MAGIC)
314 return VERR_INVALID_MAGIC;
315
316 if ( pFilter->enmType <= USBFILTERTYPE_INVALID
317 || pFilter->enmType >= USBFILTERTYPE_END)
318 {
319 Log(("USBFilter: %p - enmType=%d!\n", pFilter, pFilter->enmType));
320 return VERR_INVALID_PARAMETER;
321 }
322
323 if (pFilter->offCurEnd >= sizeof(pFilter->achStrTab))
324 {
325 Log(("USBFilter: %p - offCurEnd=%#x!\n", pFilter, pFilter->offCurEnd));
326 return VERR_INVALID_PARAMETER;
327 }
328
329 /* Validate that string value offsets are inside the string table. */
330 for (uint32_t i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
331 {
332 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch)
333 && pFilter->aFields[i].u16Value > pFilter->offCurEnd)
334 {
335 Log(("USBFilter: %p - bad offset=%#x\n", pFilter, pFilter->aFields[i].u16Value));
336 return VERR_INVALID_PARAMETER;
337 }
338 }
339
340 /*
341 * Validate the string table.
342 */
343 if (pFilter->achStrTab[0])
344 {
345 Log(("USBFilter: %p - bad null string\n", pFilter));
346 return VERR_INVALID_PARAMETER;
347 }
348
349 const char *psz = &pFilter->achStrTab[1];
350 while (psz < &pFilter->achStrTab[pFilter->offCurEnd])
351 {
352 const char *pszEnd = RTStrEnd(psz, &pFilter->achStrTab[sizeof(pFilter->achStrTab)] - psz);
353 if (!pszEnd)
354 {
355 Log(("USBFilter: %p - string at %#x isn't terminated!\n",
356 pFilter, psz - &pFilter->achStrTab[0]));
357 return VERR_INVALID_PARAMETER;
358 }
359
360 uint16_t off = (uint16_t)(uintptr_t)(psz - &pFilter->achStrTab[0]);
361 unsigned i;
362 for (i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
363 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch)
364 && pFilter->aFields[i].u16Value == off)
365 break;
366 if (i >= RT_ELEMENTS(pFilter->aFields))
367 {
368 Log(("USBFilter: %p - string at %#x isn't used by anyone! (%s)\n",
369 pFilter, psz - &pFilter->achStrTab[0], psz));
370 return VERR_INVALID_PARAMETER;
371 }
372
373 psz = pszEnd + 1;
374 }
375
376 if ((uintptr_t)(psz - &pFilter->achStrTab[0] - 1) != pFilter->offCurEnd)
377 {
378 Log(("USBFilter: %p - offCurEnd=%#x currently at %#x\n",
379 pFilter, pFilter->offCurEnd, psz - &pFilter->achStrTab[0] - 1));
380 return VERR_INVALID_PARAMETER;
381 }
382
383 while (psz < &pFilter->achStrTab[sizeof(pFilter->achStrTab)])
384 {
385 if (*psz)
386 {
387 Log(("USBFilter: %p - str tab isn't zero padded! %#x: %c\n",
388 pFilter, psz - &pFilter->achStrTab[0], *psz));
389 return VERR_INVALID_PARAMETER;
390 }
391 psz++;
392 }
393
394
395 /*
396 * Validate the fields.
397 */
398 int rc;
399 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
400 {
401 switch (pFilter->aFields[i].enmMatch)
402 {
403 case USBFILTERMATCH_IGNORE:
404 case USBFILTERMATCH_PRESENT:
405 if (pFilter->aFields[i].u16Value)
406 {
407 Log(("USBFilter: %p - #%d/%d u16Value=%d expected 0!\n",
408 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value));
409 return VERR_INVALID_PARAMETER;
410 }
411 break;
412
413 case USBFILTERMATCH_NUM_EXACT:
414 case USBFILTERMATCH_NUM_EXACT_NP:
415 if (!USBFilterIsNumericField((USBFILTERIDX)i))
416 {
417 Log(("USBFilter: %p - #%d / %d - not numeric field\n",
418 pFilter, i, pFilter->aFields[i].enmMatch));
419 return VERR_INVALID_PARAMETER;
420 }
421 break;
422
423 case USBFILTERMATCH_NUM_EXPRESSION:
424 case USBFILTERMATCH_NUM_EXPRESSION_NP:
425 if (!USBFilterIsNumericField((USBFILTERIDX)i))
426 {
427 Log(("USBFilter: %p - #%d / %d - not numeric field\n",
428 pFilter, i, pFilter->aFields[i].enmMatch));
429 return VERR_INVALID_PARAMETER;
430 }
431 if ( pFilter->aFields[i].u16Value >= pFilter->offCurEnd
432 && pFilter->offCurEnd)
433 {
434 Log(("USBFilter: %p - #%d / %d - off=%#x max=%#x\n",
435 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value, pFilter->offCurEnd));
436 return VERR_INVALID_PARAMETER;
437 }
438 psz = &pFilter->achStrTab[pFilter->aFields[i].u16Value];
439 rc = usbfilterValidateNumExpression(psz);
440 if (RT_FAILURE(rc))
441 {
442 Log(("USBFilter: %p - #%d / %d - bad num expr: %s (rc=%Rrc)\n",
443 pFilter, i, pFilter->aFields[i].enmMatch, psz, rc));
444 return rc;
445 }
446 break;
447
448 case USBFILTERMATCH_STR_EXACT:
449 case USBFILTERMATCH_STR_EXACT_NP:
450 if (!USBFilterIsStringField((USBFILTERIDX)i))
451 {
452 Log(("USBFilter: %p - #%d / %d - not string field\n",
453 pFilter, i, pFilter->aFields[i].enmMatch));
454 return VERR_INVALID_PARAMETER;
455 }
456 if ( pFilter->aFields[i].u16Value >= pFilter->offCurEnd
457 && pFilter->offCurEnd)
458 {
459 Log(("USBFilter: %p - #%d / %d - off=%#x max=%#x\n",
460 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value, pFilter->offCurEnd));
461 return VERR_INVALID_PARAMETER;
462 }
463 break;
464
465 case USBFILTERMATCH_STR_PATTERN:
466 case USBFILTERMATCH_STR_PATTERN_NP:
467 if (!USBFilterIsStringField((USBFILTERIDX)i))
468 {
469 Log(("USBFilter: %p - #%d / %d - not string field\n",
470 pFilter, i, pFilter->aFields[i].enmMatch));
471 return VERR_INVALID_PARAMETER;
472 }
473 if ( pFilter->aFields[i].u16Value >= pFilter->offCurEnd
474 && pFilter->offCurEnd)
475 {
476 Log(("USBFilter: %p - #%d / %d - off=%#x max=%#x\n",
477 pFilter, i, pFilter->aFields[i].enmMatch, pFilter->aFields[i].u16Value, pFilter->offCurEnd));
478 return VERR_INVALID_PARAMETER;
479 }
480 psz = &pFilter->achStrTab[pFilter->aFields[i].u16Value];
481 rc = usbfilterValidateStringPattern(psz);
482 if (RT_FAILURE(rc))
483 {
484 Log(("USBFilter: %p - #%d / %d - bad string pattern: %s (rc=%Rrc)\n",
485 pFilter, i, pFilter->aFields[i].enmMatch, psz, rc));
486 return rc;
487 }
488 break;
489
490 default:
491 Log(("USBFilter: %p - #%d enmMatch=%d!\n", pFilter, i, pFilter->aFields[i].enmMatch));
492 return VERR_INVALID_PARAMETER;
493 }
494 }
495
496 return VINF_SUCCESS;
497}
498
499
500/**
501 * Find the specified field in the string table.
502 *
503 * @returns Pointer to the string in the string table on success.
504 * NULL if the field is invalid or it doesn't have a string value.
505 * @param pFilter The filter.
506 * @param enmFieldIdx The field index.
507 */
508DECLINLINE(const char *) usbfilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
509{
510 if ((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
511 {
512 switch (pFilter->aFields[enmFieldIdx].enmMatch)
513 {
514 case USBFILTERMATCH_NUM_EXPRESSION:
515 case USBFILTERMATCH_NUM_EXPRESSION_NP:
516 case USBFILTERMATCH_STR_EXACT:
517 case USBFILTERMATCH_STR_EXACT_NP:
518 case USBFILTERMATCH_STR_PATTERN:
519 case USBFILTERMATCH_STR_PATTERN_NP:
520 Assert(pFilter->aFields[enmFieldIdx].u16Value < sizeof(pFilter->achStrTab));
521 return &pFilter->achStrTab[pFilter->aFields[enmFieldIdx].u16Value];
522
523 default:
524 AssertMsgFailed(("%d\n", pFilter->aFields[enmFieldIdx].enmMatch));
525 case USBFILTERMATCH_IGNORE:
526 case USBFILTERMATCH_PRESENT:
527 case USBFILTERMATCH_NUM_EXACT:
528 case USBFILTERMATCH_NUM_EXACT_NP:
529 break;
530 }
531 }
532 return NULL;
533}
534
535
536/**
537 * Gets a number value of a field.
538 *
539 * The field must contain a numeric value.
540 *
541 * @returns The field value on success, -1 on failure (invalid input / not numeric).
542 * @param pFilter The filter.
543 * @param enmFieldIdx The field index.
544 */
545DECLINLINE(int) usbfilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
546{
547 if ((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
548 {
549 switch (pFilter->aFields[enmFieldIdx].enmMatch)
550 {
551 case USBFILTERMATCH_NUM_EXACT:
552 case USBFILTERMATCH_NUM_EXACT_NP:
553 return pFilter->aFields[enmFieldIdx].u16Value;
554
555 default:
556 AssertMsgFailed(("%d\n", pFilter->aFields[enmFieldIdx].enmMatch));
557 case USBFILTERMATCH_IGNORE:
558 case USBFILTERMATCH_PRESENT:
559 case USBFILTERMATCH_NUM_EXPRESSION:
560 case USBFILTERMATCH_NUM_EXPRESSION_NP:
561 case USBFILTERMATCH_STR_EXACT:
562 case USBFILTERMATCH_STR_EXACT_NP:
563 case USBFILTERMATCH_STR_PATTERN:
564 case USBFILTERMATCH_STR_PATTERN_NP:
565 break;
566 }
567 }
568 return -1;
569}
570
571
572/**
573 * Performs simple pattern matching.
574 *
575 * @returns true on match and false on mismatch.
576 * @param pszExpr The numeric expression.
577 * @param u16Value The value to match.
578 */
579static bool usbfilterMatchNumExpression(const char *pszExpr, uint16_t u16Value)
580{
581 /*
582 * The string format is: "(<m>|([<m>]-[<n>]))|(<m>|([<m>]-[<n>]))+"
583 * where <m> and <n> are numbers in the decimal, hex (0xNNN) or octal (0NNN)
584 * form. Spaces are allowed around <m> and <n>.
585 */
586 while (*pszExpr)
587 {
588 /*
589 * Skip remnants of the previous expression and any empty expressions.
590 * ('|' is the expression separator.)
591 */
592 while (*pszExpr == '|' || RT_C_IS_BLANK(*pszExpr))
593 pszExpr++;
594 if (!*pszExpr)
595 break;
596
597 /*
598 * Parse the expression.
599 */
600 int rc;
601 uint16_t u16First = 0;
602 uint16_t u16Last = 0;
603 if (*pszExpr == '-')
604 {
605 /* -N */
606 pszExpr++;
607 rc = usbfilterReadNumber(&pszExpr, &u16Last);
608 }
609 else
610 {
611 /* M or M-N */
612 rc = usbfilterReadNumber(&pszExpr, &u16First);
613 if (RT_SUCCESS(rc))
614 {
615 pszExpr = usbfilterSkipBlanks(pszExpr);
616 if (*pszExpr == '-')
617 {
618 /* M-N */
619 pszExpr++;
620 rc = usbfilterReadNumber(&pszExpr, &u16Last);
621 }
622 else
623 {
624 /* M */
625 u16Last = u16First;
626 }
627 }
628 }
629
630 /* On success, we should either be at the end of the string or
631 at an expression separator (|). */
632 if (RT_SUCCESS(rc) && *pszExpr && *pszExpr != '|' )
633 rc = VERR_INVALID_PARAMETER;
634 if (RT_SUCCESS(rc))
635 {
636 /*
637 * Swap the values if the order is mixed up.
638 */
639 if (u16First > u16Last)
640 {
641 uint16_t u16Tmp = u16First;
642 u16First = u16Last;
643 u16Last = u16Tmp;
644 }
645
646 /*
647 * Perform the compare.
648 */
649 if ( u16Value >= u16First
650 && u16Value <= u16Last)
651 return true;
652 }
653 else
654 {
655 /*
656 * Skip the bad expression.
657 * ('|' is the expression separator.)
658 */
659 while (*pszExpr && *pszExpr != '|')
660 pszExpr++;
661 }
662 }
663
664 return false;
665}
666
667
668/**
669 * Performs simple pattern matching.
670 *
671 * @returns true on match and false on mismatch.
672 * @param pszPattern The pattern to match against.
673 * @param psz The string to match.
674 */
675static bool usbfilterMatchStringPattern(const char *pszPattern, const char *psz)
676{
677 char ch;
678 while ((ch = *pszPattern++))
679 {
680 if (ch == '?')
681 {
682 /*
683 * Matches one char or end of string.
684 */
685 if (*psz)
686 psz++;
687 }
688 else if (ch == '*')
689 {
690 /*
691 * Matches zero or more characters.
692 */
693 /* skip subsequent wildcards */
694 while ( (ch = *pszPattern) == '*'
695 || ch == '?')
696 pszPattern++;
697 if (!ch)
698 /* Pattern ends with a '*' and thus matches the rest of psz. */
699 return true;
700
701 /* Find the length of the following exact pattern sequence. */
702 ssize_t cchMatch = 1;
703 while ( (ch = pszPattern[cchMatch]) != '\0'
704 && ch != '*'
705 && ch != '?')
706 cchMatch++;
707
708 /* Check if the exact pattern sequence is too long. */
709 ssize_t cch = strlen(psz);
710 cch -= cchMatch;
711 if (cch < 0)
712 return false;
713
714 /* Is the rest an exact match? */
715 if (!ch)
716 return memcmp(psz + cch, pszPattern, cchMatch) == 0;
717
718 /*
719 * This is where things normally starts to get recursive or ugly.
720 *
721 * Just to make life simple, we'll skip the nasty stuff and say
722 * that we will do a maximal wildcard match and forget about any
723 * alternative matches.
724 *
725 * If somebody is bored out of their mind one day, feel free to
726 * implement correct matching without using recursion.
727 */
728 ch = *pszPattern;
729 const char *pszMatch = NULL;
730 while ( cch-- >= 0
731 && *psz)
732 {
733 if ( *psz == ch
734 && !strncmp(psz, pszPattern, cchMatch))
735 pszMatch = psz;
736 psz++;
737 }
738 if (!pszMatch)
739 return false;
740
741 /* advance */
742 psz = pszMatch + cchMatch;
743 pszPattern += cchMatch;
744 }
745 else
746 {
747 /* exact match */
748 if (ch != *psz)
749 return false;
750 psz++;
751 }
752 }
753
754 return *psz == '\0';
755}
756
757
758/**
759 * Match a filter against a device.
760 *
761 * @returns true if they match, false if not.
762 *
763 * @param pFilter The filter to match with.
764 * @param pDevice The device data. This is a filter (type ignored) that
765 * contains 'exact' values for all present fields and 'ignore'
766 * values for the non-present fields.
767 *
768 * @remark Both the filter and the device are ASSUMED to be valid because
769 * we don't wish to waste any time in this function.
770 */
771USBLIB_DECL(bool) USBFilterMatch(PCUSBFILTER pFilter, PCUSBFILTER pDevice)
772{
773 return USBFilterMatchRated(pFilter, pDevice) > 0;
774}
775
776
777#if 0 /*def IN_RING0*/ /** @todo convert to proper logging. */
778extern "C" int printf(const char *format, ...);
779# define dprintf(a) printf a
780#else
781# define dprintf(a) do {} while (0)
782#endif
783
784/**
785 * Match a filter against a device and rate the result.
786 *
787 * @returns -1 if no match, matching rate between 1 and 100 (inclusive) if matched.
788 *
789 * @param pFilter The filter to match with.
790 * @param pDevice The device data. This is a filter (type ignored) that
791 * contains 'exact' values for all present fields and 'ignore'
792 * values for the non-present fields.
793 *
794 * @remark Both the filter and the device are ASSUMED to be valid because
795 * we don't wish to waste any time in this function.
796 */
797USBLIB_DECL(int) USBFilterMatchRated(PCUSBFILTER pFilter, PCUSBFILTER pDevice)
798{
799 unsigned iRate = 0;
800dprintf(("USBFilterMatchRated: %p %p\n", pFilter, pDevice));
801
802 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
803 {
804 switch (pFilter->aFields[i].enmMatch)
805 {
806 case USBFILTERMATCH_IGNORE:
807 iRate += 2;
808 break;
809
810 case USBFILTERMATCH_PRESENT:
811 if (pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE)
812 {
813dprintf(("filter match[%d]: !present\n", i));
814 return -1;
815 }
816 iRate += 2;
817 break;
818
819 case USBFILTERMATCH_NUM_EXACT:
820 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
821 || pFilter->aFields[i].u16Value != pDevice->aFields[i].u16Value)
822 {
823if (pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE)
824 dprintf(("filter match[%d]: !num_exact device=ignore\n", i));
825else
826 dprintf(("filter match[%d]: !num_exact %#x (filter) != %#x (device)\n", i, pFilter->aFields[i].u16Value, pDevice->aFields[i].u16Value));
827 return -1;
828 }
829 iRate += 2;
830 break;
831
832 case USBFILTERMATCH_NUM_EXACT_NP:
833 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
834 && pFilter->aFields[i].u16Value != pDevice->aFields[i].u16Value)
835 {
836dprintf(("filter match[%d]: !num_exact_np %#x (filter) != %#x (device)\n", i, pFilter->aFields[i].u16Value, pDevice->aFields[i].u16Value));
837 return -1;
838 }
839 iRate += 2;
840 break;
841
842 case USBFILTERMATCH_NUM_EXPRESSION:
843 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
844 || !usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i),
845 pDevice->aFields[i].u16Value))
846 {
847dprintf(("filter match[%d]: !num_expression\n", i));
848 return -1;
849 }
850 iRate += 1;
851 break;
852
853 case USBFILTERMATCH_NUM_EXPRESSION_NP:
854 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
855 && !usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i),
856 pDevice->aFields[i].u16Value))
857 {
858dprintf(("filter match[%d]: !num_expression_no\n", i));
859 return -1;
860 }
861 iRate += 1;
862 break;
863
864 case USBFILTERMATCH_STR_EXACT:
865 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
866 || strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i),
867 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
868 {
869dprintf(("filter match[%d]: !str_exact\n", i));
870 return -1;
871 }
872 iRate += 2;
873 break;
874
875 case USBFILTERMATCH_STR_EXACT_NP:
876 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
877 && strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i),
878 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
879 {
880dprintf(("filter match[%d]: !str_exact_np\n", i));
881 return -1;
882 }
883 iRate += 2;
884 break;
885
886 case USBFILTERMATCH_STR_PATTERN:
887 if ( pDevice->aFields[i].enmMatch == USBFILTERMATCH_IGNORE
888 || !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i),
889 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
890 {
891dprintf(("filter match[%d]: !str_pattern\n", i));
892 return -1;
893 }
894 iRate += 1;
895 break;
896
897 case USBFILTERMATCH_STR_PATTERN_NP:
898 if ( pDevice->aFields[i].enmMatch != USBFILTERMATCH_IGNORE
899 && !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i),
900 usbfilterGetString(pDevice, (USBFILTERIDX)i)))
901 {
902dprintf(("filter match[%d]: !str_pattern_np\n", i));
903 return -1;
904 }
905 iRate += 1;
906 break;
907
908 default:
909 AssertMsgFailed(("#%d: %d\n", i, pFilter->aFields[i].enmMatch));
910 return -1;
911 }
912 }
913
914 /* iRate is the range 0..2*cFields - recalc to percent. */
915dprintf(("filter match: iRate=%d", iRate));
916 return iRate == 2 * RT_ELEMENTS(pFilter->aFields)
917 ? 100
918 : (iRate * 100) / (2 * RT_ELEMENTS(pFilter->aFields));
919}
920
921
922/**
923 * Match a filter against a USBDEVICE.
924 *
925 * @returns true if they match, false if not.
926 *
927 * @param pFilter The filter to match with.
928 * @param pDevice The device to match.
929 *
930 * @remark Both the filter and the device are ASSUMED to be valid because
931 * we don't wish to waste any time in this function.
932 */
933USBLIB_DECL(bool) USBFilterMatchDevice(PCUSBFILTER pFilter, PUSBDEVICE pDevice)
934{
935 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
936 {
937 switch (pFilter->aFields[i].enmMatch)
938 {
939 case USBFILTERMATCH_IGNORE:
940 break;
941
942 case USBFILTERMATCH_PRESENT:
943 {
944 const char *psz;
945 switch (i)
946 {
947 case USBFILTERIDX_MANUFACTURER_STR: psz = pDevice->pszManufacturer; break;
948 case USBFILTERIDX_PRODUCT_STR: psz = pDevice->pszProduct; break;
949 case USBFILTERIDX_SERIAL_NUMBER_STR: psz = pDevice->pszSerialNumber; break;
950 default: psz = ""; break;
951 }
952 if (!psz)
953 return false;
954 break;
955 }
956
957 case USBFILTERMATCH_NUM_EXACT:
958 case USBFILTERMATCH_NUM_EXACT_NP:
959 case USBFILTERMATCH_NUM_EXPRESSION:
960 case USBFILTERMATCH_NUM_EXPRESSION_NP:
961 {
962 uint16_t u16Value;
963 switch (i)
964 {
965 case USBFILTERIDX_VENDOR_ID: u16Value = pDevice->idVendor; break;
966 case USBFILTERIDX_PRODUCT_ID: u16Value = pDevice->idProduct; break;
967 case USBFILTERIDX_DEVICE: u16Value = pDevice->bcdDevice; break;
968 case USBFILTERIDX_DEVICE_CLASS: u16Value = pDevice->bDeviceClass; break;
969 case USBFILTERIDX_DEVICE_SUB_CLASS: u16Value = pDevice->bDeviceSubClass; break;
970 case USBFILTERIDX_DEVICE_PROTOCOL: u16Value = pDevice->bDeviceProtocol; break;
971 case USBFILTERIDX_BUS: u16Value = pDevice->bBus; break;
972 case USBFILTERIDX_PORT: u16Value = pDevice->bPort; break;
973 default: u16Value = UINT16_MAX; break;
974
975 }
976 switch (pFilter->aFields[i].enmMatch)
977 {
978 case USBFILTERMATCH_NUM_EXACT:
979 case USBFILTERMATCH_NUM_EXACT_NP:
980 if (pFilter->aFields[i].u16Value != u16Value)
981 return false;
982 break;
983 case USBFILTERMATCH_NUM_EXPRESSION:
984 case USBFILTERMATCH_NUM_EXPRESSION_NP:
985 if (!usbfilterMatchNumExpression(usbfilterGetString(pFilter, (USBFILTERIDX)i), u16Value))
986 return false;
987 break;
988 }
989 break;
990 }
991
992 case USBFILTERMATCH_STR_EXACT:
993 case USBFILTERMATCH_STR_EXACT_NP:
994 case USBFILTERMATCH_STR_PATTERN:
995 case USBFILTERMATCH_STR_PATTERN_NP:
996 {
997 const char *psz;
998 switch (i)
999 {
1000 case USBFILTERIDX_MANUFACTURER_STR: psz = pDevice->pszManufacturer; break;
1001 case USBFILTERIDX_PRODUCT_STR: psz = pDevice->pszProduct; break;
1002 case USBFILTERIDX_SERIAL_NUMBER_STR: psz = pDevice->pszSerialNumber; break;
1003 default: psz = NULL; break;
1004 }
1005 switch (pFilter->aFields[i].enmMatch)
1006 {
1007 case USBFILTERMATCH_STR_EXACT:
1008 if ( !psz
1009 || strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1010 return false;
1011 break;
1012
1013 case USBFILTERMATCH_STR_EXACT_NP:
1014 if ( psz
1015 && strcmp(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1016 return false;
1017 break;
1018
1019 case USBFILTERMATCH_STR_PATTERN:
1020 if ( !psz
1021 || !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1022 return false;
1023 break;
1024
1025 case USBFILTERMATCH_STR_PATTERN_NP:
1026 if ( psz
1027 && !usbfilterMatchStringPattern(usbfilterGetString(pFilter, (USBFILTERIDX)i), psz))
1028 return false;
1029 break;
1030 }
1031 break;
1032 }
1033
1034 default:
1035 AssertMsgFailed(("#%d: %d\n", i, pFilter->aFields[i].enmMatch));
1036 return false;
1037 }
1038 }
1039
1040 return true;
1041}
1042
1043
1044/**
1045 * Checks if the two filters are identical.
1046 *
1047 * @returns true if the are identical, false if they aren't.
1048 * @param pFilter The first filter.
1049 * @param pFilter2 The second filter.
1050 */
1051USBLIB_DECL(bool) USBFilterIsIdentical(PCUSBFILTER pFilter, PCUSBFILTER pFilter2)
1052{
1053 /* Lazy works here because we're darn strict with zero padding and such elsewhere. */
1054 return memcmp(pFilter, pFilter2, sizeof(*pFilter)) == 0;
1055}
1056
1057
1058
1059/**
1060 * Sets the filter type.
1061 *
1062 * @returns VBox status code.
1063 * @retval VERR_INVALID_PARAMETER if the filter type is invalid.
1064 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1065 *
1066 * @param pFilter The filter.
1067 * @param enmType The new filter type.
1068 */
1069USBLIB_DECL(int) USBFilterSetFilterType(PUSBFILTER pFilter, USBFILTERTYPE enmType)
1070{
1071 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1072 AssertReturn(enmType > USBFILTERTYPE_INVALID && enmType < USBFILTERTYPE_END, VERR_INVALID_PARAMETER);
1073
1074 pFilter->enmType = enmType;
1075 return VINF_SUCCESS;
1076}
1077
1078
1079/**
1080 * Replaces the string value of a field.
1081 *
1082 * This will remove any existing string value current held by the field from the
1083 * string table and then attempt to add the new value. This function can be used
1084 * to delete any assigned string before changing the type to numeric by passing
1085 * in an empty string. This works because the first byte in the string table is
1086 * reserved for the empty (NULL) string.
1087 *
1088 * @returns VBox status code.
1089 * @retval VINF_SUCCESS on success.
1090 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1091 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1092 * @retval VERR_INVALID_POINTER if pszString isn't valid.
1093 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1094 *
1095 * @param pFilter The filter.
1096 * @param enmFieldIdx The field index.
1097 * @param pszString The string to add.
1098 * @param fPurge Purge invalid UTF-8 encoding and control characters
1099 * before setting it.
1100 */
1101static int usbfilterSetString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszString, bool fPurge)
1102{
1103 /*
1104 * Validate input.
1105 */
1106 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1107 AssertReturn((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END, VERR_INVALID_PARAMETER);
1108 AssertPtrReturn(pszString, VERR_INVALID_POINTER);
1109
1110 Assert(pFilter->offCurEnd < sizeof(pFilter->achStrTab));
1111 Assert(pFilter->achStrTab[pFilter->offCurEnd] == '\0');
1112
1113 /*
1114 * Remove old string value if any.
1115 */
1116 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch)
1117 && pFilter->aFields[enmFieldIdx].u16Value != 0)
1118 {
1119 uint32_t off = pFilter->aFields[enmFieldIdx].u16Value;
1120 pFilter->aFields[enmFieldIdx].u16Value = 0; /* Assign it to the NULL string. */
1121
1122 unsigned cchShift = (unsigned)strlen(&pFilter->achStrTab[off]) + 1;
1123 ssize_t cchToMove = (pFilter->offCurEnd + 1) - (off + cchShift);
1124 Assert(cchToMove >= 0);
1125 if (cchToMove > 0)
1126 {
1127 /* We're not last - must shift the strings. */
1128 memmove(&pFilter->achStrTab[off], &pFilter->achStrTab[off + cchShift], cchToMove);
1129 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
1130 if ( pFilter->aFields[i].u16Value >= off
1131 && USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[i].enmMatch))
1132 pFilter->aFields[i].u16Value -= cchShift;
1133 }
1134 pFilter->offCurEnd -= cchShift;
1135 Assert(pFilter->offCurEnd < sizeof(pFilter->achStrTab));
1136 Assert(pFilter->offCurEnd + cchShift <= sizeof(pFilter->achStrTab));
1137
1138 /* zero the unused string table (to allow lazyness/strictness elsewhere). */
1139 memset(&pFilter->achStrTab[pFilter->offCurEnd], '\0', cchShift);
1140 }
1141
1142 /*
1143 * Make a special case for the empty string.
1144 * (This also makes the delete logical above work correctly for the last string.)
1145 */
1146 if (!*pszString)
1147 pFilter->aFields[enmFieldIdx].u16Value = 0;
1148 else
1149 {
1150 size_t cch = strlen(pszString);
1151 if (pFilter->offCurEnd + cch + 2 > sizeof(pFilter->achStrTab))
1152 return VERR_BUFFER_OVERFLOW;
1153
1154 pFilter->aFields[enmFieldIdx].u16Value = pFilter->offCurEnd + 1;
1155 memcpy(&pFilter->achStrTab[pFilter->offCurEnd + 1], pszString, cch + 1);
1156 if (fPurge)
1157 cch = USBLibPurgeEncoding(&pFilter->achStrTab[pFilter->offCurEnd + 1]);
1158 pFilter->offCurEnd += (uint32_t)cch + 1;
1159 }
1160
1161 return VINF_SUCCESS;
1162}
1163
1164/**
1165 * Wrapper around usbfilterSetString() that deletes any string value
1166 * currently assigned to a field.
1167 *
1168 * Upon successful return the field contains a null string, nothing or a number.
1169 *
1170 * This function will validate the field index if there isn't any string
1171 * value to delete, thus preventing any extra validating of the index.
1172 *
1173 * @returns VBox status code. See usbfilterSetString.
1174 * @param pFilter The filter.
1175 * @param enmFieldIdx The index of the field which string value should be deleted.
1176 */
1177static int usbfilterDeleteAnyStringValue(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1178{
1179 int rc = VINF_SUCCESS;
1180 if ( USBFilterIsMethodUsingStringValue((USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch)
1181 && pFilter->aFields[enmFieldIdx].u16Value != 0)
1182 rc = usbfilterSetString(pFilter, enmFieldIdx, "", false /*fPurge*/);
1183 else if ((unsigned)enmFieldIdx >= (unsigned)USBFILTERIDX_END)
1184 rc = VERR_INVALID_PARAMETER;
1185 return rc;
1186}
1187
1188
1189/**
1190 * Sets a field to always match (ignore whatever is thrown at it).
1191 *
1192 * @returns VBox status code.
1193 * @retval VINF_SUCCESS on success.
1194 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1195 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1196 *
1197 * @param pFilter The filter.
1198 * @param enmFieldIdx The field index. This must be a string field.
1199 */
1200USBLIB_DECL(int) USBFilterSetIgnore(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1201{
1202 int rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1203 if (RT_SUCCESS(rc))
1204 {
1205 pFilter->aFields[enmFieldIdx].enmMatch = USBFILTERMATCH_IGNORE;
1206 pFilter->aFields[enmFieldIdx].u16Value = 0;
1207 }
1208 return rc;
1209}
1210
1211
1212/**
1213 * Sets a field to match on device field present only.
1214 *
1215 * @returns VBox status code.
1216 * @retval VINF_SUCCESS on success.
1217 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1218 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1219 *
1220 * @param pFilter The filter.
1221 * @param enmFieldIdx The field index. This must be a string field.
1222 */
1223USBLIB_DECL(int) USBFilterSetPresentOnly(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1224{
1225 int rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1226 if (RT_SUCCESS(rc))
1227 {
1228 pFilter->aFields[enmFieldIdx].enmMatch = USBFILTERMATCH_PRESENT;
1229 pFilter->aFields[enmFieldIdx].u16Value = 0;
1230 }
1231 return rc;
1232}
1233
1234
1235/**
1236 * Sets a field to exactly match a number.
1237 *
1238 * @returns VBox status code.
1239 * @retval VINF_SUCCESS on success.
1240 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1241 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1242 *
1243 * @param pFilter The filter.
1244 * @param enmFieldIdx The field index. This must be a string field.
1245 * @param u16Value The string pattern.
1246 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1247 * If clear, a non-present field on the device will match.
1248 */
1249USBLIB_DECL(int) USBFilterSetNumExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t u16Value, bool fMustBePresent)
1250{
1251 int rc = USBFilterIsNumericField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1252 if (RT_SUCCESS(rc))
1253 {
1254 rc = usbfilterDeleteAnyStringValue(pFilter, enmFieldIdx);
1255 if (RT_SUCCESS(rc))
1256 {
1257 pFilter->aFields[enmFieldIdx].u16Value = u16Value;
1258 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_NUM_EXACT : USBFILTERMATCH_NUM_EXACT_NP;
1259 }
1260 }
1261
1262 return rc;
1263}
1264
1265
1266/**
1267 * Sets a field to match a numeric expression.
1268 *
1269 * @returns VBox status code.
1270 * @retval VINF_SUCCESS on success.
1271 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1272 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or the numeric expression aren't valid.
1273 * @retval VERR_INVALID_POINTER if pszExpression isn't a valid pointer.
1274 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1275 *
1276 * @param pFilter The filter.
1277 * @param enmFieldIdx The field index. This must be a string field.
1278 * @param pszExpression The numeric expression.
1279 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1280 * If clear, a non-present field on the device will match.
1281 */
1282USBLIB_DECL(int) USBFilterSetNumExpression(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszExpression, bool fMustBePresent)
1283{
1284 int rc = USBFilterIsNumericField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1285 if (RT_SUCCESS(rc))
1286 {
1287 /* Strip leading spaces and empty sub expressions (||). */
1288 while (*pszExpression && (RT_C_IS_BLANK(*pszExpression) || *pszExpression == '|'))
1289 pszExpression++;
1290
1291 rc = usbfilterValidateNumExpression(pszExpression);
1292 if (RT_SUCCESS(rc))
1293 {
1294 /* We could optimize the expression further (stripping spaces, convert numbers),
1295 but it's more work than what it's worth and it could upset some users. */
1296 rc = usbfilterSetString(pFilter, enmFieldIdx, pszExpression, false /*fPurge*/);
1297 if (RT_SUCCESS(rc))
1298 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_NUM_EXPRESSION : USBFILTERMATCH_NUM_EXPRESSION_NP;
1299 else if (rc == VERR_NO_DIGITS)
1300 rc = VERR_INVALID_PARAMETER;
1301 }
1302 }
1303 return rc;
1304}
1305
1306
1307/**
1308 * Sets a field to exactly match a string.
1309 *
1310 * @returns VBox status code.
1311 * @retval VINF_SUCCESS on success.
1312 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1313 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid.
1314 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1315 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1316 *
1317 * @param pFilter The filter.
1318 * @param enmFieldIdx The field index. This must be a string field.
1319 * @param pszValue The string value.
1320 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1321 * If clear, a non-present field on the device will match.
1322 * @param fPurge Purge invalid UTF-8 encoding and control
1323 * characters before setting it.
1324 */
1325USBLIB_DECL(int) USBFilterSetStringExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszValue,
1326 bool fMustBePresent, bool fPurge)
1327{
1328 int rc = USBFilterIsStringField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1329 if (RT_SUCCESS(rc))
1330 {
1331 rc = usbfilterSetString(pFilter, enmFieldIdx, pszValue, fPurge);
1332 if (RT_SUCCESS(rc))
1333 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_STR_EXACT : USBFILTERMATCH_STR_EXACT_NP;
1334 }
1335 return rc;
1336}
1337
1338
1339/**
1340 * Sets a field to match a string pattern.
1341 *
1342 * @returns VBox status code.
1343 * @retval VINF_SUCCESS on success.
1344 * @retval VERR_BUFFER_OVERFLOW if the string table is full.
1345 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or pattern aren't valid.
1346 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1347 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1348 *
1349 * @param pFilter The filter.
1350 * @param enmFieldIdx The field index. This must be a string field.
1351 * @param pszPattern The string pattern.
1352 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1353 * If clear, a non-present field on the device will match.
1354 */
1355USBLIB_DECL(int) USBFilterSetStringPattern(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszPattern, bool fMustBePresent)
1356{
1357 int rc = USBFilterIsStringField(enmFieldIdx) ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
1358 if (RT_SUCCESS(rc))
1359 {
1360 rc = usbfilterValidateStringPattern(pszPattern);
1361 if (RT_SUCCESS(rc))
1362 {
1363 rc = usbfilterSetString(pFilter, enmFieldIdx, pszPattern, false /*fPurge*/);
1364 if (RT_SUCCESS(rc))
1365 pFilter->aFields[enmFieldIdx].enmMatch = fMustBePresent ? USBFILTERMATCH_STR_PATTERN : USBFILTERMATCH_STR_PATTERN_NP;
1366 }
1367 }
1368 return rc;
1369}
1370
1371
1372/**
1373 * Sets the must-be-present part of a field.
1374 *
1375 * This only works on field which already has matching criteria. This means
1376 * that field marked 'ignore' will not be processed and will result in a
1377 * warning status code.
1378 *
1379 * @returns VBox status code.
1380 * @retval VINF_SUCCESS on success.
1381 * @retval VWRN_INVALID_PARAMETER if the field is marked 'ignore'. No assertions.
1382 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx or pattern aren't valid.
1383 * @retval VERR_INVALID_POINTER if pszPattern isn't a valid pointer.
1384 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1385 *
1386 * @param pFilter The filter.
1387 * @param enmFieldIdx The field index.
1388 * @param fMustBePresent If set, a non-present field on the device will result in a mismatch.
1389 * If clear, a non-present field on the device will match.
1390 */
1391USBLIB_DECL(int) USBFilterSetMustBePresent(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, bool fMustBePresent)
1392{
1393 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
1394 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1395 AssertReturn((unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END, VERR_INVALID_PARAMETER);
1396
1397 USBFILTERMATCH enmMatch = (USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch;
1398 if (fMustBePresent)
1399 {
1400 switch (enmMatch)
1401 {
1402 case USBFILTERMATCH_IGNORE:
1403 return VWRN_INVALID_PARAMETER;
1404
1405 case USBFILTERMATCH_PRESENT:
1406 case USBFILTERMATCH_NUM_EXACT:
1407 case USBFILTERMATCH_NUM_EXPRESSION:
1408 case USBFILTERMATCH_STR_EXACT:
1409 case USBFILTERMATCH_STR_PATTERN:
1410 break;
1411
1412 case USBFILTERMATCH_NUM_EXACT_NP:
1413 enmMatch = USBFILTERMATCH_NUM_EXACT;
1414 break;
1415 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1416 enmMatch = USBFILTERMATCH_NUM_EXPRESSION;
1417 break;
1418 case USBFILTERMATCH_STR_EXACT_NP:
1419 enmMatch = USBFILTERMATCH_STR_EXACT;
1420 break;
1421 case USBFILTERMATCH_STR_PATTERN_NP:
1422 enmMatch = USBFILTERMATCH_STR_PATTERN;
1423 break;
1424 default:
1425 AssertMsgFailedReturn(("%p: enmFieldIdx=%d enmMatch=%d\n", pFilter, enmFieldIdx, enmMatch), VERR_INVALID_MAGIC);
1426 }
1427 }
1428 else
1429 {
1430 switch (enmMatch)
1431 {
1432 case USBFILTERMATCH_IGNORE:
1433 return VWRN_INVALID_PARAMETER;
1434
1435 case USBFILTERMATCH_NUM_EXACT_NP:
1436 case USBFILTERMATCH_STR_PATTERN_NP:
1437 case USBFILTERMATCH_STR_EXACT_NP:
1438 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1439 break;
1440
1441 case USBFILTERMATCH_PRESENT:
1442 enmMatch = USBFILTERMATCH_IGNORE;
1443 break;
1444 case USBFILTERMATCH_NUM_EXACT:
1445 enmMatch = USBFILTERMATCH_NUM_EXACT_NP;
1446 break;
1447 case USBFILTERMATCH_NUM_EXPRESSION:
1448 enmMatch = USBFILTERMATCH_NUM_EXPRESSION_NP;
1449 break;
1450 case USBFILTERMATCH_STR_EXACT:
1451 enmMatch = USBFILTERMATCH_STR_EXACT_NP;
1452 break;
1453 case USBFILTERMATCH_STR_PATTERN:
1454 enmMatch = USBFILTERMATCH_STR_PATTERN_NP;
1455 break;
1456
1457 default:
1458 AssertMsgFailedReturn(("%p: enmFieldIdx=%d enmMatch=%d\n", pFilter, enmFieldIdx, enmMatch), VERR_INVALID_MAGIC);
1459 }
1460 }
1461
1462 pFilter->aFields[enmFieldIdx].enmMatch = enmMatch;
1463 return VINF_SUCCESS;
1464}
1465
1466
1467/**
1468 * Gets the filter type.
1469 *
1470 * @returns The filter type.
1471 * USBFILTERTYPE_INVALID if the filter is invalid.
1472 * @param pFilter The filter.
1473 */
1474USBLIB_DECL(USBFILTERTYPE) USBFilterGetFilterType(PCUSBFILTER pFilter)
1475{
1476 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, USBFILTERTYPE_INVALID);
1477 return pFilter->enmType;
1478}
1479
1480
1481/**
1482 * Gets the matching method for a field.
1483 *
1484 * @returns The matching method on success, UBFILTERMATCH_INVALID on invalid field index.
1485 * @param pFilter The filter.
1486 * @param enmFieldIdx The field index.
1487 */
1488USBLIB_DECL(USBFILTERMATCH) USBFilterGetMatchingMethod(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1489{
1490 if ( pFilter->u32Magic == USBFILTER_MAGIC
1491 && (unsigned)enmFieldIdx < (unsigned)USBFILTERIDX_END)
1492 return (USBFILTERMATCH)pFilter->aFields[enmFieldIdx].enmMatch;
1493 return USBFILTERMATCH_INVALID;
1494}
1495
1496
1497/**
1498 * Gets the numeric value of a field.
1499 *
1500 * The field must contain a number, we're not doing any conversions for you.
1501 *
1502 * @returns VBox status code.
1503 * @retval VINF_SUCCESS on success.
1504 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid or if the field doesn't contain a number.
1505 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1506 *
1507 * @param pFilter The filter.
1508 * @param enmFieldIdx The field index.
1509 * @param pu16Value Where to store the value.
1510 */
1511USBLIB_DECL(int) USBFilterQueryNum(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t *pu16Value)
1512{
1513 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1514 int iValue = usbfilterGetNum(pFilter, enmFieldIdx);
1515 if (iValue == -1)
1516 return VERR_INVALID_PARAMETER;
1517 *pu16Value = (uint16_t)iValue;
1518 return VINF_SUCCESS;
1519}
1520
1521
1522/**
1523 * Gets the numeric value of a field.
1524 *
1525 * The field must contain a number, we're not doing any conversions for you.
1526 *
1527 * @returns The field value on success, -1 on failure (invalid input / not numeric).
1528 *
1529 * @param pFilter The filter.
1530 * @param enmFieldIdx The field index.
1531 */
1532USBLIB_DECL(int) USBFilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1533{
1534 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, -1);
1535 return usbfilterGetNum(pFilter, enmFieldIdx);
1536}
1537
1538
1539/**
1540 * Gets the string value of a field.
1541 *
1542 * The field must contain a string, we're not doing any conversions for you.
1543 *
1544 * @returns VBox status code.
1545 * @retval VINF_SUCCESS on success.
1546 * @retval VERR_BUFFER_OVERFLOW if the buffer isn't sufficient to hold the string. The buffer
1547 * will be filled with as much of the string that'll fit.
1548 * @retval VERR_INVALID_PARAMETER if the enmFieldIdx isn't valid or if the field doesn't contain a string.
1549 * @retval VERR_INVALID_MAGIC if pFilter is invalid.
1550 *
1551 * @param pFilter The filter.
1552 * @param enmFieldIdx The field index.
1553 * @param pszBuf Where to store the string.
1554 * @param cchBuf The size of the buffer.
1555 */
1556USBLIB_DECL(int) USBFilterQueryString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, char *pszBuf, size_t cchBuf)
1557{
1558 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, VERR_INVALID_MAGIC);
1559
1560 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1561 if (RT_UNLIKELY(!psz))
1562 return VERR_INVALID_PARAMETER;
1563
1564 int rc = VINF_SUCCESS;
1565 size_t cch = strlen(psz);
1566 if (cch < cchBuf)
1567 memcpy(pszBuf, psz, cch + 1);
1568 else
1569 {
1570 rc = VERR_BUFFER_OVERFLOW;
1571 if (cchBuf)
1572 {
1573 memcpy(pszBuf, psz, cchBuf - 1);
1574 pszBuf[cchBuf - 1] = '\0';
1575 }
1576 }
1577
1578 return rc;
1579}
1580
1581
1582/**
1583 * Gets the string table entry for a field.
1584 *
1585 * @returns Pointer to the string. (readonly!)
1586 *
1587 * @param pFilter The filter.
1588 * @param enmFieldIdx The field index.
1589 */
1590USBLIB_DECL(const char *) USBFilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1591{
1592 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, NULL);
1593
1594 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1595 if (RT_UNLIKELY(!psz))
1596 return NULL;
1597 return psz;
1598}
1599
1600
1601/**
1602 * Gets the string length of a field containing a string.
1603 *
1604 * @returns String length on success, -1 on failure (not a string, bad filter).
1605 * @param pFilter The filter.
1606 * @param enmFieldIdx The field index.
1607 */
1608USBLIB_DECL(ssize_t) USBFilterGetStringLen(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx)
1609{
1610 if (RT_LIKELY(pFilter->u32Magic == USBFILTER_MAGIC))
1611 {
1612 const char *psz = usbfilterGetString(pFilter, enmFieldIdx);
1613 if (RT_LIKELY(psz))
1614 return strlen(psz);
1615 }
1616 return -1;
1617}
1618
1619
1620/**
1621 * Check if any of the fields are set to something substatial.
1622 *
1623 * Consider the fileter a wildcard if this returns false.
1624 *
1625 * @returns true / false.
1626 * @param pFilter The filter.
1627 */
1628USBLIB_DECL(bool) USBFilterHasAnySubstatialCriteria(PCUSBFILTER pFilter)
1629{
1630 AssertReturn(pFilter->u32Magic == USBFILTER_MAGIC, false);
1631
1632 for (unsigned i = 0; i < RT_ELEMENTS(pFilter->aFields); i++)
1633 {
1634 switch (pFilter->aFields[i].enmMatch)
1635 {
1636 case USBFILTERMATCH_IGNORE:
1637 case USBFILTERMATCH_PRESENT:
1638 break;
1639
1640 case USBFILTERMATCH_NUM_EXACT:
1641 case USBFILTERMATCH_NUM_EXACT_NP:
1642 case USBFILTERMATCH_STR_EXACT:
1643 case USBFILTERMATCH_STR_EXACT_NP:
1644 return true;
1645
1646 case USBFILTERMATCH_NUM_EXPRESSION:
1647 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1648 {
1649 const char *psz = usbfilterGetString(pFilter, (USBFILTERIDX)i);
1650 if (psz)
1651 {
1652 while (*psz && (*psz == '|' || RT_C_IS_BLANK(*psz)))
1653 psz++;
1654 if (*psz)
1655 return true;
1656 }
1657 break;
1658 }
1659
1660 case USBFILTERMATCH_STR_PATTERN:
1661 case USBFILTERMATCH_STR_PATTERN_NP:
1662 {
1663 const char *psz = usbfilterGetString(pFilter, (USBFILTERIDX)i);
1664 if (psz)
1665 {
1666 while (*psz && (*psz == '*' || *psz == '?'))
1667 psz++;
1668 if (*psz)
1669 return true;
1670 }
1671 break;
1672 }
1673 }
1674 }
1675
1676 return false;
1677}
1678
1679
1680
1681/**
1682 * Checks whether the specified field is a numeric field or not.
1683 *
1684 * @returns true / false.
1685 * @param enmFieldIdx The field index.
1686 */
1687USBLIB_DECL(bool) USBFilterIsNumericField(USBFILTERIDX enmFieldIdx)
1688{
1689 switch (enmFieldIdx)
1690 {
1691 case USBFILTERIDX_VENDOR_ID:
1692 case USBFILTERIDX_PRODUCT_ID:
1693 case USBFILTERIDX_DEVICE:
1694 case USBFILTERIDX_DEVICE_CLASS:
1695 case USBFILTERIDX_DEVICE_SUB_CLASS:
1696 case USBFILTERIDX_DEVICE_PROTOCOL:
1697 case USBFILTERIDX_BUS:
1698 case USBFILTERIDX_PORT:
1699 return true;
1700
1701 default:
1702 AssertMsgFailed(("%d\n", enmFieldIdx));
1703 RT_FALL_THRU();
1704 case USBFILTERIDX_MANUFACTURER_STR:
1705 case USBFILTERIDX_PRODUCT_STR:
1706 case USBFILTERIDX_SERIAL_NUMBER_STR:
1707 return false;
1708 }
1709}
1710
1711
1712/**
1713 * Checks whether the specified field is a string field or not.
1714 *
1715 * @returns true / false.
1716 * @param enmFieldIdx The field index.
1717 */
1718USBLIB_DECL(bool) USBFilterIsStringField(USBFILTERIDX enmFieldIdx)
1719{
1720 switch (enmFieldIdx)
1721 {
1722 default:
1723 AssertMsgFailed(("%d\n", enmFieldIdx));
1724 RT_FALL_THRU();
1725 case USBFILTERIDX_VENDOR_ID:
1726 case USBFILTERIDX_PRODUCT_ID:
1727 case USBFILTERIDX_DEVICE:
1728 case USBFILTERIDX_DEVICE_CLASS:
1729 case USBFILTERIDX_DEVICE_SUB_CLASS:
1730 case USBFILTERIDX_DEVICE_PROTOCOL:
1731 case USBFILTERIDX_BUS:
1732 case USBFILTERIDX_PORT:
1733 return false;
1734
1735 case USBFILTERIDX_MANUFACTURER_STR:
1736 case USBFILTERIDX_PRODUCT_STR:
1737 case USBFILTERIDX_SERIAL_NUMBER_STR:
1738 return true;
1739 }
1740}
1741
1742
1743/**
1744 * Checks whether the specified matching method uses a numeric value or not.
1745 *
1746 * @returns true / false.
1747 * @param enmMatchingMethod The matching method.
1748 */
1749USBLIB_DECL(bool) USBFilterIsMethodUsingNumericValue(USBFILTERMATCH enmMatchingMethod)
1750{
1751 switch (enmMatchingMethod)
1752 {
1753 default:
1754 AssertMsgFailed(("%d\n", enmMatchingMethod));
1755 RT_FALL_THRU();
1756 case USBFILTERMATCH_IGNORE:
1757 case USBFILTERMATCH_PRESENT:
1758 case USBFILTERMATCH_NUM_EXPRESSION:
1759 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1760 case USBFILTERMATCH_STR_EXACT:
1761 case USBFILTERMATCH_STR_EXACT_NP:
1762 case USBFILTERMATCH_STR_PATTERN:
1763 case USBFILTERMATCH_STR_PATTERN_NP:
1764 return false;
1765
1766 case USBFILTERMATCH_NUM_EXACT:
1767 case USBFILTERMATCH_NUM_EXACT_NP:
1768 return true;
1769 }
1770}
1771
1772
1773/**
1774 * Checks whether the specified matching method uses a string value or not.
1775 *
1776 * @returns true / false.
1777 * @param enmMatchingMethod The matching method.
1778 */
1779USBLIB_DECL(bool) USBFilterIsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod)
1780{
1781 switch (enmMatchingMethod)
1782 {
1783 default:
1784 AssertMsgFailed(("%d\n", enmMatchingMethod));
1785 RT_FALL_THRU();
1786 case USBFILTERMATCH_IGNORE:
1787 case USBFILTERMATCH_PRESENT:
1788 case USBFILTERMATCH_NUM_EXACT:
1789 case USBFILTERMATCH_NUM_EXACT_NP:
1790 return false;
1791
1792 case USBFILTERMATCH_NUM_EXPRESSION:
1793 case USBFILTERMATCH_NUM_EXPRESSION_NP:
1794 case USBFILTERMATCH_STR_EXACT:
1795 case USBFILTERMATCH_STR_EXACT_NP:
1796 case USBFILTERMATCH_STR_PATTERN:
1797 case USBFILTERMATCH_STR_PATTERN_NP:
1798 return true;
1799 }
1800}
1801
1802
1803/**
1804 * Checks if a matching method is for numeric fields or not.
1805 *
1806 * @returns true / false.
1807 * @param enmMatchingMethod The matching method.
1808 */
1809USBLIB_DECL(bool) USBFilterIsMethodNumeric(USBFILTERMATCH enmMatchingMethod)
1810{
1811 return enmMatchingMethod >= USBFILTERMATCH_NUM_FIRST
1812 && enmMatchingMethod <= USBFILTERMATCH_NUM_LAST;
1813}
1814
1815/**
1816 * Checks if a matching method is for string fields or not.
1817 *
1818 * @returns true / false.
1819 * @param enmMatchingMethod The matching method.
1820 */
1821USBLIB_DECL(bool) USBFilterIsMethodString(USBFILTERMATCH enmMatchingMethod)
1822{
1823 return enmMatchingMethod >= USBFILTERMATCH_STR_FIRST
1824 && enmMatchingMethod <= USBFILTERMATCH_STR_LAST;
1825}
1826
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette