VirtualBox

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

Last change on this file since 76530 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

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