~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/6lowpan/nhc_udp.c

Version: ~ [ linux-5.13-rc1 ] ~ [ linux-5.12.2 ] ~ [ linux-5.11.19 ] ~ [ linux-5.10.35 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.117 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 18 #include "nhc.h"
 19 
 20 #define LOWPAN_NHC_UDP_MASK             0xF8
 21 #define LOWPAN_NHC_UDP_ID               0xF0
 22 #define LOWPAN_NHC_UDP_IDLEN            1
 23 
 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
 28 
 29 /* values for port compression, _with checksum_ ie bit 5 set to 0 */
 30 
 31 /* all inline */
 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
 39 /* checksum elided */
 40 #define LOWPAN_NHC_UDP_CS_C     0x04
 41 
 42 static int udp_uncompress(struct sk_buff *skb, size_t needed)
 43 {
 44         u8 tmp = 0, val = 0;
 45         struct udphdr uh;
 46         bool fail;
 47         int err;
 48 
 49         fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
 50 
 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));
 56                 break;
 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);
 61                 break;
 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));
 66                 break;
 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));
 71                 break;
 72         default:
 73                 BUG();
 74         }
 75 
 76         pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
 77                  ntohs(uh.source), ntohs(uh.dest));
 78 
 79         /* checksum */
 80         if (tmp & LOWPAN_NHC_UDP_CS_C) {
 81                 pr_debug_ratelimited("checksum elided currently not supported\n");
 82                 fail = true;
 83         } else {
 84                 fail |= lowpan_fetch_skb(skb, &uh.check, sizeof(uh.check));
 85         }
 86 
 87         if (fail)
 88                 return -EINVAL;
 89 
 90         /* UDP length needs to be infered from the lower layers
 91          * here, we obtain the hint from the remaining size of the
 92          * frame
 93          */
 94         switch (lowpan_dev(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));
 99                 else
100                         uh.len = htons(skb->len + sizeof(struct udphdr));
101                 break;
102         default:
103                 uh.len = htons(skb->len + sizeof(struct udphdr));
104                 break;
105         }
106         pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len));
107 
108         /* replace the compressed UDP head by the uncompressed UDP
109          * header
110          */
111         err = skb_cow(skb, needed);
112         if (unlikely(err))
113                 return err;
114 
115         skb_push(skb, sizeof(struct udphdr));
116         skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
117 
118         return 0;
119 }
120 
121 static int udp_compress(struct sk_buff *skb, u8 **hc_ptr)
122 {
123         const struct udphdr *uh = udp_hdr(skb);
124         u8 tmp;
125 
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));
144                 /* source port */
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));
155                 /* source port */
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));
160         } else {
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));
165                 /* source port */
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));
169         }
170 
171         /* checksum is always inline */
172         lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
173 
174         return 0;
175 }
176 
177 static void udp_nhid_setup(struct lowpan_nhc *nhc)
178 {
179         nhc->id[0] = LOWPAN_NHC_UDP_ID;
180         nhc->idmask[0] = LOWPAN_NHC_UDP_MASK;
181 }
182 
183 LOWPAN_NHC(nhc_udp, "RFC6282 UDP", NEXTHDR_UDP, sizeof(struct udphdr),
184            udp_nhid_setup, LOWPAN_NHC_UDP_IDLEN, udp_uncompress, udp_compress);
185 
186 module_lowpan_nhc(nhc_udp);
187 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 UDP compression");
188 MODULE_LICENSE("GPL");
189 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp