0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include "nhc.h"
0014
0015 #define LOWPAN_NHC_UDP_MASK 0xF8
0016 #define LOWPAN_NHC_UDP_ID 0xF0
0017
0018 #define LOWPAN_NHC_UDP_4BIT_PORT 0xF0B0
0019 #define LOWPAN_NHC_UDP_4BIT_MASK 0xFFF0
0020 #define LOWPAN_NHC_UDP_8BIT_PORT 0xF000
0021 #define LOWPAN_NHC_UDP_8BIT_MASK 0xFF00
0022
0023
0024
0025
0026 #define LOWPAN_NHC_UDP_CS_P_00 0xF0
0027
0028 #define LOWPAN_NHC_UDP_CS_P_01 0xF1
0029
0030 #define LOWPAN_NHC_UDP_CS_P_10 0xF2
0031
0032 #define LOWPAN_NHC_UDP_CS_P_11 0xF3
0033
0034 #define LOWPAN_NHC_UDP_CS_C 0x04
0035
0036 static int udp_uncompress(struct sk_buff *skb, size_t needed)
0037 {
0038 u8 tmp = 0, val = 0;
0039 struct udphdr uh;
0040 bool fail;
0041 int err;
0042
0043 fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
0044
0045 pr_debug("UDP header uncompression\n");
0046 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
0047 case LOWPAN_NHC_UDP_CS_P_00:
0048 fail |= lowpan_fetch_skb(skb, &uh.source, sizeof(uh.source));
0049 fail |= lowpan_fetch_skb(skb, &uh.dest, sizeof(uh.dest));
0050 break;
0051 case LOWPAN_NHC_UDP_CS_P_01:
0052 fail |= lowpan_fetch_skb(skb, &uh.source, sizeof(uh.source));
0053 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
0054 uh.dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
0055 break;
0056 case LOWPAN_NHC_UDP_CS_P_10:
0057 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
0058 uh.source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
0059 fail |= lowpan_fetch_skb(skb, &uh.dest, sizeof(uh.dest));
0060 break;
0061 case LOWPAN_NHC_UDP_CS_P_11:
0062 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
0063 uh.source = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val >> 4));
0064 uh.dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val & 0x0f));
0065 break;
0066 default:
0067 BUG();
0068 }
0069
0070 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
0071 ntohs(uh.source), ntohs(uh.dest));
0072
0073
0074 if (tmp & LOWPAN_NHC_UDP_CS_C) {
0075 pr_debug_ratelimited("checksum elided currently not supported\n");
0076 fail = true;
0077 } else {
0078 fail |= lowpan_fetch_skb(skb, &uh.check, sizeof(uh.check));
0079 }
0080
0081 if (fail)
0082 return -EINVAL;
0083
0084
0085
0086
0087
0088 switch (lowpan_dev(skb->dev)->lltype) {
0089 case LOWPAN_LLTYPE_IEEE802154:
0090 if (lowpan_802154_cb(skb)->d_size)
0091 uh.len = htons(lowpan_802154_cb(skb)->d_size -
0092 sizeof(struct ipv6hdr));
0093 else
0094 uh.len = htons(skb->len + sizeof(struct udphdr));
0095 break;
0096 default:
0097 uh.len = htons(skb->len + sizeof(struct udphdr));
0098 break;
0099 }
0100 pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len));
0101
0102
0103
0104
0105 err = skb_cow(skb, needed);
0106 if (unlikely(err))
0107 return err;
0108
0109 skb_push(skb, sizeof(struct udphdr));
0110 skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
0111
0112 return 0;
0113 }
0114
0115 static int udp_compress(struct sk_buff *skb, u8 **hc_ptr)
0116 {
0117 const struct udphdr *uh = udp_hdr(skb);
0118 u8 tmp;
0119
0120 if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
0121 LOWPAN_NHC_UDP_4BIT_PORT) &&
0122 ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
0123 LOWPAN_NHC_UDP_4BIT_PORT)) {
0124 pr_debug("UDP header: both ports compression to 4 bits\n");
0125
0126 tmp = LOWPAN_NHC_UDP_CS_P_11;
0127 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0128
0129 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
0130 ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
0131 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0132 } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
0133 LOWPAN_NHC_UDP_8BIT_PORT) {
0134 pr_debug("UDP header: remove 8 bits of dest\n");
0135
0136 tmp = LOWPAN_NHC_UDP_CS_P_01;
0137 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0138
0139 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
0140
0141 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
0142 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0143 } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
0144 LOWPAN_NHC_UDP_8BIT_PORT) {
0145 pr_debug("UDP header: remove 8 bits of source\n");
0146
0147 tmp = LOWPAN_NHC_UDP_CS_P_10;
0148 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0149
0150 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
0151 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0152
0153 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
0154 } else {
0155 pr_debug("UDP header: can't compress\n");
0156
0157 tmp = LOWPAN_NHC_UDP_CS_P_00;
0158 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
0159
0160 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
0161
0162 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
0163 }
0164
0165
0166 lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
0167
0168 return 0;
0169 }
0170
0171 LOWPAN_NHC(nhc_udp, "RFC6282 UDP", NEXTHDR_UDP, sizeof(struct udphdr),
0172 LOWPAN_NHC_UDP_ID, LOWPAN_NHC_UDP_MASK, udp_uncompress, udp_compress);
0173
0174 module_lowpan_nhc(nhc_udp);
0175 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 UDP compression");
0176 MODULE_LICENSE("GPL");