2 * 6LoWPAN IPv6 UDP compression according to RFC6282
6 * Alexander Aring <aar@pengutronix.de>
9 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
10 * Jon Smirl <jonsmirl@gmail.com>
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.
20 #define LOWPAN_NHC_UDP_MASK 0xF8
21 #define LOWPAN_NHC_UDP_ID 0xF0
22 #define LOWPAN_NHC_UDP_IDLEN 1
24 #define LOWPAN_NHC_UDP_4BIT_PORT 0xF0B0
25 #define LOWPAN_NHC_UDP_4BIT_MASK 0xFFF0
26 #define LOWPAN_NHC_UDP_8BIT_PORT 0xF000
27 #define LOWPAN_NHC_UDP_8BIT_MASK 0xFF00
29 /* values for port compression, _with checksum_ ie bit 5 set to 0 */
32 #define LOWPAN_NHC_UDP_CS_P_00 0xF0
33 /* source 16bit inline, dest = 0xF0 + 8 bit inline */
34 #define LOWPAN_NHC_UDP_CS_P_01 0xF1
35 /* source = 0xF0 + 8bit inline, dest = 16 bit inline */
36 #define LOWPAN_NHC_UDP_CS_P_10 0xF2
37 /* source & dest = 0xF0B + 4bit inline */
38 #define LOWPAN_NHC_UDP_CS_P_11 0xF3
40 #define LOWPAN_NHC_UDP_CS_C 0x04
42 static int udp_uncompress(struct sk_buff
*skb
, size_t needed
)
49 fail
= lowpan_fetch_skb(skb
, &tmp
, sizeof(tmp
));
51 pr_debug("UDP header uncompression\n");
52 switch (tmp
& LOWPAN_NHC_UDP_CS_P_11
) {
53 case LOWPAN_NHC_UDP_CS_P_00
:
54 fail
|= lowpan_fetch_skb(skb
, &uh
.source
, sizeof(uh
.source
));
55 fail
|= lowpan_fetch_skb(skb
, &uh
.dest
, sizeof(uh
.dest
));
57 case LOWPAN_NHC_UDP_CS_P_01
:
58 fail
|= lowpan_fetch_skb(skb
, &uh
.source
, sizeof(uh
.source
));
59 fail
|= lowpan_fetch_skb(skb
, &val
, sizeof(val
));
60 uh
.dest
= htons(val
+ LOWPAN_NHC_UDP_8BIT_PORT
);
62 case LOWPAN_NHC_UDP_CS_P_10
:
63 fail
|= lowpan_fetch_skb(skb
, &val
, sizeof(val
));
64 uh
.source
= htons(val
+ LOWPAN_NHC_UDP_8BIT_PORT
);
65 fail
|= lowpan_fetch_skb(skb
, &uh
.dest
, sizeof(uh
.dest
));
67 case LOWPAN_NHC_UDP_CS_P_11
:
68 fail
|= lowpan_fetch_skb(skb
, &val
, sizeof(val
));
69 uh
.source
= htons(LOWPAN_NHC_UDP_4BIT_PORT
+ (val
>> 4));
70 uh
.dest
= htons(LOWPAN_NHC_UDP_4BIT_PORT
+ (val
& 0x0f));
76 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
77 ntohs(uh
.source
), ntohs(uh
.dest
));
80 if (tmp
& LOWPAN_NHC_UDP_CS_C
) {
81 pr_debug_ratelimited("checksum elided currently not supported\n");
84 fail
|= lowpan_fetch_skb(skb
, &uh
.check
, sizeof(uh
.check
));
90 /* UDP length needs to be infered from the lower layers
91 * here, we obtain the hint from the remaining size of the
94 switch (lowpan_priv(skb
->dev
)->lltype
) {
95 case LOWPAN_LLTYPE_IEEE802154
:
96 if (lowpan_802154_cb(skb
)->d_size
)
97 uh
.len
= htons(lowpan_802154_cb(skb
)->d_size
-
98 sizeof(struct ipv6hdr
));
100 uh
.len
= htons(skb
->len
+ sizeof(struct udphdr
));
103 uh
.len
= htons(skb
->len
+ sizeof(struct udphdr
));
106 pr_debug("uncompressed UDP length: src = %d", ntohs(uh
.len
));
108 /* replace the compressed UDP head by the uncompressed UDP
111 err
= skb_cow(skb
, needed
);
115 skb_push(skb
, sizeof(struct udphdr
));
116 skb_copy_to_linear_data(skb
, &uh
, sizeof(struct udphdr
));
121 static int udp_compress(struct sk_buff
*skb
, u8
**hc_ptr
)
123 const struct udphdr
*uh
= udp_hdr(skb
);
126 if (((ntohs(uh
->source
) & LOWPAN_NHC_UDP_4BIT_MASK
) ==
127 LOWPAN_NHC_UDP_4BIT_PORT
) &&
128 ((ntohs(uh
->dest
) & LOWPAN_NHC_UDP_4BIT_MASK
) ==
129 LOWPAN_NHC_UDP_4BIT_PORT
)) {
130 pr_debug("UDP header: both ports compression to 4 bits\n");
131 /* compression value */
132 tmp
= LOWPAN_NHC_UDP_CS_P_11
;
133 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
134 /* source and destination port */
135 tmp
= ntohs(uh
->dest
) - LOWPAN_NHC_UDP_4BIT_PORT
+
136 ((ntohs(uh
->source
) - LOWPAN_NHC_UDP_4BIT_PORT
) << 4);
137 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
138 } else if ((ntohs(uh
->dest
) & LOWPAN_NHC_UDP_8BIT_MASK
) ==
139 LOWPAN_NHC_UDP_8BIT_PORT
) {
140 pr_debug("UDP header: remove 8 bits of dest\n");
141 /* compression value */
142 tmp
= LOWPAN_NHC_UDP_CS_P_01
;
143 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
145 lowpan_push_hc_data(hc_ptr
, &uh
->source
, sizeof(uh
->source
));
146 /* destination port */
147 tmp
= ntohs(uh
->dest
) - LOWPAN_NHC_UDP_8BIT_PORT
;
148 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
149 } else if ((ntohs(uh
->source
) & LOWPAN_NHC_UDP_8BIT_MASK
) ==
150 LOWPAN_NHC_UDP_8BIT_PORT
) {
151 pr_debug("UDP header: remove 8 bits of source\n");
152 /* compression value */
153 tmp
= LOWPAN_NHC_UDP_CS_P_10
;
154 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
156 tmp
= ntohs(uh
->source
) - LOWPAN_NHC_UDP_8BIT_PORT
;
157 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
158 /* destination port */
159 lowpan_push_hc_data(hc_ptr
, &uh
->dest
, sizeof(uh
->dest
));
161 pr_debug("UDP header: can't compress\n");
162 /* compression value */
163 tmp
= LOWPAN_NHC_UDP_CS_P_00
;
164 lowpan_push_hc_data(hc_ptr
, &tmp
, sizeof(tmp
));
166 lowpan_push_hc_data(hc_ptr
, &uh
->source
, sizeof(uh
->source
));
167 /* destination port */
168 lowpan_push_hc_data(hc_ptr
, &uh
->dest
, sizeof(uh
->dest
));
171 /* checksum is always inline */
172 lowpan_push_hc_data(hc_ptr
, &uh
->check
, sizeof(uh
->check
));
177 static void udp_nhid_setup(struct lowpan_nhc
*nhc
)
179 nhc
->id
[0] = LOWPAN_NHC_UDP_ID
;
180 nhc
->idmask
[0] = LOWPAN_NHC_UDP_MASK
;
183 LOWPAN_NHC(nhc_udp
, "RFC6282 UDP", NEXTHDR_UDP
, sizeof(struct udphdr
),
184 udp_nhid_setup
, LOWPAN_NHC_UDP_IDLEN
, udp_uncompress
, udp_compress
);
186 module_lowpan_nhc(nhc_udp
);
187 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 UDP compression");
188 MODULE_LICENSE("GPL");