fc_frame.c 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright(c) 2007 Intel Corporation. All rights reserved.
  4. *
  5. * Maintained at www.Open-FCoE.org
  6. */
  7. /*
  8. * Frame allocation.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/skbuff.h>
  13. #include <linux/crc32.h>
  14. #include <linux/gfp.h>
  15. #include <scsi/fc_frame.h>
  16. /*
  17. * Check the CRC in a frame.
  18. */
  19. u32 fc_frame_crc_check(struct fc_frame *fp)
  20. {
  21. u32 crc;
  22. u32 error;
  23. const u8 *bp;
  24. unsigned int len;
  25. WARN_ON(!fc_frame_is_linear(fp));
  26. fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
  27. len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */
  28. bp = (const u8 *) fr_hdr(fp);
  29. crc = ~crc32(~0, bp, len);
  30. error = crc ^ fr_crc(fp);
  31. return error;
  32. }
  33. EXPORT_SYMBOL(fc_frame_crc_check);
  34. /*
  35. * Allocate a frame intended to be sent.
  36. * Get an sk_buff for the frame and set the length.
  37. */
  38. struct fc_frame *_fc_frame_alloc(size_t len)
  39. {
  40. struct fc_frame *fp;
  41. struct sk_buff *skb;
  42. WARN_ON((len % sizeof(u32)) != 0);
  43. len += sizeof(struct fc_frame_header);
  44. skb = alloc_skb_fclone(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM +
  45. NET_SKB_PAD, GFP_ATOMIC);
  46. if (!skb)
  47. return NULL;
  48. skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM);
  49. fp = (struct fc_frame *) skb;
  50. fc_frame_init(fp);
  51. skb_put(skb, len);
  52. return fp;
  53. }
  54. EXPORT_SYMBOL(_fc_frame_alloc);
  55. struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len)
  56. {
  57. struct fc_frame *fp;
  58. size_t fill;
  59. fill = payload_len % 4;
  60. if (fill != 0)
  61. fill = 4 - fill;
  62. fp = _fc_frame_alloc(payload_len + fill);
  63. if (fp) {
  64. memset((char *) fr_hdr(fp) + payload_len, 0, fill);
  65. /* trim is OK, we just allocated it so there are no fragments */
  66. skb_trim(fp_skb(fp),
  67. payload_len + sizeof(struct fc_frame_header));
  68. }
  69. return fp;
  70. }
  71. EXPORT_SYMBOL(fc_frame_alloc_fill);