cffrml.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * CAIF Framing Layer.
  3. *
  4. * Copyright (C) ST-Ericsson AB 2010
  5. * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
  6. * License terms: GNU General Public License (GPL) version 2
  7. */
  8. #include <linux/stddef.h>
  9. #include <linux/spinlock.h>
  10. #include <linux/slab.h>
  11. #include <linux/crc-ccitt.h>
  12. #include <net/caif/caif_layer.h>
  13. #include <net/caif/cfpkt.h>
  14. #include <net/caif/cffrml.h>
  15. #define container_obj(layr) container_of(layr, struct cffrml, layer)
  16. struct cffrml {
  17. struct cflayer layer;
  18. bool dofcs; /* !< FCS active */
  19. };
  20. static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt);
  21. static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt);
  22. static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  23. int phyid);
  24. static u32 cffrml_rcv_error;
  25. static u32 cffrml_rcv_checsum_error;
  26. struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
  27. {
  28. struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
  29. if (!this) {
  30. pr_warning("CAIF: %s(): Out of memory\n", __func__);
  31. return NULL;
  32. }
  33. caif_assert(offsetof(struct cffrml, layer) == 0);
  34. memset(this, 0, sizeof(struct cflayer));
  35. this->layer.receive = cffrml_receive;
  36. this->layer.transmit = cffrml_transmit;
  37. this->layer.ctrlcmd = cffrml_ctrlcmd;
  38. snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid);
  39. this->dofcs = use_fcs;
  40. this->layer.id = phyid;
  41. return (struct cflayer *) this;
  42. }
  43. void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up)
  44. {
  45. this->up = up;
  46. }
  47. void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn)
  48. {
  49. this->dn = dn;
  50. }
  51. static u16 cffrml_checksum(u16 chks, void *buf, u16 len)
  52. {
  53. /* FIXME: FCS should be moved to glue in order to use OS-Specific
  54. * solutions
  55. */
  56. return crc_ccitt(chks, buf, len);
  57. }
  58. static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
  59. {
  60. u16 tmp;
  61. u16 len;
  62. u16 hdrchks;
  63. u16 pktchks;
  64. struct cffrml *this;
  65. this = container_obj(layr);
  66. cfpkt_extr_head(pkt, &tmp, 2);
  67. len = le16_to_cpu(tmp);
  68. /* Subtract for FCS on length if FCS is not used. */
  69. if (!this->dofcs)
  70. len -= 2;
  71. if (cfpkt_setlen(pkt, len) < 0) {
  72. ++cffrml_rcv_error;
  73. pr_err("CAIF: %s():Framing length error (%d)\n", __func__, len);
  74. cfpkt_destroy(pkt);
  75. return -EPROTO;
  76. }
  77. /*
  78. * Don't do extract if FCS is false, rather do setlen - then we don't
  79. * get a cache-miss.
  80. */
  81. if (this->dofcs) {
  82. cfpkt_extr_trail(pkt, &tmp, 2);
  83. hdrchks = le16_to_cpu(tmp);
  84. pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
  85. if (pktchks != hdrchks) {
  86. cfpkt_add_trail(pkt, &tmp, 2);
  87. ++cffrml_rcv_error;
  88. ++cffrml_rcv_checsum_error;
  89. pr_info("CAIF: %s(): Frame checksum error "
  90. "(0x%x != 0x%x)\n", __func__, hdrchks, pktchks);
  91. return -EILSEQ;
  92. }
  93. }
  94. if (cfpkt_erroneous(pkt)) {
  95. ++cffrml_rcv_error;
  96. pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
  97. cfpkt_destroy(pkt);
  98. return -EPROTO;
  99. }
  100. return layr->up->receive(layr->up, pkt);
  101. }
  102. static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
  103. {
  104. int tmp;
  105. u16 chks;
  106. u16 len;
  107. int ret;
  108. struct cffrml *this = container_obj(layr);
  109. if (this->dofcs) {
  110. chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
  111. tmp = cpu_to_le16(chks);
  112. cfpkt_add_trail(pkt, &tmp, 2);
  113. } else {
  114. cfpkt_pad_trail(pkt, 2);
  115. }
  116. len = cfpkt_getlen(pkt);
  117. tmp = cpu_to_le16(len);
  118. cfpkt_add_head(pkt, &tmp, 2);
  119. cfpkt_info(pkt)->hdr_len += 2;
  120. if (cfpkt_erroneous(pkt)) {
  121. pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
  122. return -EPROTO;
  123. }
  124. ret = layr->dn->transmit(layr->dn, pkt);
  125. if (ret < 0) {
  126. /* Remove header on faulty packet. */
  127. cfpkt_extr_head(pkt, &tmp, 2);
  128. }
  129. return ret;
  130. }
  131. static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
  132. int phyid)
  133. {
  134. if (layr->up->ctrlcmd)
  135. layr->up->ctrlcmd(layr->up, ctrl, layr->id);
  136. }