]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/6lowpan/iphc.c
Merge tag 'iio-fixes-for-3.19a' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / net / 6lowpan / iphc.c
1 /*
2  * Copyright 2011, Siemens AG
3  * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
4  */
5
6 /* Based on patches from Jon Smirl <jonsmirl@gmail.com>
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  *
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>
51 #include <linux/module.h>
52 #include <linux/netdevice.h>
53 #include <net/6lowpan.h>
54 #include <net/ipv6.h>
55 #include <net/af_ieee802154.h>
56
57 /* Uncompress address function for source and
58  * destination address(non-multicast).
59  *
60  * address_mode is sam value or dam value.
61  */
62 static int uncompress_addr(struct sk_buff *skb,
63                            struct in6_addr *ipaddr, const u8 address_mode,
64                            const u8 *lladdr, const u8 addr_type,
65                            const u8 addr_len)
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
138 /* Uncompress address function for source context
139  * based address(non-multicast).
140  */
141 static int uncompress_context_based_src_addr(struct sk_buff *skb,
142                                              struct in6_addr *ipaddr,
143                                              const u8 sam)
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
171 /* Uncompress function for multicast destination address,
172  * when M bit is set.
173  */
174 static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
175                                              struct in6_addr *ipaddr,
176                                              const u8 dam)
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",
222                         ipaddr->s6_addr, 16);
223
224         return 0;
225 }
226
227 static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
228 {
229         bool fail;
230         u8 tmp = 0, val = 0;
231
232         fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
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:
238                         fail |= lowpan_fetch_skb(skb, &uh->source,
239                                                  sizeof(uh->source));
240                         fail |= lowpan_fetch_skb(skb, &uh->dest,
241                                                  sizeof(uh->dest));
242                         break;
243                 case LOWPAN_NHC_UDP_CS_P_01:
244                         fail |= lowpan_fetch_skb(skb, &uh->source,
245                                                  sizeof(uh->source));
246                         fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
247                         uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
248                         break;
249                 case LOWPAN_NHC_UDP_CS_P_10:
250                         fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
251                         uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
252                         fail |= lowpan_fetch_skb(skb, &uh->dest,
253                                                  sizeof(uh->dest));
254                         break;
255                 case LOWPAN_NHC_UDP_CS_P_11:
256                         fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
257                         uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
258                                            (val >> 4));
259                         uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
260                                          (val & 0x0f));
261                         break;
262                 default:
263                         pr_debug("ERROR: unknown UDP format\n");
264                         goto err;
265                 }
266
267                 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
268                          ntohs(uh->source), ntohs(uh->dest));
269
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 {
275                         fail |= lowpan_fetch_skb(skb, &uh->check,
276                                                  sizeof(uh->check));
277                 }
278
279                 /* UDP length needs to be infered from the lower layers
280                  * here, we obtain the hint from the remaining size of the
281                  * frame
282                  */
283                 uh->len = htons(skb->len + sizeof(struct udphdr));
284                 pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
285         } else {
286                 pr_debug("ERROR: unsupported NH format\n");
287                 goto err;
288         }
289
290         if (fail)
291                 goto err;
292
293         return 0;
294 err:
295         return -EINVAL;
296 }
297
298 /* TTL uncompression values */
299 static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
300
301 int
302 lowpan_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)
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",
313                        skb->data, skb->len);
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");
318                 if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
319                         return -EINVAL;
320         }
321
322         hdr.version = 6;
323
324         /* Traffic Class and Flow Label */
325         switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
326         /* Traffic Class and FLow Label carried in-line
327          * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
328          */
329         case 0: /* 00b */
330                 if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
331                         return -EINVAL;
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;
339         /* Traffic class carried in-line
340          * ECN + DSCP (1 byte), Flow Label is elided
341          */
342         case 2: /* 10b */
343                 if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
344                         return -EINVAL;
345
346                 hdr.priority = ((tmp >> 2) & 0x0f);
347                 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
348                 break;
349         /* Flow Label carried in-line
350          * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
351          */
352         case 1: /* 01b */
353                 if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
354                         return -EINVAL;
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 */
370                 if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
371                         return -EINVAL;
372
373                 pr_debug("NH flag is set, next header carried inline: %02x\n",
374                          hdr.nexthdr);
375         }
376
377         /* Hop Limit */
378         if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
379                 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
380         } else {
381                 if (lowpan_fetch_skb(skb, &hdr.hop_limit,
382                                      sizeof(hdr.hop_limit)))
383                         return -EINVAL;
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");
392                 err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp);
393         } else {
394                 /* Source address uncompression */
395                 pr_debug("source address stateless compression\n");
396                 err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
397                                       saddr_type, saddr_len);
398         }
399
400         /* Check on error of previous branch */
401         if (err)
402                 return -EINVAL;
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 {
413                         err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
414                                                                 tmp);
415
416                         if (err)
417                                 return -EINVAL;
418                 }
419         } else {
420                 err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
421                                       daddr_type, daddr_len);
422                 pr_debug("dest: stateless compression mode %d dest %pI6c\n",
423                          tmp, &hdr.daddr);
424                 if (err)
425                         return -EINVAL;
426         }
427
428         /* UDP data uncompression */
429         if (iphc0 & LOWPAN_IPHC_NH_C) {
430                 struct udphdr uh;
431                 const int needed = sizeof(struct udphdr) + sizeof(hdr);
432
433                 if (uncompress_udp_header(skb, &uh))
434                         return -EINVAL;
435
436                 /* replace the compressed UDP head by the uncompressed UDP
437                  * header
438                  */
439                 err = skb_cow(skb, needed);
440                 if (unlikely(err))
441                         return err;
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",
448                                (u8 *)&uh, sizeof(uh));
449
450                 hdr.nexthdr = UIP_PROTO_UDP;
451         } else {
452                 err = skb_cow(skb, sizeof(hdr));
453                 if (unlikely(err))
454                         return err;
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
467         skb_push(skb, sizeof(hdr));
468         skb_reset_network_header(skb);
469         skb_copy_to_linear_data(skb, &hdr, sizeof(hdr));
470
471         raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
472
473         return 0;
474 }
475 EXPORT_SYMBOL_GPL(lowpan_header_decompress);
476
477 static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
478                                   const struct in6_addr *ipaddr,
479                                   const unsigned char *lladdr)
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 */
488                 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
489                 val = 2; /* 16-bits */
490                 raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
491                                 *hc_ptr - 2, 2);
492         } else {
493                 /* do not compress IID => xxxx::IID */
494                 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
495                 val = 1; /* 64-bits */
496                 raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
497                                 *hc_ptr - 8, 8);
498         }
499
500         return rol8(val, shift);
501 }
502
503 static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
504 {
505         struct udphdr *uh;
506         u8 tmp;
507
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
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)) {
520                 pr_debug("UDP header: both ports compression to 4 bits\n");
521                 /* compression value */
522                 tmp = LOWPAN_NHC_UDP_CS_P_11;
523                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
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);
527                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
528         } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
529                         LOWPAN_NHC_UDP_8BIT_PORT) {
530                 pr_debug("UDP header: remove 8 bits of dest\n");
531                 /* compression value */
532                 tmp = LOWPAN_NHC_UDP_CS_P_01;
533                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
534                 /* source port */
535                 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
536                 /* destination port */
537                 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
538                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
539         } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
540                         LOWPAN_NHC_UDP_8BIT_PORT) {
541                 pr_debug("UDP header: remove 8 bits of source\n");
542                 /* compression value */
543                 tmp = LOWPAN_NHC_UDP_CS_P_10;
544                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
545                 /* source port */
546                 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
547                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
548                 /* destination port */
549                 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
550         } else {
551                 pr_debug("UDP header: can't compress\n");
552                 /* compression value */
553                 tmp = LOWPAN_NHC_UDP_CS_P_00;
554                 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
555                 /* source port */
556                 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
557                 /* destination port */
558                 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
559         }
560
561         /* checksum is always inline */
562         lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
563
564         /* skip the UDP header */
565         skb_pull(skb, sizeof(struct udphdr));
566 }
567
568 int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
569                            unsigned short type, const void *_daddr,
570                            const void *_saddr, unsigned int len)
571 {
572         u8 tmp, iphc0, iphc1, *hc_ptr;
573         struct ipv6hdr *hdr;
574         u8 head[100] = {};
575         int addr_type;
576
577         if (type != ETH_P_IPV6)
578                 return -EINVAL;
579
580         hdr = ipv6_hdr(skb);
581         hc_ptr = head + 2;
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",
585                  hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
586                  hdr->hop_limit, &hdr->daddr);
587
588         raw_dump_table(__func__, "raw skb network header dump",
589                        skb_network_header(skb), sizeof(struct ipv6hdr));
590
591         /* As we copy some bit-length fields, in the IPHC encoding bytes,
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
606         raw_dump_table(__func__, "sending raw skb network uncompressed packet",
607                        skb->data, skb->len);
608
609         /* Traffic class, flow label
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
615         /* hc format of TC is ECN | DSCP , original one is DSCP | ECN */
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) &&
620             (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
621                 /* flow label can be compressed */
622                 iphc0 |= LOWPAN_IPHC_FL_C;
623                 if ((hdr->priority == 0) &&
624                     ((hdr->flow_lbl[0] & 0xF0) == 0)) {
625                         /* compress (elide) all */
626                         iphc0 |= LOWPAN_IPHC_TC_C;
627                 } else {
628                         /* compress only the flow label */
629                         *hc_ptr = tmp;
630                         hc_ptr += 1;
631                 }
632         } else {
633                 /* Flow label cannot be compressed */
634                 if ((hdr->priority == 0) &&
635                     ((hdr->flow_lbl[0] & 0xF0) == 0)) {
636                         /* compress only traffic class */
637                         iphc0 |= LOWPAN_IPHC_TC_C;
638                         *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
639                         memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
640                         hc_ptr += 3;
641                 } else {
642                         /* compress nothing */
643                         memcpy(hc_ptr, hdr, 4);
644                         /* replace the top byte with new ECN | DSCP format */
645                         *hc_ptr = tmp;
646                         hc_ptr += 4;
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
656         if ((iphc0 & LOWPAN_IPHC_NH_C) == 0)
657                 lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr,
658                                     sizeof(hdr->nexthdr));
659
660         /* Hop limit
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:
677                 lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit,
678                                     sizeof(hdr->hop_limit));
679         }
680
681         addr_type = ipv6_addr_type(&hdr->saddr);
682         /* source address compression */
683         if (addr_type == IPV6_ADDR_ANY) {
684                 pr_debug("source address is unspecified, setting SAC\n");
685                 iphc1 |= LOWPAN_IPHC_SAC;
686         } else {
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                 }
697         }
698
699         addr_type = ipv6_addr_type(&hdr->daddr);
700         /* destination address compression */
701         if (addr_type & IPV6_ADDR_MULTICAST) {
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 */
708                         lowpan_push_hc_data(&hc_ptr,
709                                             &hdr->daddr.s6_addr[15], 1);
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 */
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);
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 */
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);
726                 } else {
727                         pr_debug("using full address\n");
728                         iphc1 |= LOWPAN_IPHC_DAM_00;
729                         lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
730                 }
731         } else {
732                 if (addr_type & IPV6_ADDR_LINKLOCAL) {
733                         /* TODO: context lookup */
734                         iphc1 |= lowpan_compress_addr_64(&hc_ptr,
735                                 LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
736                         pr_debug("dest address unicast link-local %pI6c "
737                                  "iphc1 0x%02x\n", &hdr->daddr, iphc1);
738                 } else {
739                         pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
740                         lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
741                 }
742         }
743
744         /* UDP header compression */
745         if (hdr->nexthdr == UIP_PROTO_UDP)
746                 compress_udp_header(&hc_ptr, skb);
747
748         head[0] = iphc0;
749         head[1] = iphc1;
750
751         skb_pull(skb, sizeof(struct ipv6hdr));
752         skb_reset_transport_header(skb);
753         memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head);
754         skb_reset_network_header(skb);
755
756         pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len);
757
758         raw_dump_table(__func__, "raw skb data dump compressed",
759                        skb->data, skb->len);
760         return 0;
761 }
762 EXPORT_SYMBOL_GPL(lowpan_header_compress);
763
764 MODULE_LICENSE("GPL");