VirtualBox

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

Last change on this file since 44528 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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