drivers/usb/gadget/function/f_eem.c | 30 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-)
From: Markus Elfring <elfring@users.sourceforge.net>
Date: Wed, 25 Sep 2024 17:26:40 +0200
Add jump targets so that a bit of exception handling can be better reused
at the end of this function implementation.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
drivers/usb/gadget/function/f_eem.c | 30 ++++++++++++++---------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index 6de81ea17274..b1be23e947dc 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -450,24 +450,17 @@ static int eem_unwrap(struct gether *port,
ep = port->in_ep;
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
- if (!req) {
- dev_kfree_skb_any(skb2);
- goto next;
- }
+ if (!req)
+ goto free_skb;
req->buf = kmalloc(skb2->len, GFP_KERNEL);
- if (!req->buf) {
- usb_ep_free_request(ep, req);
- dev_kfree_skb_any(skb2);
- goto next;
- }
+ if (!req->buf)
+ goto free_request;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
kfree(req->buf);
- usb_ep_free_request(ep, req);
- dev_kfree_skb_any(skb2);
- goto next;
+ goto free_request;
}
ctx->skb = skb2;
ctx->ep = ep;
@@ -536,10 +529,9 @@ static int eem_unwrap(struct gether *port,
NET_IP_ALIGN,
0,
GFP_ATOMIC);
- if (unlikely(!skb3)) {
- dev_kfree_skb_any(skb2);
- goto next;
- }
+ if (unlikely(!skb3))
+ goto free_skb;
+
dev_kfree_skb_any(skb2);
skb_queue_tail(list, skb3);
}
@@ -550,6 +542,12 @@ static int eem_unwrap(struct gether *port,
error:
dev_kfree_skb_any(skb);
return status;
+
+free_request:
+ usb_ep_free_request(ep, req);
+free_skb:
+ dev_kfree_skb_any(skb2);
+ goto next;
}
static inline struct f_eem_opts *to_f_eem_opts(struct config_item *item)
--
2.46.1
Hi Markus,
kernel test robot noticed the following build errors:
[auto build test ERROR on usb/usb-testing]
[also build test ERROR on usb/usb-next usb/usb-linus westeri-thunderbolt/next linus/master v6.11 next-20240926]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Markus-Elfring/usb-gadget-eem-Use-common-error-handling-code-in-eem_unwrap/20240925-233931
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
patch link: https://lore.kernel.org/r/59fadd5a-6574-4379-98ac-cc4f11b675cc%40web.de
patch subject: [PATCH] usb: gadget: eem: Use common error handling code in eem_unwrap()
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20240926/202409261628.MdRLCYzn-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 7773243d9916f98ba0ffce0c3a960e4aa9f03e81)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240926/202409261628.MdRLCYzn-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202409261628.MdRLCYzn-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from drivers/usb/gadget/function/f_eem.c:13:
In file included from include/linux/etherdevice.h:20:
In file included from include/linux/if_ether.h:19:
In file included from include/linux/skbuff.h:17:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:10:
In file included from include/linux/mm.h:2232:
include/linux/vmstat.h:517:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
517 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
| ~~~~~~~~~~~ ^ ~~~
In file included from drivers/usb/gadget/function/f_eem.c:13:
In file included from include/linux/etherdevice.h:20:
In file included from include/linux/if_ether.h:19:
In file included from include/linux/skbuff.h:17:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:12:
In file included from include/linux/hardirq.h:11:
In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:14:
In file included from arch/hexagon/include/asm/io.h:328:
include/asm-generic/io.h:548:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
548 | val = __raw_readb(PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:561:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
561 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
| ^
In file included from drivers/usb/gadget/function/f_eem.c:13:
In file included from include/linux/etherdevice.h:20:
In file included from include/linux/if_ether.h:19:
In file included from include/linux/skbuff.h:17:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:12:
In file included from include/linux/hardirq.h:11:
In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:14:
In file included from arch/hexagon/include/asm/io.h:328:
include/asm-generic/io.h:574:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
574 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
| ~~~~~~~~~~ ^
include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
| ^
In file included from drivers/usb/gadget/function/f_eem.c:13:
In file included from include/linux/etherdevice.h:20:
In file included from include/linux/if_ether.h:19:
In file included from include/linux/skbuff.h:17:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:12:
In file included from include/linux/hardirq.h:11:
In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
In file included from include/asm-generic/hardirq.h:17:
In file included from include/linux/irq.h:20:
In file included from include/linux/io.h:14:
In file included from arch/hexagon/include/asm/io.h:328:
include/asm-generic/io.h:585:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
585 | __raw_writeb(value, PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:595:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
595 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
include/asm-generic/io.h:605:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
605 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
| ~~~~~~~~~~ ^
>> drivers/usb/gadget/function/f_eem.c:547:22: error: use of undeclared identifier 'ep'
547 | usb_ep_free_request(ep, req);
| ^
>> drivers/usb/gadget/function/f_eem.c:547:26: error: use of undeclared identifier 'req'
547 | usb_ep_free_request(ep, req);
| ^
>> drivers/usb/gadget/function/f_eem.c:549:20: error: use of undeclared identifier 'skb2'; did you mean 'skb'?
549 | dev_kfree_skb_any(skb2);
| ^~~~
| skb
drivers/usb/gadget/function/f_eem.c:393:20: note: 'skb' declared here
393 | struct sk_buff *skb,
| ^
7 warnings and 3 errors generated.
vim +/ep +547 drivers/usb/gadget/function/f_eem.c
387
388 /*
389 * Remove the EEM header. Note that there can be many EEM packets in a single
390 * USB transfer, so we need to break them out and handle them independently.
391 */
392 static int eem_unwrap(struct gether *port,
393 struct sk_buff *skb,
394 struct sk_buff_head *list)
395 {
396 struct usb_composite_dev *cdev = port->func.config->cdev;
397 int status = 0;
398
399 do {
400 struct sk_buff *skb2;
401 u16 header;
402 u16 len = 0;
403
404 if (skb->len < EEM_HLEN) {
405 status = -EINVAL;
406 DBG(cdev, "invalid EEM header\n");
407 goto error;
408 }
409
410 /* remove the EEM header */
411 header = get_unaligned_le16(skb->data);
412 skb_pull(skb, EEM_HLEN);
413
414 /* EEM packet header format:
415 * b0..14: EEM type dependent (data or command)
416 * b15: bmType (0 == data, 1 == command)
417 */
418 if (header & BIT(15)) {
419 struct usb_request *req;
420 struct in_context *ctx;
421 struct usb_ep *ep;
422 u16 bmEEMCmd;
423
424 /* EEM command packet format:
425 * b0..10: bmEEMCmdParam
426 * b11..13: bmEEMCmd
427 * b14: reserved (must be zero)
428 * b15: bmType (1 == command)
429 */
430 if (header & BIT(14))
431 continue;
432
433 bmEEMCmd = (header >> 11) & 0x7;
434 switch (bmEEMCmd) {
435 case 0: /* echo */
436 len = header & 0x7FF;
437 if (skb->len < len) {
438 status = -EOVERFLOW;
439 goto error;
440 }
441
442 skb2 = skb_clone(skb, GFP_ATOMIC);
443 if (unlikely(!skb2)) {
444 DBG(cdev, "EEM echo response error\n");
445 goto next;
446 }
447 skb_trim(skb2, len);
448 put_unaligned_le16(BIT(15) | BIT(11) | len,
449 skb_push(skb2, 2));
450
451 ep = port->in_ep;
452 req = usb_ep_alloc_request(ep, GFP_ATOMIC);
453 if (!req)
454 goto free_skb;
455
456 req->buf = kmalloc(skb2->len, GFP_KERNEL);
457 if (!req->buf)
458 goto free_request;
459
460 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
461 if (!ctx) {
462 kfree(req->buf);
463 goto free_request;
464 }
465 ctx->skb = skb2;
466 ctx->ep = ep;
467
468 skb_copy_bits(skb2, 0, req->buf, skb2->len);
469 req->length = skb2->len;
470 req->complete = eem_cmd_complete;
471 req->zero = 1;
472 req->context = ctx;
473 if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
474 DBG(cdev, "echo response queue fail\n");
475 break;
476
477 case 1: /* echo response */
478 case 2: /* suspend hint */
479 case 3: /* response hint */
480 case 4: /* response complete hint */
481 case 5: /* tickle */
482 default: /* reserved */
483 continue;
484 }
485 } else {
486 u32 crc, crc2;
487 struct sk_buff *skb3;
488
489 /* check for zero-length EEM packet */
490 if (header == 0)
491 continue;
492
493 /* EEM data packet format:
494 * b0..13: length of ethernet frame
495 * b14: bmCRC (0 == sentinel, 1 == calculated)
496 * b15: bmType (0 == data)
497 */
498 len = header & 0x3FFF;
499 if ((skb->len < len)
500 || (len < (ETH_HLEN + ETH_FCS_LEN))) {
501 status = -EINVAL;
502 goto error;
503 }
504
505 /* validate CRC */
506 if (header & BIT(14)) {
507 crc = get_unaligned_le32(skb->data + len
508 - ETH_FCS_LEN);
509 crc2 = ~crc32_le(~0,
510 skb->data, len - ETH_FCS_LEN);
511 } else {
512 crc = get_unaligned_be32(skb->data + len
513 - ETH_FCS_LEN);
514 crc2 = 0xdeadbeef;
515 }
516 if (crc != crc2) {
517 DBG(cdev, "invalid EEM CRC\n");
518 goto next;
519 }
520
521 skb2 = skb_clone(skb, GFP_ATOMIC);
522 if (unlikely(!skb2)) {
523 DBG(cdev, "unable to unframe EEM packet\n");
524 goto next;
525 }
526 skb_trim(skb2, len - ETH_FCS_LEN);
527
528 skb3 = skb_copy_expand(skb2,
529 NET_IP_ALIGN,
530 0,
531 GFP_ATOMIC);
532 if (unlikely(!skb3))
533 goto free_skb;
534
535 dev_kfree_skb_any(skb2);
536 skb_queue_tail(list, skb3);
537 }
538 next:
539 skb_pull(skb, len);
540 } while (skb->len);
541
542 error:
543 dev_kfree_skb_any(skb);
544 return status;
545
546 free_request:
> 547 usb_ep_free_request(ep, req);
548 free_skb:
> 549 dev_kfree_skb_any(skb2);
550 goto next;
551 }
552
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Markus,
kernel test robot noticed the following build errors:
[auto build test ERROR on usb/usb-testing]
[also build test ERROR on usb/usb-next usb/usb-linus westeri-thunderbolt/next linus/master v6.11 next-20240925]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Markus-Elfring/usb-gadget-eem-Use-common-error-handling-code-in-eem_unwrap/20240925-233931
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
patch link: https://lore.kernel.org/r/59fadd5a-6574-4379-98ac-cc4f11b675cc%40web.de
patch subject: [PATCH] usb: gadget: eem: Use common error handling code in eem_unwrap()
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20240926/202409261347.SAA10KGy-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240926/202409261347.SAA10KGy-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202409261347.SAA10KGy-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/usb/gadget/function/f_eem.c: In function 'eem_unwrap':
>> drivers/usb/gadget/function/f_eem.c:547:29: error: 'ep' undeclared (first use in this function); did you mean 'up'?
547 | usb_ep_free_request(ep, req);
| ^~
| up
drivers/usb/gadget/function/f_eem.c:547:29: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/usb/gadget/function/f_eem.c:547:33: error: 'req' undeclared (first use in this function); did you mean 'rq'?
547 | usb_ep_free_request(ep, req);
| ^~~
| rq
>> drivers/usb/gadget/function/f_eem.c:549:27: error: 'skb2' undeclared (first use in this function); did you mean 'skb'?
549 | dev_kfree_skb_any(skb2);
| ^~~~
| skb
vim +547 drivers/usb/gadget/function/f_eem.c
387
388 /*
389 * Remove the EEM header. Note that there can be many EEM packets in a single
390 * USB transfer, so we need to break them out and handle them independently.
391 */
392 static int eem_unwrap(struct gether *port,
393 struct sk_buff *skb,
394 struct sk_buff_head *list)
395 {
396 struct usb_composite_dev *cdev = port->func.config->cdev;
397 int status = 0;
398
399 do {
400 struct sk_buff *skb2;
401 u16 header;
402 u16 len = 0;
403
404 if (skb->len < EEM_HLEN) {
405 status = -EINVAL;
406 DBG(cdev, "invalid EEM header\n");
407 goto error;
408 }
409
410 /* remove the EEM header */
411 header = get_unaligned_le16(skb->data);
412 skb_pull(skb, EEM_HLEN);
413
414 /* EEM packet header format:
415 * b0..14: EEM type dependent (data or command)
416 * b15: bmType (0 == data, 1 == command)
417 */
418 if (header & BIT(15)) {
419 struct usb_request *req;
420 struct in_context *ctx;
421 struct usb_ep *ep;
422 u16 bmEEMCmd;
423
424 /* EEM command packet format:
425 * b0..10: bmEEMCmdParam
426 * b11..13: bmEEMCmd
427 * b14: reserved (must be zero)
428 * b15: bmType (1 == command)
429 */
430 if (header & BIT(14))
431 continue;
432
433 bmEEMCmd = (header >> 11) & 0x7;
434 switch (bmEEMCmd) {
435 case 0: /* echo */
436 len = header & 0x7FF;
437 if (skb->len < len) {
438 status = -EOVERFLOW;
439 goto error;
440 }
441
442 skb2 = skb_clone(skb, GFP_ATOMIC);
443 if (unlikely(!skb2)) {
444 DBG(cdev, "EEM echo response error\n");
445 goto next;
446 }
447 skb_trim(skb2, len);
448 put_unaligned_le16(BIT(15) | BIT(11) | len,
449 skb_push(skb2, 2));
450
451 ep = port->in_ep;
452 req = usb_ep_alloc_request(ep, GFP_ATOMIC);
453 if (!req)
454 goto free_skb;
455
456 req->buf = kmalloc(skb2->len, GFP_KERNEL);
457 if (!req->buf)
458 goto free_request;
459
460 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
461 if (!ctx) {
462 kfree(req->buf);
463 goto free_request;
464 }
465 ctx->skb = skb2;
466 ctx->ep = ep;
467
468 skb_copy_bits(skb2, 0, req->buf, skb2->len);
469 req->length = skb2->len;
470 req->complete = eem_cmd_complete;
471 req->zero = 1;
472 req->context = ctx;
473 if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
474 DBG(cdev, "echo response queue fail\n");
475 break;
476
477 case 1: /* echo response */
478 case 2: /* suspend hint */
479 case 3: /* response hint */
480 case 4: /* response complete hint */
481 case 5: /* tickle */
482 default: /* reserved */
483 continue;
484 }
485 } else {
486 u32 crc, crc2;
487 struct sk_buff *skb3;
488
489 /* check for zero-length EEM packet */
490 if (header == 0)
491 continue;
492
493 /* EEM data packet format:
494 * b0..13: length of ethernet frame
495 * b14: bmCRC (0 == sentinel, 1 == calculated)
496 * b15: bmType (0 == data)
497 */
498 len = header & 0x3FFF;
499 if ((skb->len < len)
500 || (len < (ETH_HLEN + ETH_FCS_LEN))) {
501 status = -EINVAL;
502 goto error;
503 }
504
505 /* validate CRC */
506 if (header & BIT(14)) {
507 crc = get_unaligned_le32(skb->data + len
508 - ETH_FCS_LEN);
509 crc2 = ~crc32_le(~0,
510 skb->data, len - ETH_FCS_LEN);
511 } else {
512 crc = get_unaligned_be32(skb->data + len
513 - ETH_FCS_LEN);
514 crc2 = 0xdeadbeef;
515 }
516 if (crc != crc2) {
517 DBG(cdev, "invalid EEM CRC\n");
518 goto next;
519 }
520
521 skb2 = skb_clone(skb, GFP_ATOMIC);
522 if (unlikely(!skb2)) {
523 DBG(cdev, "unable to unframe EEM packet\n");
524 goto next;
525 }
526 skb_trim(skb2, len - ETH_FCS_LEN);
527
528 skb3 = skb_copy_expand(skb2,
529 NET_IP_ALIGN,
530 0,
531 GFP_ATOMIC);
532 if (unlikely(!skb3))
533 goto free_skb;
534
535 dev_kfree_skb_any(skb2);
536 skb_queue_tail(list, skb3);
537 }
538 next:
539 skb_pull(skb, len);
540 } while (skb->len);
541
542 error:
543 dev_kfree_skb_any(skb);
544 return status;
545
546 free_request:
> 547 usb_ep_free_request(ep, req);
548 free_skb:
> 549 dev_kfree_skb_any(skb2);
550 goto next;
551 }
552
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on usb/usb-testing]
> [also build test ERROR on usb/usb-next usb/usb-linus westeri-thunderbolt/next linus/master v6.11 next-20240925]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Markus-Elfring/usb-gadget-eem-Use-common-error-handling-code-in-eem_unwrap/20240925-233931
> base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
> patch link: https://lore.kernel.org/r/59fadd5a-6574-4379-98ac-cc4f11b675cc%40web.de
> patch subject: [PATCH] usb: gadget: eem: Use common error handling code in eem_unwrap()
> config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20240926/202409261347.SAA10KGy-lkp@intel.com/config)
> compiler: alpha-linux-gcc (GCC) 13.3.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240926/202409261347.SAA10KGy-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202409261347.SAA10KGy-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> drivers/usb/gadget/function/f_eem.c: In function 'eem_unwrap':
>>> drivers/usb/gadget/function/f_eem.c:547:29: error: 'ep' undeclared (first use in this function); did you mean 'up'?
> 547 | usb_ep_free_request(ep, req);
> | ^~
> | up
> drivers/usb/gadget/function/f_eem.c:547:29: note: each undeclared identifier is reported only once for each function it appears in
>>> drivers/usb/gadget/function/f_eem.c:547:33: error: 'req' undeclared (first use in this function); did you mean 'rq'?
> 547 | usb_ep_free_request(ep, req);
> | ^~~
> | rq
>>> drivers/usb/gadget/function/f_eem.c:549:27: error: 'skb2' undeclared (first use in this function); did you mean 'skb'?
> 549 | dev_kfree_skb_any(skb2);
> | ^~~~
> | skb
Is there development support to adjust the scope for mentioned local variables?
> vim +547 drivers/usb/gadget/function/f_eem.c
>
> 387
> 388 /*
> 389 * Remove the EEM header. Note that there can be many EEM packets in a single
> 390 * USB transfer, so we need to break them out and handle them independently.
> 391 */
> 392 static int eem_unwrap(struct gether *port,
> 393 struct sk_buff *skb,
> 394 struct sk_buff_head *list)
> 395 {
> 396 struct usb_composite_dev *cdev = port->func.config->cdev;
> 397 int status = 0;
> 398
> 399 do {
> 400 struct sk_buff *skb2;
> 401 u16 header;
> 402 u16 len = 0;
> 403
> 404 if (skb->len < EEM_HLEN) {
> 405 status = -EINVAL;
> 406 DBG(cdev, "invalid EEM header\n");
> 407 goto error;
> 408 }
> 409
> 410 /* remove the EEM header */
> 411 header = get_unaligned_le16(skb->data);
> 412 skb_pull(skb, EEM_HLEN);
> 413
> 414 /* EEM packet header format:
> 415 * b0..14: EEM type dependent (data or command)
> 416 * b15: bmType (0 == data, 1 == command)
> 417 */
> 418 if (header & BIT(15)) {
> 419 struct usb_request *req;
> 420 struct in_context *ctx;
> 421 struct usb_ep *ep;
> 422 u16 bmEEMCmd;
> 423
> 424 /* EEM command packet format:
> 425 * b0..10: bmEEMCmdParam
> 426 * b11..13: bmEEMCmd
> 427 * b14: reserved (must be zero)
> 428 * b15: bmType (1 == command)
> 429 */
> 430 if (header & BIT(14))
> 431 continue;
> 432
> 433 bmEEMCmd = (header >> 11) & 0x7;
> 434 switch (bmEEMCmd) {
> 435 case 0: /* echo */
> 436 len = header & 0x7FF;
> 437 if (skb->len < len) {
> 438 status = -EOVERFLOW;
> 439 goto error;
> 440 }
> 441
> 442 skb2 = skb_clone(skb, GFP_ATOMIC);
> 443 if (unlikely(!skb2)) {
> 444 DBG(cdev, "EEM echo response error\n");
> 445 goto next;
> 446 }
> 447 skb_trim(skb2, len);
> 448 put_unaligned_le16(BIT(15) | BIT(11) | len,
> 449 skb_push(skb2, 2));
> 450
> 451 ep = port->in_ep;
> 452 req = usb_ep_alloc_request(ep, GFP_ATOMIC);
> 453 if (!req)
> 454 goto free_skb;
> 455
> 456 req->buf = kmalloc(skb2->len, GFP_KERNEL);
> 457 if (!req->buf)
> 458 goto free_request;
> 459
> 460 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
> 461 if (!ctx) {
> 462 kfree(req->buf);
> 463 goto free_request;
> 464 }
> 465 ctx->skb = skb2;
> 466 ctx->ep = ep;
> 467
> 468 skb_copy_bits(skb2, 0, req->buf, skb2->len);
> 469 req->length = skb2->len;
> 470 req->complete = eem_cmd_complete;
> 471 req->zero = 1;
> 472 req->context = ctx;
> 473 if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
> 474 DBG(cdev, "echo response queue fail\n");
> 475 break;
> 476
> 477 case 1: /* echo response */
> 478 case 2: /* suspend hint */
> 479 case 3: /* response hint */
> 480 case 4: /* response complete hint */
> 481 case 5: /* tickle */
> 482 default: /* reserved */
> 483 continue;
> 484 }
> 485 } else {
> 486 u32 crc, crc2;
> 487 struct sk_buff *skb3;
> 488
> 489 /* check for zero-length EEM packet */
> 490 if (header == 0)
> 491 continue;
> 492
> 493 /* EEM data packet format:
> 494 * b0..13: length of ethernet frame
> 495 * b14: bmCRC (0 == sentinel, 1 == calculated)
> 496 * b15: bmType (0 == data)
> 497 */
> 498 len = header & 0x3FFF;
> 499 if ((skb->len < len)
> 500 || (len < (ETH_HLEN + ETH_FCS_LEN))) {
> 501 status = -EINVAL;
> 502 goto error;
> 503 }
> 504
> 505 /* validate CRC */
> 506 if (header & BIT(14)) {
> 507 crc = get_unaligned_le32(skb->data + len
> 508 - ETH_FCS_LEN);
> 509 crc2 = ~crc32_le(~0,
> 510 skb->data, len - ETH_FCS_LEN);
> 511 } else {
> 512 crc = get_unaligned_be32(skb->data + len
> 513 - ETH_FCS_LEN);
> 514 crc2 = 0xdeadbeef;
> 515 }
> 516 if (crc != crc2) {
> 517 DBG(cdev, "invalid EEM CRC\n");
> 518 goto next;
> 519 }
> 520
> 521 skb2 = skb_clone(skb, GFP_ATOMIC);
> 522 if (unlikely(!skb2)) {
> 523 DBG(cdev, "unable to unframe EEM packet\n");
> 524 goto next;
> 525 }
> 526 skb_trim(skb2, len - ETH_FCS_LEN);
> 527
> 528 skb3 = skb_copy_expand(skb2,
> 529 NET_IP_ALIGN,
> 530 0,
> 531 GFP_ATOMIC);
> 532 if (unlikely(!skb3))
> 533 goto free_skb;
> 534
> 535 dev_kfree_skb_any(skb2);
> 536 skb_queue_tail(list, skb3);
> 537 }
> 538 next:
> 539 skb_pull(skb, len);
> 540 } while (skb->len);
> 541
> 542 error:
> 543 dev_kfree_skb_any(skb);
> 544 return status;
> 545
> 546 free_request:
> > 547 usb_ep_free_request(ep, req);
> 548 free_skb:
> > 549 dev_kfree_skb_any(skb2);
> 550 goto next;
> 551 }
> 552
Would any other software design options become acceptable for the reduction of duplicate statements
(according to resource management)?
Regards,
Markus
© 2016 - 2026 Red Hat, Inc.