nhc_udp.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /*
  2. * 6LoWPAN IPv6 UDP compression according to RFC6282
  3. *
  4. *
  5. * Authors:
  6. * Alexander Aring <aar@pengutronix.de>
  7. *
  8. * Orignal written by:
  9. * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  10. * Jon Smirl <jonsmirl@gmail.com>
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; either version
  15. * 2 of the License, or (at your option) any later version.
  16. */
  17. #include "nhc.h"
  18. #define LOWPAN_NHC_UDP_IDLEN 1
  19. static int udp_uncompress(struct sk_buff *skb, size_t needed)
  20. {
  21. u8 tmp = 0, val = 0;
  22. struct udphdr uh;
  23. bool fail;
  24. int err;
  25. fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
  26. pr_debug("UDP header uncompression\n");
  27. switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
  28. case LOWPAN_NHC_UDP_CS_P_00:
  29. fail |= lowpan_fetch_skb(skb, &uh.source, sizeof(uh.source));
  30. fail |= lowpan_fetch_skb(skb, &uh.dest, sizeof(uh.dest));
  31. break;
  32. case LOWPAN_NHC_UDP_CS_P_01:
  33. fail |= lowpan_fetch_skb(skb, &uh.source, sizeof(uh.source));
  34. fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
  35. uh.dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
  36. break;
  37. case LOWPAN_NHC_UDP_CS_P_10:
  38. fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
  39. uh.source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
  40. fail |= lowpan_fetch_skb(skb, &uh.dest, sizeof(uh.dest));
  41. break;
  42. case LOWPAN_NHC_UDP_CS_P_11:
  43. fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
  44. uh.source = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val >> 4));
  45. uh.dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val & 0x0f));
  46. break;
  47. default:
  48. BUG();
  49. }
  50. pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
  51. ntohs(uh.source), ntohs(uh.dest));
  52. /* checksum */
  53. if (tmp & LOWPAN_NHC_UDP_CS_C) {
  54. pr_debug_ratelimited("checksum elided currently not supported\n");
  55. fail = true;
  56. } else {
  57. fail |= lowpan_fetch_skb(skb, &uh.check, sizeof(uh.check));
  58. }
  59. if (fail)
  60. return -EINVAL;
  61. /* UDP length needs to be infered from the lower layers
  62. * here, we obtain the hint from the remaining size of the
  63. * frame
  64. */
  65. uh.len = htons(skb->len + sizeof(struct udphdr));
  66. pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len));
  67. /* replace the compressed UDP head by the uncompressed UDP
  68. * header
  69. */
  70. err = skb_cow(skb, needed);
  71. if (unlikely(err))
  72. return err;
  73. skb_push(skb, sizeof(struct udphdr));
  74. skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
  75. return 0;
  76. }
  77. static int udp_compress(struct sk_buff *skb, u8 **hc_ptr)
  78. {
  79. const struct udphdr *uh = udp_hdr(skb);
  80. u8 tmp;
  81. if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
  82. LOWPAN_NHC_UDP_4BIT_PORT) &&
  83. ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
  84. LOWPAN_NHC_UDP_4BIT_PORT)) {
  85. pr_debug("UDP header: both ports compression to 4 bits\n");
  86. /* compression value */
  87. tmp = LOWPAN_NHC_UDP_CS_P_11;
  88. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  89. /* source and destination port */
  90. tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
  91. ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
  92. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  93. } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
  94. LOWPAN_NHC_UDP_8BIT_PORT) {
  95. pr_debug("UDP header: remove 8 bits of dest\n");
  96. /* compression value */
  97. tmp = LOWPAN_NHC_UDP_CS_P_01;
  98. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  99. /* source port */
  100. lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
  101. /* destination port */
  102. tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
  103. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  104. } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
  105. LOWPAN_NHC_UDP_8BIT_PORT) {
  106. pr_debug("UDP header: remove 8 bits of source\n");
  107. /* compression value */
  108. tmp = LOWPAN_NHC_UDP_CS_P_10;
  109. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  110. /* source port */
  111. tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
  112. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  113. /* destination port */
  114. lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
  115. } else {
  116. pr_debug("UDP header: can't compress\n");
  117. /* compression value */
  118. tmp = LOWPAN_NHC_UDP_CS_P_00;
  119. lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
  120. /* source port */
  121. lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
  122. /* destination port */
  123. lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
  124. }
  125. /* checksum is always inline */
  126. lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
  127. return 0;
  128. }
  129. static void udp_nhid_setup(struct lowpan_nhc *nhc)
  130. {
  131. nhc->id[0] = LOWPAN_NHC_UDP_ID;
  132. nhc->idmask[0] = LOWPAN_NHC_UDP_MASK;
  133. }
  134. LOWPAN_NHC(nhc_udp, "RFC6282 UDP", NEXTHDR_UDP, sizeof(struct udphdr),
  135. udp_nhid_setup, LOWPAN_NHC_UDP_IDLEN, udp_uncompress, udp_compress);
  136. module_lowpan_nhc(nhc_udp);
  137. MODULE_DESCRIPTION("6LoWPAN next header RFC6282 UDP compression");
  138. MODULE_LICENSE("GPL");