coresight: fix comment in of_coresight.c
[linux-2.6-block.git] / net / 6lowpan / iphc.c
CommitLineData
8df8c56a
JR
1/*
2 * Copyright 2011, Siemens AG
3 * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
4 */
5
4710d806 6/* Based on patches from Jon Smirl <jonsmirl@gmail.com>
8df8c56a
JR
7 * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
8df8c56a
JR
18 */
19
20/* Jon's code is based on 6lowpan implementation for Contiki which is:
21 * Copyright (c) 2008, Swedish Institute of Computer Science.
22 * All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. Neither the name of the Institute nor the names of its contributors
33 * may be used to endorse or promote products derived from this software
34 * without specific prior written permission.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 */
48
49#include <linux/bitops.h>
50#include <linux/if_arp.h>
5ae5e991 51#include <linux/module.h>
8df8c56a 52#include <linux/netdevice.h>
cefc8c8a 53#include <net/6lowpan.h>
8df8c56a
JR
54#include <net/ipv6.h>
55#include <net/af_ieee802154.h>
56
4710d806 57/* Uncompress address function for source and
8df8c56a
JR
58 * destination address(non-multicast).
59 *
60 * address_mode is sam value or dam value.
61 */
62static int uncompress_addr(struct sk_buff *skb,
4710d806
VB
63 struct in6_addr *ipaddr, const u8 address_mode,
64 const u8 *lladdr, const u8 addr_type,
65 const u8 addr_len)
8df8c56a
JR
66{
67 bool fail;
68
69 switch (address_mode) {
70 case LOWPAN_IPHC_ADDR_00:
71 /* for global link addresses */
72 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
73 break;
74 case LOWPAN_IPHC_ADDR_01:
75 /* fe:80::XXXX:XXXX:XXXX:XXXX */
76 ipaddr->s6_addr[0] = 0xFE;
77 ipaddr->s6_addr[1] = 0x80;
78 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
79 break;
80 case LOWPAN_IPHC_ADDR_02:
81 /* fe:80::ff:fe00:XXXX */
82 ipaddr->s6_addr[0] = 0xFE;
83 ipaddr->s6_addr[1] = 0x80;
84 ipaddr->s6_addr[11] = 0xFF;
85 ipaddr->s6_addr[12] = 0xFE;
86 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
87 break;
88 case LOWPAN_IPHC_ADDR_03:
89 fail = false;
90 switch (addr_type) {
91 case IEEE802154_ADDR_LONG:
92 /* fe:80::XXXX:XXXX:XXXX:XXXX
93 * \_________________/
94 * hwaddr
95 */
96 ipaddr->s6_addr[0] = 0xFE;
97 ipaddr->s6_addr[1] = 0x80;
98 memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
99 /* second bit-flip (Universe/Local)
100 * is done according RFC2464
101 */
102 ipaddr->s6_addr[8] ^= 0x02;
103 break;
104 case IEEE802154_ADDR_SHORT:
105 /* fe:80::ff:fe00:XXXX
106 * \__/
107 * short_addr
108 *
109 * Universe/Local bit is zero.
110 */
111 ipaddr->s6_addr[0] = 0xFE;
112 ipaddr->s6_addr[1] = 0x80;
113 ipaddr->s6_addr[11] = 0xFF;
114 ipaddr->s6_addr[12] = 0xFE;
115 ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
116 break;
117 default:
118 pr_debug("Invalid addr_type set\n");
119 return -EINVAL;
120 }
121 break;
122 default:
123 pr_debug("Invalid address mode value: 0x%x\n", address_mode);
124 return -EINVAL;
125 }
126
127 if (fail) {
128 pr_debug("Failed to fetch skb data\n");
129 return -EIO;
130 }
131
132 raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
133 ipaddr->s6_addr, 16);
134
135 return 0;
136}
137
4710d806 138/* Uncompress address function for source context
8df8c56a
JR
139 * based address(non-multicast).
140 */
141static int uncompress_context_based_src_addr(struct sk_buff *skb,
4710d806
VB
142 struct in6_addr *ipaddr,
143 const u8 sam)
8df8c56a
JR
144{
145 switch (sam) {
146 case LOWPAN_IPHC_ADDR_00:
147 /* unspec address ::
148 * Do nothing, address is already ::
149 */
150 break;
151 case LOWPAN_IPHC_ADDR_01:
152 /* TODO */
153 case LOWPAN_IPHC_ADDR_02:
154 /* TODO */
155 case LOWPAN_IPHC_ADDR_03:
156 /* TODO */
157 netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
158 return -EINVAL;
159 default:
160 pr_debug("Invalid sam value: 0x%x\n", sam);
161 return -EINVAL;
162 }
163
164 raw_dump_inline(NULL,
165 "Reconstructed context based ipv6 src addr is",
166 ipaddr->s6_addr, 16);
167
168 return 0;
169}
170
8df8c56a
JR
171/* Uncompress function for multicast destination address,
172 * when M bit is set.
173 */
7fc4cfda
MH
174static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
175 struct in6_addr *ipaddr,
176 const u8 dam)
8df8c56a
JR
177{
178 bool fail;
179
180 switch (dam) {
181 case LOWPAN_IPHC_DAM_00:
182 /* 00: 128 bits. The full address
183 * is carried in-line.
184 */
185 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
186 break;
187 case LOWPAN_IPHC_DAM_01:
188 /* 01: 48 bits. The address takes
189 * the form ffXX::00XX:XXXX:XXXX.
190 */
191 ipaddr->s6_addr[0] = 0xFF;
192 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
193 fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
194 break;
195 case LOWPAN_IPHC_DAM_10:
196 /* 10: 32 bits. The address takes
197 * the form ffXX::00XX:XXXX.
198 */
199 ipaddr->s6_addr[0] = 0xFF;
200 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
201 fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
202 break;
203 case LOWPAN_IPHC_DAM_11:
204 /* 11: 8 bits. The address takes
205 * the form ff02::00XX.
206 */
207 ipaddr->s6_addr[0] = 0xFF;
208 ipaddr->s6_addr[1] = 0x02;
209 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
210 break;
211 default:
212 pr_debug("DAM value has a wrong value: 0x%x\n", dam);
213 return -EINVAL;
214 }
215
216 if (fail) {
217 pr_debug("Failed to fetch skb data\n");
218 return -EIO;
219 }
220
221 raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
7fc4cfda 222 ipaddr->s6_addr, 16);
8df8c56a
JR
223
224 return 0;
225}
226
7fc4cfda 227static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
8df8c56a 228{
1672a36b
AA
229 bool fail;
230 u8 tmp = 0, val = 0;
8df8c56a 231
8ec1d9be 232 fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
8df8c56a
JR
233
234 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
235 pr_debug("UDP header uncompression\n");
236 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
237 case LOWPAN_NHC_UDP_CS_P_00:
8ec1d9be
AA
238 fail |= lowpan_fetch_skb(skb, &uh->source,
239 sizeof(uh->source));
240 fail |= lowpan_fetch_skb(skb, &uh->dest,
241 sizeof(uh->dest));
8df8c56a
JR
242 break;
243 case LOWPAN_NHC_UDP_CS_P_01:
8ec1d9be
AA
244 fail |= lowpan_fetch_skb(skb, &uh->source,
245 sizeof(uh->source));
246 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
1672a36b 247 uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
8df8c56a
JR
248 break;
249 case LOWPAN_NHC_UDP_CS_P_10:
8ec1d9be 250 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
1672a36b 251 uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
8ec1d9be
AA
252 fail |= lowpan_fetch_skb(skb, &uh->dest,
253 sizeof(uh->dest));
8df8c56a
JR
254 break;
255 case LOWPAN_NHC_UDP_CS_P_11:
8ec1d9be 256 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
e5d966ef 257 uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
1672a36b 258 (val >> 4));
e5d966ef 259 uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
1672a36b 260 (val & 0x0f));
8df8c56a
JR
261 break;
262 default:
263 pr_debug("ERROR: unknown UDP format\n");
264 goto err;
8df8c56a
JR
265 }
266
267 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
e5d966ef 268 ntohs(uh->source), ntohs(uh->dest));
8df8c56a 269
573701ce
AA
270 /* checksum */
271 if (tmp & LOWPAN_NHC_UDP_CS_C) {
272 pr_debug_ratelimited("checksum elided currently not supported\n");
273 goto err;
274 } else {
8ec1d9be
AA
275 fail |= lowpan_fetch_skb(skb, &uh->check,
276 sizeof(uh->check));
573701ce 277 }
8df8c56a 278
89f53490 279 /* UDP length needs to be infered from the lower layers
8df8c56a
JR
280 * here, we obtain the hint from the remaining size of the
281 * frame
282 */
283 uh->len = htons(skb->len + sizeof(struct udphdr));
e5d966ef 284 pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
8df8c56a
JR
285 } else {
286 pr_debug("ERROR: unsupported NH format\n");
287 goto err;
288 }
289
1672a36b
AA
290 if (fail)
291 goto err;
292
8df8c56a
JR
293 return 0;
294err:
295 return -EINVAL;
296}
297
298/* TTL uncompression values */
299static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
300
01141234
MT
301int
302lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
303 const u8 *saddr, const u8 saddr_type,
304 const u8 saddr_len, const u8 *daddr,
305 const u8 daddr_type, const u8 daddr_len,
306 u8 iphc0, u8 iphc1)
8df8c56a
JR
307{
308 struct ipv6hdr hdr = {};
309 u8 tmp, num_context = 0;
310 int err;
311
312 raw_dump_table(__func__, "raw skb data dump uncompressed",
4710d806 313 skb->data, skb->len);
8df8c56a
JR
314
315 /* another if the CID flag is set */
316 if (iphc1 & LOWPAN_IPHC_CID) {
317 pr_debug("CID flag is set, increase header with one\n");
4ebc960f 318 if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
56b2c3ee 319 return -EINVAL;
8df8c56a
JR
320 }
321
322 hdr.version = 6;
323
324 /* Traffic Class and Flow Label */
325 switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
4710d806 326 /* Traffic Class and FLow Label carried in-line
8df8c56a
JR
327 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
328 */
329 case 0: /* 00b */
4ebc960f 330 if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
56b2c3ee 331 return -EINVAL;
8df8c56a
JR
332
333 memcpy(&hdr.flow_lbl, &skb->data[0], 3);
334 skb_pull(skb, 3);
335 hdr.priority = ((tmp >> 2) & 0x0f);
336 hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
337 (hdr.flow_lbl[0] & 0x0f);
338 break;
4710d806 339 /* Traffic class carried in-line
8df8c56a
JR
340 * ECN + DSCP (1 byte), Flow Label is elided
341 */
342 case 2: /* 10b */
4ebc960f 343 if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
56b2c3ee 344 return -EINVAL;
8df8c56a
JR
345
346 hdr.priority = ((tmp >> 2) & 0x0f);
347 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
348 break;
4710d806 349 /* Flow Label carried in-line
8df8c56a
JR
350 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
351 */
352 case 1: /* 01b */
4ebc960f 353 if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
56b2c3ee 354 return -EINVAL;
8df8c56a
JR
355
356 hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
357 memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
358 skb_pull(skb, 2);
359 break;
360 /* Traffic Class and Flow Label are elided */
361 case 3: /* 11b */
362 break;
363 default:
364 break;
365 }
366
367 /* Next Header */
368 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
369 /* Next header is carried inline */
4ebc960f 370 if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
56b2c3ee 371 return -EINVAL;
8df8c56a
JR
372
373 pr_debug("NH flag is set, next header carried inline: %02x\n",
374 hdr.nexthdr);
375 }
376
377 /* Hop Limit */
4710d806 378 if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
8df8c56a 379 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
4710d806 380 } else {
4ebc960f
AA
381 if (lowpan_fetch_skb(skb, &hdr.hop_limit,
382 sizeof(hdr.hop_limit)))
56b2c3ee 383 return -EINVAL;
8df8c56a
JR
384 }
385
386 /* Extract SAM to the tmp variable */
387 tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
388
389 if (iphc1 & LOWPAN_IPHC_SAC) {
390 /* Source address context based uncompression */
391 pr_debug("SAC bit is set. Handle context based source address.\n");
7fc4cfda 392 err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp);
8df8c56a
JR
393 } else {
394 /* Source address uncompression */
395 pr_debug("source address stateless compression\n");
396 err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
4710d806 397 saddr_type, saddr_len);
8df8c56a
JR
398 }
399
400 /* Check on error of previous branch */
401 if (err)
56b2c3ee 402 return -EINVAL;
8df8c56a
JR
403
404 /* Extract DAM to the tmp variable */
405 tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
406
407 /* check for Multicast Compression */
408 if (iphc1 & LOWPAN_IPHC_M) {
409 if (iphc1 & LOWPAN_IPHC_DAC) {
410 pr_debug("dest: context-based mcast compression\n");
411 /* TODO: implement this */
412 } else {
7fc4cfda
MH
413 err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
414 tmp);
415
8df8c56a 416 if (err)
56b2c3ee 417 return -EINVAL;
8df8c56a
JR
418 }
419 } else {
420 err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
4710d806 421 daddr_type, daddr_len);
8df8c56a 422 pr_debug("dest: stateless compression mode %d dest %pI6c\n",
4710d806 423 tmp, &hdr.daddr);
8df8c56a 424 if (err)
56b2c3ee 425 return -EINVAL;
8df8c56a
JR
426 }
427
428 /* UDP data uncompression */
429 if (iphc0 & LOWPAN_IPHC_NH_C) {
430 struct udphdr uh;
11e3ff70 431 const int needed = sizeof(struct udphdr) + sizeof(hdr);
4710d806 432
8df8c56a 433 if (uncompress_udp_header(skb, &uh))
56b2c3ee 434 return -EINVAL;
8df8c56a 435
4710d806 436 /* replace the compressed UDP head by the uncompressed UDP
8df8c56a
JR
437 * header
438 */
11e3ff70 439 err = skb_cow(skb, needed);
56b2c3ee 440 if (unlikely(err))
11e3ff70 441 return err;
8df8c56a
JR
442
443 skb_push(skb, sizeof(struct udphdr));
444 skb_reset_transport_header(skb);
445 skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
446
447 raw_dump_table(__func__, "raw UDP header dump",
4710d806 448 (u8 *)&uh, sizeof(uh));
8df8c56a
JR
449
450 hdr.nexthdr = UIP_PROTO_UDP;
11e3ff70
MT
451 } else {
452 err = skb_cow(skb, sizeof(hdr));
56b2c3ee 453 if (unlikely(err))
11e3ff70 454 return err;
8df8c56a
JR
455 }
456
457 hdr.payload_len = htons(skb->len);
458
459 pr_debug("skb headroom size = %d, data length = %d\n",
460 skb_headroom(skb), skb->len);
461
462 pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t"
463 "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n",
464 hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
465 hdr.hop_limit, &hdr.daddr);
466
f8b36176
MT
467 skb_push(skb, sizeof(hdr));
468 skb_reset_network_header(skb);
469 skb_copy_to_linear_data(skb, &hdr, sizeof(hdr));
8df8c56a 470
f8b36176 471 raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
8df8c56a 472
f8b36176 473 return 0;
8df8c56a 474}
01141234 475EXPORT_SYMBOL_GPL(lowpan_header_decompress);
8df8c56a 476
84ca5e03 477static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
4710d806
VB
478 const struct in6_addr *ipaddr,
479 const unsigned char *lladdr)
8df8c56a
JR
480{
481 u8 val = 0;
482
483 if (is_addr_mac_addr_based(ipaddr, lladdr)) {
484 val = 3; /* 0-bits */
485 pr_debug("address compression 0 bits\n");
486 } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
487 /* compress IID to 16 bits xxxx::XXXX */
85c71240 488 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
8df8c56a
JR
489 val = 2; /* 16-bits */
490 raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
84ca5e03 491 *hc_ptr - 2, 2);
8df8c56a
JR
492 } else {
493 /* do not compress IID => xxxx::IID */
85c71240 494 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
8df8c56a
JR
495 val = 1; /* 64-bits */
496 raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
84ca5e03 497 *hc_ptr - 8, 8);
8df8c56a
JR
498 }
499
500 return rol8(val, shift);
501}
502
84ca5e03 503static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
8df8c56a 504{
980edbd5 505 struct udphdr *uh;
5cede84c 506 u8 tmp;
8df8c56a 507
980edbd5
SV
508 /* In the case of RAW sockets the transport header is not set by
509 * the ip6 stack so we must set it ourselves
510 */
511 if (skb->transport_header == skb->network_header)
512 skb_set_transport_header(skb, sizeof(struct ipv6hdr));
513
514 uh = udp_hdr(skb);
515
e5d966ef
AA
516 if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
517 LOWPAN_NHC_UDP_4BIT_PORT) &&
518 ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
519 LOWPAN_NHC_UDP_4BIT_PORT)) {
8df8c56a 520 pr_debug("UDP header: both ports compression to 4 bits\n");
c567c771 521 /* compression value */
5cede84c 522 tmp = LOWPAN_NHC_UDP_CS_P_11;
84ca5e03 523 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
c567c771
AA
524 /* source and destination port */
525 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
526 ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
84ca5e03 527 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
e5d966ef 528 } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
8df8c56a
JR
529 LOWPAN_NHC_UDP_8BIT_PORT) {
530 pr_debug("UDP header: remove 8 bits of dest\n");
c567c771 531 /* compression value */
5cede84c 532 tmp = LOWPAN_NHC_UDP_CS_P_01;
84ca5e03 533 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
c567c771 534 /* source port */
84ca5e03 535 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
c567c771
AA
536 /* destination port */
537 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
84ca5e03 538 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
e5d966ef 539 } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
8df8c56a
JR
540 LOWPAN_NHC_UDP_8BIT_PORT) {
541 pr_debug("UDP header: remove 8 bits of source\n");
c567c771 542 /* compression value */
5cede84c 543 tmp = LOWPAN_NHC_UDP_CS_P_10;
84ca5e03 544 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
c567c771
AA
545 /* source port */
546 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
84ca5e03 547 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
c567c771 548 /* destination port */
84ca5e03 549 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
8df8c56a
JR
550 } else {
551 pr_debug("UDP header: can't compress\n");
c567c771 552 /* compression value */
5cede84c 553 tmp = LOWPAN_NHC_UDP_CS_P_00;
84ca5e03 554 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
c567c771 555 /* source port */
84ca5e03 556 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
c567c771 557 /* destination port */
84ca5e03 558 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
8df8c56a
JR
559 }
560
561 /* checksum is always inline */
84ca5e03 562 lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
8df8c56a
JR
563
564 /* skip the UDP header */
565 skb_pull(skb, sizeof(struct udphdr));
566}
567
568int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
4710d806
VB
569 unsigned short type, const void *_daddr,
570 const void *_saddr, unsigned int len)
8df8c56a 571{
84ca5e03 572 u8 tmp, iphc0, iphc1, *hc_ptr;
8df8c56a
JR
573 struct ipv6hdr *hdr;
574 u8 head[100] = {};
556a5bfc 575 int addr_type;
8df8c56a
JR
576
577 if (type != ETH_P_IPV6)
578 return -EINVAL;
579
580 hdr = ipv6_hdr(skb);
84ca5e03 581 hc_ptr = head + 2;
8df8c56a
JR
582
583 pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n"
584 "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n",
4710d806
VB
585 hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
586 hdr->hop_limit, &hdr->daddr);
8df8c56a
JR
587
588 raw_dump_table(__func__, "raw skb network header dump",
4710d806 589 skb_network_header(skb), sizeof(struct ipv6hdr));
8df8c56a 590
4710d806 591 /* As we copy some bit-length fields, in the IPHC encoding bytes,
8df8c56a
JR
592 * we sometimes use |=
593 * If the field is 0, and the current bit value in memory is 1,
594 * this does not work. We therefore reset the IPHC encoding here
595 */
596 iphc0 = LOWPAN_DISPATCH_IPHC;
597 iphc1 = 0;
598
599 /* TODO: context lookup */
600
601 raw_dump_inline(__func__, "saddr",
602 (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
603 raw_dump_inline(__func__, "daddr",
604 (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
605
7fc4cfda 606 raw_dump_table(__func__, "sending raw skb network uncompressed packet",
4710d806 607 skb->data, skb->len);
8df8c56a 608
4710d806 609 /* Traffic class, flow label
8df8c56a
JR
610 * If flow label is 0, compress it. If traffic class is 0, compress it
611 * We have to process both in the same time as the offset of traffic
612 * class depends on the presence of version and flow label
613 */
614
84ca5e03 615 /* hc format of TC is ECN | DSCP , original one is DSCP | ECN */
8df8c56a
JR
616 tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
617 tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
618
619 if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
4710d806 620 (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
8df8c56a
JR
621 /* flow label can be compressed */
622 iphc0 |= LOWPAN_IPHC_FL_C;
623 if ((hdr->priority == 0) &&
4710d806 624 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
8df8c56a
JR
625 /* compress (elide) all */
626 iphc0 |= LOWPAN_IPHC_TC_C;
627 } else {
628 /* compress only the flow label */
84ca5e03
AA
629 *hc_ptr = tmp;
630 hc_ptr += 1;
8df8c56a
JR
631 }
632 } else {
633 /* Flow label cannot be compressed */
634 if ((hdr->priority == 0) &&
4710d806 635 ((hdr->flow_lbl[0] & 0xF0) == 0)) {
8df8c56a
JR
636 /* compress only traffic class */
637 iphc0 |= LOWPAN_IPHC_TC_C;
84ca5e03
AA
638 *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
639 memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
640 hc_ptr += 3;
8df8c56a
JR
641 } else {
642 /* compress nothing */
84ca5e03 643 memcpy(hc_ptr, hdr, 4);
8df8c56a 644 /* replace the top byte with new ECN | DSCP format */
84ca5e03
AA
645 *hc_ptr = tmp;
646 hc_ptr += 4;
8df8c56a
JR
647 }
648 }
649
650 /* NOTE: payload length is always compressed */
651
652 /* Next Header is compress if UDP */
653 if (hdr->nexthdr == UIP_PROTO_UDP)
654 iphc0 |= LOWPAN_IPHC_NH_C;
655
85c71240
AA
656 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0)
657 lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr,
658 sizeof(hdr->nexthdr));
8df8c56a 659
4710d806 660 /* Hop limit
8df8c56a
JR
661 * if 1: compress, encoding is 01
662 * if 64: compress, encoding is 10
663 * if 255: compress, encoding is 11
664 * else do not compress
665 */
666 switch (hdr->hop_limit) {
667 case 1:
668 iphc0 |= LOWPAN_IPHC_TTL_1;
669 break;
670 case 64:
671 iphc0 |= LOWPAN_IPHC_TTL_64;
672 break;
673 case 255:
674 iphc0 |= LOWPAN_IPHC_TTL_255;
675 break;
676 default:
85c71240
AA
677 lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit,
678 sizeof(hdr->hop_limit));
8df8c56a
JR
679 }
680
556a5bfc 681 addr_type = ipv6_addr_type(&hdr->saddr);
8df8c56a 682 /* source address compression */
556a5bfc 683 if (addr_type == IPV6_ADDR_ANY) {
8df8c56a
JR
684 pr_debug("source address is unspecified, setting SAC\n");
685 iphc1 |= LOWPAN_IPHC_SAC;
8df8c56a 686 } else {
556a5bfc
AA
687 if (addr_type & IPV6_ADDR_LINKLOCAL) {
688 iphc1 |= lowpan_compress_addr_64(&hc_ptr,
689 LOWPAN_IPHC_SAM_BIT,
690 &hdr->saddr, _saddr);
691 pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
692 &hdr->saddr, iphc1);
693 } else {
694 pr_debug("send the full source address\n");
695 lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16);
696 }
8df8c56a
JR
697 }
698
556a5bfc 699 addr_type = ipv6_addr_type(&hdr->daddr);
8df8c56a 700 /* destination address compression */
556a5bfc 701 if (addr_type & IPV6_ADDR_MULTICAST) {
8df8c56a
JR
702 pr_debug("destination address is multicast: ");
703 iphc1 |= LOWPAN_IPHC_M;
704 if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
705 pr_debug("compressed to 1 octet\n");
706 iphc1 |= LOWPAN_IPHC_DAM_11;
707 /* use last byte */
85c71240
AA
708 lowpan_push_hc_data(&hc_ptr,
709 &hdr->daddr.s6_addr[15], 1);
8df8c56a
JR
710 } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
711 pr_debug("compressed to 4 octets\n");
712 iphc1 |= LOWPAN_IPHC_DAM_10;
713 /* second byte + the last three */
85c71240
AA
714 lowpan_push_hc_data(&hc_ptr,
715 &hdr->daddr.s6_addr[1], 1);
716 lowpan_push_hc_data(&hc_ptr,
717 &hdr->daddr.s6_addr[13], 3);
8df8c56a
JR
718 } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
719 pr_debug("compressed to 6 octets\n");
720 iphc1 |= LOWPAN_IPHC_DAM_01;
721 /* second byte + the last five */
85c71240
AA
722 lowpan_push_hc_data(&hc_ptr,
723 &hdr->daddr.s6_addr[1], 1);
724 lowpan_push_hc_data(&hc_ptr,
725 &hdr->daddr.s6_addr[11], 5);
8df8c56a
JR
726 } else {
727 pr_debug("using full address\n");
728 iphc1 |= LOWPAN_IPHC_DAM_00;
85c71240 729 lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
8df8c56a
JR
730 }
731 } else {
556a5bfc
AA
732 if (addr_type & IPV6_ADDR_LINKLOCAL) {
733 /* TODO: context lookup */
84ca5e03 734 iphc1 |= lowpan_compress_addr_64(&hc_ptr,
8df8c56a
JR
735 LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
736 pr_debug("dest address unicast link-local %pI6c "
7fc4cfda 737 "iphc1 0x%02x\n", &hdr->daddr, iphc1);
8df8c56a
JR
738 } else {
739 pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
85c71240 740 lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
8df8c56a
JR
741 }
742 }
743
744 /* UDP header compression */
745 if (hdr->nexthdr == UIP_PROTO_UDP)
84ca5e03 746 compress_udp_header(&hc_ptr, skb);
8df8c56a
JR
747
748 head[0] = iphc0;
749 head[1] = iphc1;
750
751 skb_pull(skb, sizeof(struct ipv6hdr));
752 skb_reset_transport_header(skb);
84ca5e03 753 memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head);
8df8c56a
JR
754 skb_reset_network_header(skb);
755
84ca5e03 756 pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len);
8df8c56a
JR
757
758 raw_dump_table(__func__, "raw skb data dump compressed",
4710d806 759 skb->data, skb->len);
8df8c56a
JR
760 return 0;
761}
762EXPORT_SYMBOL_GPL(lowpan_header_compress);
5ae5e991
YD
763
764MODULE_LICENSE("GPL");