18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2011, Siemens AG 38c2ecf20Sopenharmony_ci * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* Based on patches from Jon Smirl <jonsmirl@gmail.com> 78c2ecf20Sopenharmony_ci * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 118c2ecf20Sopenharmony_ci * as published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 148c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 168c2ecf20Sopenharmony_ci * GNU General Public License for more details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* Jon's code is based on 6lowpan implementation for Contiki which is: 218c2ecf20Sopenharmony_ci * Copyright (c) 2008, Swedish Institute of Computer Science. 228c2ecf20Sopenharmony_ci * All rights reserved. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 258c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 268c2ecf20Sopenharmony_ci * are met: 278c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 288c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 298c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 308c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 318c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 328c2ecf20Sopenharmony_ci * 3. Neither the name of the Institute nor the names of its contributors 338c2ecf20Sopenharmony_ci * may be used to endorse or promote products derived from this software 348c2ecf20Sopenharmony_ci * without specific prior written permission. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 378c2ecf20Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 388c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 398c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 408c2ecf20Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 418c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 428c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 438c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 448c2ecf20Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 458c2ecf20Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 468c2ecf20Sopenharmony_ci * SUCH DAMAGE. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <linux/bitops.h> 508c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 518c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include <net/6lowpan.h> 548c2ecf20Sopenharmony_ci#include <net/ipv6.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include "6lowpan_i.h" 578c2ecf20Sopenharmony_ci#include "nhc.h" 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Values of fields within the IPHC encoding first byte */ 608c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_TF_MASK 0x18 618c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_TF_00 0x00 628c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_TF_01 0x08 638c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_TF_10 0x10 648c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_TF_11 0x18 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_NH 0x04 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_HLIM_MASK 0x03 698c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_HLIM_00 0x00 708c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_HLIM_01 0x01 718c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_HLIM_10 0x02 728c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_HLIM_11 0x03 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Values of fields within the IPHC encoding second byte */ 758c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_CID 0x80 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_SAC 0x40 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_SAM_MASK 0x30 808c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_SAM_00 0x00 818c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_SAM_01 0x10 828c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_SAM_10 0x20 838c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_SAM_11 0x30 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_M 0x08 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_DAC 0x04 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_DAM_MASK 0x03 908c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_DAM_00 0x00 918c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_DAM_01 0x01 928c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_DAM_10 0x02 938c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_DAM_11 0x03 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* ipv6 address based on mac 968c2ecf20Sopenharmony_ci * second bit-flip (Universe/Local) is done according RFC2464 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci#define is_addr_mac_addr_based(a, m) \ 998c2ecf20Sopenharmony_ci ((((a)->s6_addr[8]) == (((m)[0]) ^ 0x02)) && \ 1008c2ecf20Sopenharmony_ci (((a)->s6_addr[9]) == (m)[1]) && \ 1018c2ecf20Sopenharmony_ci (((a)->s6_addr[10]) == (m)[2]) && \ 1028c2ecf20Sopenharmony_ci (((a)->s6_addr[11]) == (m)[3]) && \ 1038c2ecf20Sopenharmony_ci (((a)->s6_addr[12]) == (m)[4]) && \ 1048c2ecf20Sopenharmony_ci (((a)->s6_addr[13]) == (m)[5]) && \ 1058c2ecf20Sopenharmony_ci (((a)->s6_addr[14]) == (m)[6]) && \ 1068c2ecf20Sopenharmony_ci (((a)->s6_addr[15]) == (m)[7])) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* check whether we can compress the IID to 16 bits, 1098c2ecf20Sopenharmony_ci * it's possible for unicast addresses with first 49 bits are zero only. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci#define lowpan_is_iid_16_bit_compressable(a) \ 1128c2ecf20Sopenharmony_ci ((((a)->s6_addr16[4]) == 0) && \ 1138c2ecf20Sopenharmony_ci (((a)->s6_addr[10]) == 0) && \ 1148c2ecf20Sopenharmony_ci (((a)->s6_addr[11]) == 0xff) && \ 1158c2ecf20Sopenharmony_ci (((a)->s6_addr[12]) == 0xfe) && \ 1168c2ecf20Sopenharmony_ci (((a)->s6_addr[13]) == 0)) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* check whether the 112-bit gid of the multicast address is mappable to: */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* 48 bits, FFXX::00XX:XXXX:XXXX */ 1218c2ecf20Sopenharmony_ci#define lowpan_is_mcast_addr_compressable48(a) \ 1228c2ecf20Sopenharmony_ci ((((a)->s6_addr16[1]) == 0) && \ 1238c2ecf20Sopenharmony_ci (((a)->s6_addr16[2]) == 0) && \ 1248c2ecf20Sopenharmony_ci (((a)->s6_addr16[3]) == 0) && \ 1258c2ecf20Sopenharmony_ci (((a)->s6_addr16[4]) == 0) && \ 1268c2ecf20Sopenharmony_ci (((a)->s6_addr[10]) == 0)) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* 32 bits, FFXX::00XX:XXXX */ 1298c2ecf20Sopenharmony_ci#define lowpan_is_mcast_addr_compressable32(a) \ 1308c2ecf20Sopenharmony_ci ((((a)->s6_addr16[1]) == 0) && \ 1318c2ecf20Sopenharmony_ci (((a)->s6_addr16[2]) == 0) && \ 1328c2ecf20Sopenharmony_ci (((a)->s6_addr16[3]) == 0) && \ 1338c2ecf20Sopenharmony_ci (((a)->s6_addr16[4]) == 0) && \ 1348c2ecf20Sopenharmony_ci (((a)->s6_addr16[5]) == 0) && \ 1358c2ecf20Sopenharmony_ci (((a)->s6_addr[12]) == 0)) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* 8 bits, FF02::00XX */ 1388c2ecf20Sopenharmony_ci#define lowpan_is_mcast_addr_compressable8(a) \ 1398c2ecf20Sopenharmony_ci ((((a)->s6_addr[1]) == 2) && \ 1408c2ecf20Sopenharmony_ci (((a)->s6_addr16[1]) == 0) && \ 1418c2ecf20Sopenharmony_ci (((a)->s6_addr16[2]) == 0) && \ 1428c2ecf20Sopenharmony_ci (((a)->s6_addr16[3]) == 0) && \ 1438c2ecf20Sopenharmony_ci (((a)->s6_addr16[4]) == 0) && \ 1448c2ecf20Sopenharmony_ci (((a)->s6_addr16[5]) == 0) && \ 1458c2ecf20Sopenharmony_ci (((a)->s6_addr16[6]) == 0) && \ 1468c2ecf20Sopenharmony_ci (((a)->s6_addr[14]) == 0)) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define lowpan_is_linklocal_zero_padded(a) \ 1498c2ecf20Sopenharmony_ci (!(hdr->saddr.s6_addr[1] & 0x3f) && \ 1508c2ecf20Sopenharmony_ci !hdr->saddr.s6_addr16[1] && \ 1518c2ecf20Sopenharmony_ci !hdr->saddr.s6_addr32[1]) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_CID_DCI(cid) (cid & 0x0f) 1548c2ecf20Sopenharmony_ci#define LOWPAN_IPHC_CID_SCI(cid) ((cid & 0xf0) >> 4) 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void 1578c2ecf20Sopenharmony_cilowpan_iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr, 1588c2ecf20Sopenharmony_ci const void *lladdr) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci const struct ieee802154_addr *addr = lladdr; 1618c2ecf20Sopenharmony_ci u8 eui64[EUI64_ADDR_LEN]; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci switch (addr->mode) { 1648c2ecf20Sopenharmony_ci case IEEE802154_ADDR_LONG: 1658c2ecf20Sopenharmony_ci ieee802154_le64_to_be64(eui64, &addr->extended_addr); 1668c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_eui64_lladdr(ipaddr, eui64); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case IEEE802154_ADDR_SHORT: 1698c2ecf20Sopenharmony_ci /* fe:80::ff:fe00:XXXX 1708c2ecf20Sopenharmony_ci * \__/ 1718c2ecf20Sopenharmony_ci * short_addr 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * Universe/Local bit is zero. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFE; 1768c2ecf20Sopenharmony_ci ipaddr->s6_addr[1] = 0x80; 1778c2ecf20Sopenharmony_ci ipaddr->s6_addr[11] = 0xFF; 1788c2ecf20Sopenharmony_ci ipaddr->s6_addr[12] = 0xFE; 1798c2ecf20Sopenharmony_ci ieee802154_le16_to_be16(&ipaddr->s6_addr16[7], 1808c2ecf20Sopenharmony_ci &addr->short_addr); 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci default: 1838c2ecf20Sopenharmony_ci /* should never handled and filtered by 802154 6lowpan */ 1848c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct lowpan_iphc_ctx * 1908c2ecf20Sopenharmony_cilowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ret = &lowpan_dev(dev)->ctx.table[id]; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!lowpan_iphc_ctx_is_active(ret)) 1958c2ecf20Sopenharmony_ci return NULL; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic struct lowpan_iphc_ctx * 2018c2ecf20Sopenharmony_cilowpan_iphc_ctx_get_by_addr(const struct net_device *dev, 2028c2ecf20Sopenharmony_ci const struct in6_addr *addr) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table; 2058c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ret = NULL; 2068c2ecf20Sopenharmony_ci struct in6_addr addr_pfx; 2078c2ecf20Sopenharmony_ci u8 addr_plen; 2088c2ecf20Sopenharmony_ci int i; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2118c2ecf20Sopenharmony_ci /* Check if context is valid. A context that is not valid 2128c2ecf20Sopenharmony_ci * MUST NOT be used for compression. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci if (!lowpan_iphc_ctx_is_active(&table[i]) || 2158c2ecf20Sopenharmony_ci !lowpan_iphc_ctx_is_compression(&table[i])) 2168c2ecf20Sopenharmony_ci continue; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ipv6_addr_prefix(&addr_pfx, addr, table[i].plen); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* if prefix len < 64, the remaining bits until 64th bit is 2218c2ecf20Sopenharmony_ci * zero. Otherwise we use table[i]->plen. 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci if (table[i].plen < 64) 2248c2ecf20Sopenharmony_ci addr_plen = 64; 2258c2ecf20Sopenharmony_ci else 2268c2ecf20Sopenharmony_ci addr_plen = table[i].plen; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (ipv6_prefix_equal(&addr_pfx, &table[i].pfx, addr_plen)) { 2298c2ecf20Sopenharmony_ci /* remember first match */ 2308c2ecf20Sopenharmony_ci if (!ret) { 2318c2ecf20Sopenharmony_ci ret = &table[i]; 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* get the context with longest prefix len */ 2368c2ecf20Sopenharmony_ci if (table[i].plen > ret->plen) 2378c2ecf20Sopenharmony_ci ret = &table[i]; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic struct lowpan_iphc_ctx * 2458c2ecf20Sopenharmony_cilowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev, 2468c2ecf20Sopenharmony_ci const struct in6_addr *addr) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table; 2498c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ret = NULL; 2508c2ecf20Sopenharmony_ci struct in6_addr addr_mcast, network_pfx = {}; 2518c2ecf20Sopenharmony_ci int i; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* init mcast address with */ 2548c2ecf20Sopenharmony_ci memcpy(&addr_mcast, addr, sizeof(*addr)); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { 2578c2ecf20Sopenharmony_ci /* Check if context is valid. A context that is not valid 2588c2ecf20Sopenharmony_ci * MUST NOT be used for compression. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci if (!lowpan_iphc_ctx_is_active(&table[i]) || 2618c2ecf20Sopenharmony_ci !lowpan_iphc_ctx_is_compression(&table[i])) 2628c2ecf20Sopenharmony_ci continue; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* setting plen */ 2658c2ecf20Sopenharmony_ci addr_mcast.s6_addr[3] = table[i].plen; 2668c2ecf20Sopenharmony_ci /* get network prefix to copy into multicast address */ 2678c2ecf20Sopenharmony_ci ipv6_addr_prefix(&network_pfx, &table[i].pfx, 2688c2ecf20Sopenharmony_ci table[i].plen); 2698c2ecf20Sopenharmony_ci /* setting network prefix */ 2708c2ecf20Sopenharmony_ci memcpy(&addr_mcast.s6_addr[4], &network_pfx, 8); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (ipv6_addr_equal(addr, &addr_mcast)) { 2738c2ecf20Sopenharmony_ci ret = &table[i]; 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic void lowpan_iphc_uncompress_lladdr(const struct net_device *dev, 2828c2ecf20Sopenharmony_ci struct in6_addr *ipaddr, 2838c2ecf20Sopenharmony_ci const void *lladdr) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci switch (dev->addr_len) { 2868c2ecf20Sopenharmony_ci case ETH_ALEN: 2878c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_eui48_lladdr(ipaddr, lladdr); 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case EUI64_ADDR_LEN: 2908c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci default: 2938c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* Uncompress address function for source and 2998c2ecf20Sopenharmony_ci * destination address(non-multicast). 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * address_mode is the masked value for sam or dam value 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_cistatic int lowpan_iphc_uncompress_addr(struct sk_buff *skb, 3048c2ecf20Sopenharmony_ci const struct net_device *dev, 3058c2ecf20Sopenharmony_ci struct in6_addr *ipaddr, 3068c2ecf20Sopenharmony_ci u8 address_mode, const void *lladdr) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci bool fail; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci switch (address_mode) { 3118c2ecf20Sopenharmony_ci /* SAM and DAM are the same here */ 3128c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_00: 3138c2ecf20Sopenharmony_ci /* for global link addresses */ 3148c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci case LOWPAN_IPHC_SAM_01: 3178c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_01: 3188c2ecf20Sopenharmony_ci /* fe:80::XXXX:XXXX:XXXX:XXXX */ 3198c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFE; 3208c2ecf20Sopenharmony_ci ipaddr->s6_addr[1] = 0x80; 3218c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci case LOWPAN_IPHC_SAM_10: 3248c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_10: 3258c2ecf20Sopenharmony_ci /* fe:80::ff:fe00:XXXX */ 3268c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFE; 3278c2ecf20Sopenharmony_ci ipaddr->s6_addr[1] = 0x80; 3288c2ecf20Sopenharmony_ci ipaddr->s6_addr[11] = 0xFF; 3298c2ecf20Sopenharmony_ci ipaddr->s6_addr[12] = 0xFE; 3308c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case LOWPAN_IPHC_SAM_11: 3338c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_11: 3348c2ecf20Sopenharmony_ci fail = false; 3358c2ecf20Sopenharmony_ci switch (lowpan_dev(dev)->lltype) { 3368c2ecf20Sopenharmony_ci case LOWPAN_LLTYPE_IEEE802154: 3378c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci default: 3408c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci default: 3458c2ecf20Sopenharmony_ci pr_debug("Invalid address mode value: 0x%x\n", address_mode); 3468c2ecf20Sopenharmony_ci return -EINVAL; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (fail) { 3508c2ecf20Sopenharmony_ci pr_debug("Failed to fetch skb data\n"); 3518c2ecf20Sopenharmony_ci return -EIO; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci raw_dump_inline(NULL, "Reconstructed ipv6 addr is", 3558c2ecf20Sopenharmony_ci ipaddr->s6_addr, 16); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* Uncompress address function for source context 3618c2ecf20Sopenharmony_ci * based address(non-multicast). 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_cistatic int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb, 3648c2ecf20Sopenharmony_ci const struct net_device *dev, 3658c2ecf20Sopenharmony_ci const struct lowpan_iphc_ctx *ctx, 3668c2ecf20Sopenharmony_ci struct in6_addr *ipaddr, 3678c2ecf20Sopenharmony_ci u8 address_mode, const void *lladdr) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci bool fail; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci switch (address_mode) { 3728c2ecf20Sopenharmony_ci /* SAM and DAM are the same here */ 3738c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_00: 3748c2ecf20Sopenharmony_ci fail = false; 3758c2ecf20Sopenharmony_ci /* SAM_00 -> unspec address :: 3768c2ecf20Sopenharmony_ci * Do nothing, address is already :: 3778c2ecf20Sopenharmony_ci * 3788c2ecf20Sopenharmony_ci * DAM 00 -> reserved should never occur. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case LOWPAN_IPHC_SAM_01: 3828c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_01: 3838c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); 3848c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case LOWPAN_IPHC_SAM_10: 3878c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_10: 3888c2ecf20Sopenharmony_ci ipaddr->s6_addr[11] = 0xFF; 3898c2ecf20Sopenharmony_ci ipaddr->s6_addr[12] = 0xFE; 3908c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); 3918c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci case LOWPAN_IPHC_SAM_11: 3948c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_11: 3958c2ecf20Sopenharmony_ci fail = false; 3968c2ecf20Sopenharmony_ci switch (lowpan_dev(dev)->lltype) { 3978c2ecf20Sopenharmony_ci case LOWPAN_LLTYPE_IEEE802154: 3988c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci default: 4018c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci default: 4078c2ecf20Sopenharmony_ci pr_debug("Invalid sam value: 0x%x\n", address_mode); 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (fail) { 4128c2ecf20Sopenharmony_ci pr_debug("Failed to fetch skb data\n"); 4138c2ecf20Sopenharmony_ci return -EIO; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci raw_dump_inline(NULL, 4178c2ecf20Sopenharmony_ci "Reconstructed context based ipv6 src addr is", 4188c2ecf20Sopenharmony_ci ipaddr->s6_addr, 16); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* Uncompress function for multicast destination address, 4248c2ecf20Sopenharmony_ci * when M bit is set. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_cistatic int lowpan_uncompress_multicast_daddr(struct sk_buff *skb, 4278c2ecf20Sopenharmony_ci struct in6_addr *ipaddr, 4288c2ecf20Sopenharmony_ci u8 address_mode) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci bool fail; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci switch (address_mode) { 4338c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_00: 4348c2ecf20Sopenharmony_ci /* 00: 128 bits. The full address 4358c2ecf20Sopenharmony_ci * is carried in-line. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_01: 4408c2ecf20Sopenharmony_ci /* 01: 48 bits. The address takes 4418c2ecf20Sopenharmony_ci * the form ffXX::00XX:XXXX:XXXX. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFF; 4448c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); 4458c2ecf20Sopenharmony_ci fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_10: 4488c2ecf20Sopenharmony_ci /* 10: 32 bits. The address takes 4498c2ecf20Sopenharmony_ci * the form ffXX::00XX:XXXX. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFF; 4528c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); 4538c2ecf20Sopenharmony_ci fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAM_11: 4568c2ecf20Sopenharmony_ci /* 11: 8 bits. The address takes 4578c2ecf20Sopenharmony_ci * the form ff02::00XX. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFF; 4608c2ecf20Sopenharmony_ci ipaddr->s6_addr[1] = 0x02; 4618c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci default: 4648c2ecf20Sopenharmony_ci pr_debug("DAM value has a wrong value: 0x%x\n", address_mode); 4658c2ecf20Sopenharmony_ci return -EINVAL; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (fail) { 4698c2ecf20Sopenharmony_ci pr_debug("Failed to fetch skb data\n"); 4708c2ecf20Sopenharmony_ci return -EIO; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", 4748c2ecf20Sopenharmony_ci ipaddr->s6_addr, 16); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int lowpan_uncompress_multicast_ctx_daddr(struct sk_buff *skb, 4808c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ctx, 4818c2ecf20Sopenharmony_ci struct in6_addr *ipaddr, 4828c2ecf20Sopenharmony_ci u8 address_mode) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct in6_addr network_pfx = {}; 4858c2ecf20Sopenharmony_ci bool fail; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci ipaddr->s6_addr[0] = 0xFF; 4888c2ecf20Sopenharmony_ci fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 2); 4898c2ecf20Sopenharmony_ci fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[12], 4); 4908c2ecf20Sopenharmony_ci if (fail) 4918c2ecf20Sopenharmony_ci return -EIO; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* take prefix_len and network prefix from the context */ 4948c2ecf20Sopenharmony_ci ipaddr->s6_addr[3] = ctx->plen; 4958c2ecf20Sopenharmony_ci /* get network prefix to copy into multicast address */ 4968c2ecf20Sopenharmony_ci ipv6_addr_prefix(&network_pfx, &ctx->pfx, ctx->plen); 4978c2ecf20Sopenharmony_ci /* setting network prefix */ 4988c2ecf20Sopenharmony_ci memcpy(&ipaddr->s6_addr[4], &network_pfx, 8); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* get the ecn values from iphc tf format and set it to ipv6hdr */ 5048c2ecf20Sopenharmony_cistatic inline void lowpan_iphc_tf_set_ecn(struct ipv6hdr *hdr, const u8 *tf) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci /* get the two higher bits which is ecn */ 5078c2ecf20Sopenharmony_ci u8 ecn = tf[0] & 0xc0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* ECN takes 0x30 in hdr->flow_lbl[0] */ 5108c2ecf20Sopenharmony_ci hdr->flow_lbl[0] |= (ecn >> 2); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/* get the dscp values from iphc tf format and set it to ipv6hdr */ 5148c2ecf20Sopenharmony_cistatic inline void lowpan_iphc_tf_set_dscp(struct ipv6hdr *hdr, const u8 *tf) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci /* DSCP is at place after ECN */ 5178c2ecf20Sopenharmony_ci u8 dscp = tf[0] & 0x3f; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* The four highest bits need to be set at hdr->priority */ 5208c2ecf20Sopenharmony_ci hdr->priority |= ((dscp & 0x3c) >> 2); 5218c2ecf20Sopenharmony_ci /* The two lower bits is part of hdr->flow_lbl[0] */ 5228c2ecf20Sopenharmony_ci hdr->flow_lbl[0] |= ((dscp & 0x03) << 6); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* get the flow label values from iphc tf format and set it to ipv6hdr */ 5268c2ecf20Sopenharmony_cistatic inline void lowpan_iphc_tf_set_lbl(struct ipv6hdr *hdr, const u8 *lbl) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci /* flow label is always some array started with lower nibble of 5298c2ecf20Sopenharmony_ci * flow_lbl[0] and followed with two bytes afterwards. Inside inline 5308c2ecf20Sopenharmony_ci * data the flow_lbl position can be different, which will be handled 5318c2ecf20Sopenharmony_ci * by lbl pointer. E.g. case "01" vs "00" the traffic class is 8 bit 5328c2ecf20Sopenharmony_ci * shifted, the different lbl pointer will handle that. 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * The flow label will started at lower nibble of flow_lbl[0], the 5358c2ecf20Sopenharmony_ci * higher nibbles are part of DSCP + ECN. 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci hdr->flow_lbl[0] |= lbl[0] & 0x0f; 5388c2ecf20Sopenharmony_ci memcpy(&hdr->flow_lbl[1], &lbl[1], 2); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* lowpan_iphc_tf_decompress - decompress the traffic class. 5428c2ecf20Sopenharmony_ci * This function will return zero on success, a value lower than zero if 5438c2ecf20Sopenharmony_ci * failed. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic int lowpan_iphc_tf_decompress(struct sk_buff *skb, struct ipv6hdr *hdr, 5468c2ecf20Sopenharmony_ci u8 val) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci u8 tf[4]; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Traffic Class and Flow Label */ 5518c2ecf20Sopenharmony_ci switch (val) { 5528c2ecf20Sopenharmony_ci case LOWPAN_IPHC_TF_00: 5538c2ecf20Sopenharmony_ci /* ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */ 5548c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, tf, 4)) 5558c2ecf20Sopenharmony_ci return -EINVAL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* 1 2 3 5588c2ecf20Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 5598c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5608c2ecf20Sopenharmony_ci * |ECN| DSCP | rsv | Flow Label | 5618c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_ecn(hdr, tf); 5648c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_dscp(hdr, tf); 5658c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_lbl(hdr, &tf[1]); 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci case LOWPAN_IPHC_TF_01: 5688c2ecf20Sopenharmony_ci /* ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided. */ 5698c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, tf, 3)) 5708c2ecf20Sopenharmony_ci return -EINVAL; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* 1 2 5738c2ecf20Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 5748c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5758c2ecf20Sopenharmony_ci * |ECN|rsv| Flow Label | 5768c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_ecn(hdr, tf); 5798c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_lbl(hdr, &tf[0]); 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci case LOWPAN_IPHC_TF_10: 5828c2ecf20Sopenharmony_ci /* ECN + DSCP (1 byte), Flow Label is elided. */ 5838c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, tf, 1)) 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* 0 1 2 3 4 5 6 7 5878c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+ 5888c2ecf20Sopenharmony_ci * |ECN| DSCP | 5898c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+ 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_ecn(hdr, tf); 5928c2ecf20Sopenharmony_ci lowpan_iphc_tf_set_dscp(hdr, tf); 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case LOWPAN_IPHC_TF_11: 5958c2ecf20Sopenharmony_ci /* Traffic Class and Flow Label are elided */ 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci default: 5988c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 5998c2ecf20Sopenharmony_ci return -EINVAL; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci/* TTL uncompression values */ 6068c2ecf20Sopenharmony_cistatic const u8 lowpan_ttl_values[] = { 6078c2ecf20Sopenharmony_ci [LOWPAN_IPHC_HLIM_01] = 1, 6088c2ecf20Sopenharmony_ci [LOWPAN_IPHC_HLIM_10] = 64, 6098c2ecf20Sopenharmony_ci [LOWPAN_IPHC_HLIM_11] = 255, 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ciint lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev, 6138c2ecf20Sopenharmony_ci const void *daddr, const void *saddr) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct ipv6hdr hdr = {}; 6168c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *ci; 6178c2ecf20Sopenharmony_ci u8 iphc0, iphc1, cid = 0; 6188c2ecf20Sopenharmony_ci int err; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci raw_dump_table(__func__, "raw skb data dump uncompressed", 6218c2ecf20Sopenharmony_ci skb->data, skb->len); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, &iphc0, sizeof(iphc0)) || 6248c2ecf20Sopenharmony_ci lowpan_fetch_skb(skb, &iphc1, sizeof(iphc1))) 6258c2ecf20Sopenharmony_ci return -EINVAL; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci hdr.version = 6; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* default CID = 0, another if the CID flag is set */ 6308c2ecf20Sopenharmony_ci if (iphc1 & LOWPAN_IPHC_CID) { 6318c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, &cid, sizeof(cid))) 6328c2ecf20Sopenharmony_ci return -EINVAL; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci err = lowpan_iphc_tf_decompress(skb, &hdr, 6368c2ecf20Sopenharmony_ci iphc0 & LOWPAN_IPHC_TF_MASK); 6378c2ecf20Sopenharmony_ci if (err < 0) 6388c2ecf20Sopenharmony_ci return err; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Next Header */ 6418c2ecf20Sopenharmony_ci if (!(iphc0 & LOWPAN_IPHC_NH)) { 6428c2ecf20Sopenharmony_ci /* Next header is carried inline */ 6438c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr))) 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci pr_debug("NH flag is set, next header carried inline: %02x\n", 6478c2ecf20Sopenharmony_ci hdr.nexthdr); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Hop Limit */ 6518c2ecf20Sopenharmony_ci if ((iphc0 & LOWPAN_IPHC_HLIM_MASK) != LOWPAN_IPHC_HLIM_00) { 6528c2ecf20Sopenharmony_ci hdr.hop_limit = lowpan_ttl_values[iphc0 & LOWPAN_IPHC_HLIM_MASK]; 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci if (lowpan_fetch_skb(skb, &hdr.hop_limit, 6558c2ecf20Sopenharmony_ci sizeof(hdr.hop_limit))) 6568c2ecf20Sopenharmony_ci return -EINVAL; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (iphc1 & LOWPAN_IPHC_SAC) { 6608c2ecf20Sopenharmony_ci spin_lock_bh(&lowpan_dev(dev)->ctx.lock); 6618c2ecf20Sopenharmony_ci ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_SCI(cid)); 6628c2ecf20Sopenharmony_ci if (!ci) { 6638c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 6648c2ecf20Sopenharmony_ci return -EINVAL; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci pr_debug("SAC bit is set. Handle context based source address.\n"); 6688c2ecf20Sopenharmony_ci err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.saddr, 6698c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_SAM_MASK, 6708c2ecf20Sopenharmony_ci saddr); 6718c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 6728c2ecf20Sopenharmony_ci } else { 6738c2ecf20Sopenharmony_ci /* Source address uncompression */ 6748c2ecf20Sopenharmony_ci pr_debug("source address stateless compression\n"); 6758c2ecf20Sopenharmony_ci err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.saddr, 6768c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_SAM_MASK, 6778c2ecf20Sopenharmony_ci saddr); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* Check on error of previous branch */ 6818c2ecf20Sopenharmony_ci if (err) 6828c2ecf20Sopenharmony_ci return -EINVAL; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci switch (iphc1 & (LOWPAN_IPHC_M | LOWPAN_IPHC_DAC)) { 6858c2ecf20Sopenharmony_ci case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC: 6868c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_BROADCAST; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci spin_lock_bh(&lowpan_dev(dev)->ctx.lock); 6898c2ecf20Sopenharmony_ci ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid)); 6908c2ecf20Sopenharmony_ci if (!ci) { 6918c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 6928c2ecf20Sopenharmony_ci return -EINVAL; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* multicast with context */ 6968c2ecf20Sopenharmony_ci pr_debug("dest: context-based mcast compression\n"); 6978c2ecf20Sopenharmony_ci err = lowpan_uncompress_multicast_ctx_daddr(skb, ci, 6988c2ecf20Sopenharmony_ci &hdr.daddr, 6998c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_DAM_MASK); 7008c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci case LOWPAN_IPHC_M: 7038c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_BROADCAST; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* multicast */ 7068c2ecf20Sopenharmony_ci err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr, 7078c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_DAM_MASK); 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci case LOWPAN_IPHC_DAC: 7108c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci spin_lock_bh(&lowpan_dev(dev)->ctx.lock); 7138c2ecf20Sopenharmony_ci ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid)); 7148c2ecf20Sopenharmony_ci if (!ci) { 7158c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 7168c2ecf20Sopenharmony_ci return -EINVAL; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* Destination address context based uncompression */ 7208c2ecf20Sopenharmony_ci pr_debug("DAC bit is set. Handle context based destination address.\n"); 7218c2ecf20Sopenharmony_ci err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.daddr, 7228c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_DAM_MASK, 7238c2ecf20Sopenharmony_ci daddr); 7248c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci default: 7278c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.daddr, 7308c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_DAM_MASK, 7318c2ecf20Sopenharmony_ci daddr); 7328c2ecf20Sopenharmony_ci pr_debug("dest: stateless compression mode %d dest %pI6c\n", 7338c2ecf20Sopenharmony_ci iphc1 & LOWPAN_IPHC_DAM_MASK, &hdr.daddr); 7348c2ecf20Sopenharmony_ci break; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (err) 7388c2ecf20Sopenharmony_ci return -EINVAL; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* Next header data uncompression */ 7418c2ecf20Sopenharmony_ci if (iphc0 & LOWPAN_IPHC_NH) { 7428c2ecf20Sopenharmony_ci err = lowpan_nhc_do_uncompression(skb, dev, &hdr); 7438c2ecf20Sopenharmony_ci if (err < 0) 7448c2ecf20Sopenharmony_ci return err; 7458c2ecf20Sopenharmony_ci } else { 7468c2ecf20Sopenharmony_ci err = skb_cow(skb, sizeof(hdr)); 7478c2ecf20Sopenharmony_ci if (unlikely(err)) 7488c2ecf20Sopenharmony_ci return err; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci switch (lowpan_dev(dev)->lltype) { 7528c2ecf20Sopenharmony_ci case LOWPAN_LLTYPE_IEEE802154: 7538c2ecf20Sopenharmony_ci if (lowpan_802154_cb(skb)->d_size) 7548c2ecf20Sopenharmony_ci hdr.payload_len = htons(lowpan_802154_cb(skb)->d_size - 7558c2ecf20Sopenharmony_ci sizeof(struct ipv6hdr)); 7568c2ecf20Sopenharmony_ci else 7578c2ecf20Sopenharmony_ci hdr.payload_len = htons(skb->len); 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci default: 7608c2ecf20Sopenharmony_ci hdr.payload_len = htons(skb->len); 7618c2ecf20Sopenharmony_ci break; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci pr_debug("skb headroom size = %d, data length = %d\n", 7658c2ecf20Sopenharmony_ci skb_headroom(skb), skb->len); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" 7688c2ecf20Sopenharmony_ci "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", 7698c2ecf20Sopenharmony_ci hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, 7708c2ecf20Sopenharmony_ci hdr.hop_limit, &hdr.daddr); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci skb_push(skb, sizeof(hdr)); 7738c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 7748c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 7758c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, &hdr, sizeof(hdr)); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lowpan_header_decompress); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic const u8 lowpan_iphc_dam_to_sam_value[] = { 7848c2ecf20Sopenharmony_ci [LOWPAN_IPHC_DAM_00] = LOWPAN_IPHC_SAM_00, 7858c2ecf20Sopenharmony_ci [LOWPAN_IPHC_DAM_01] = LOWPAN_IPHC_SAM_01, 7868c2ecf20Sopenharmony_ci [LOWPAN_IPHC_DAM_10] = LOWPAN_IPHC_SAM_10, 7878c2ecf20Sopenharmony_ci [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11, 7888c2ecf20Sopenharmony_ci}; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic inline bool 7918c2ecf20Sopenharmony_cilowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr, 7928c2ecf20Sopenharmony_ci const struct lowpan_iphc_ctx *ctx, 7938c2ecf20Sopenharmony_ci const void *lladdr) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci const struct ieee802154_addr *addr = lladdr; 7968c2ecf20Sopenharmony_ci unsigned char extended_addr[EUI64_ADDR_LEN]; 7978c2ecf20Sopenharmony_ci bool lladdr_compress = false; 7988c2ecf20Sopenharmony_ci struct in6_addr tmp = {}; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci switch (addr->mode) { 8018c2ecf20Sopenharmony_ci case IEEE802154_ADDR_LONG: 8028c2ecf20Sopenharmony_ci ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr); 8038c2ecf20Sopenharmony_ci /* check for SAM/DAM = 11 */ 8048c2ecf20Sopenharmony_ci memcpy(&tmp.s6_addr[8], &extended_addr, EUI64_ADDR_LEN); 8058c2ecf20Sopenharmony_ci /* second bit-flip (Universe/Local) is done according RFC2464 */ 8068c2ecf20Sopenharmony_ci tmp.s6_addr[8] ^= 0x02; 8078c2ecf20Sopenharmony_ci /* context information are always used */ 8088c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 8098c2ecf20Sopenharmony_ci if (ipv6_addr_equal(&tmp, ipaddr)) 8108c2ecf20Sopenharmony_ci lladdr_compress = true; 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci case IEEE802154_ADDR_SHORT: 8138c2ecf20Sopenharmony_ci tmp.s6_addr[11] = 0xFF; 8148c2ecf20Sopenharmony_ci tmp.s6_addr[12] = 0xFE; 8158c2ecf20Sopenharmony_ci ieee802154_le16_to_be16(&tmp.s6_addr16[7], 8168c2ecf20Sopenharmony_ci &addr->short_addr); 8178c2ecf20Sopenharmony_ci /* context information are always used */ 8188c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 8198c2ecf20Sopenharmony_ci if (ipv6_addr_equal(&tmp, ipaddr)) 8208c2ecf20Sopenharmony_ci lladdr_compress = true; 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci default: 8238c2ecf20Sopenharmony_ci /* should never handled and filtered by 802154 6lowpan */ 8248c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 8258c2ecf20Sopenharmony_ci break; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return lladdr_compress; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic bool lowpan_iphc_addr_equal(const struct net_device *dev, 8328c2ecf20Sopenharmony_ci const struct lowpan_iphc_ctx *ctx, 8338c2ecf20Sopenharmony_ci const struct in6_addr *ipaddr, 8348c2ecf20Sopenharmony_ci const void *lladdr) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct in6_addr tmp = {}; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci lowpan_iphc_uncompress_lladdr(dev, &tmp, lladdr); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (ctx) 8418c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return ipv6_addr_equal(&tmp, ipaddr); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, 8478c2ecf20Sopenharmony_ci const struct in6_addr *ipaddr, 8488c2ecf20Sopenharmony_ci const struct lowpan_iphc_ctx *ctx, 8498c2ecf20Sopenharmony_ci const unsigned char *lladdr, bool sam) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct in6_addr tmp = {}; 8528c2ecf20Sopenharmony_ci u8 dam; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci switch (lowpan_dev(dev)->lltype) { 8558c2ecf20Sopenharmony_ci case LOWPAN_LLTYPE_IEEE802154: 8568c2ecf20Sopenharmony_ci if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx, 8578c2ecf20Sopenharmony_ci lladdr)) { 8588c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_11; 8598c2ecf20Sopenharmony_ci goto out; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci default: 8638c2ecf20Sopenharmony_ci if (lowpan_iphc_addr_equal(dev, ctx, ipaddr, lladdr)) { 8648c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_11; 8658c2ecf20Sopenharmony_ci goto out; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 8718c2ecf20Sopenharmony_ci /* check for SAM/DAM = 10 */ 8728c2ecf20Sopenharmony_ci tmp.s6_addr[11] = 0xFF; 8738c2ecf20Sopenharmony_ci tmp.s6_addr[12] = 0xFE; 8748c2ecf20Sopenharmony_ci memcpy(&tmp.s6_addr[14], &ipaddr->s6_addr[14], 2); 8758c2ecf20Sopenharmony_ci /* context information are always used */ 8768c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 8778c2ecf20Sopenharmony_ci if (ipv6_addr_equal(&tmp, ipaddr)) { 8788c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[14], 2); 8798c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_10; 8808c2ecf20Sopenharmony_ci goto out; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 8848c2ecf20Sopenharmony_ci /* check for SAM/DAM = 01, should always match */ 8858c2ecf20Sopenharmony_ci memcpy(&tmp.s6_addr[8], &ipaddr->s6_addr[8], 8); 8868c2ecf20Sopenharmony_ci /* context information are always used */ 8878c2ecf20Sopenharmony_ci ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 8888c2ecf20Sopenharmony_ci if (ipv6_addr_equal(&tmp, ipaddr)) { 8898c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[8], 8); 8908c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_01; 8918c2ecf20Sopenharmony_ci goto out; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci WARN_ONCE(1, "context found but no address mode matched\n"); 8958c2ecf20Sopenharmony_ci return LOWPAN_IPHC_DAM_00; 8968c2ecf20Sopenharmony_ciout: 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (sam) 8998c2ecf20Sopenharmony_ci return lowpan_iphc_dam_to_sam_value[dam]; 9008c2ecf20Sopenharmony_ci else 9018c2ecf20Sopenharmony_ci return dam; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic inline bool 9058c2ecf20Sopenharmony_cilowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr, 9068c2ecf20Sopenharmony_ci const void *lladdr) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci const struct ieee802154_addr *addr = lladdr; 9098c2ecf20Sopenharmony_ci unsigned char extended_addr[EUI64_ADDR_LEN]; 9108c2ecf20Sopenharmony_ci bool lladdr_compress = false; 9118c2ecf20Sopenharmony_ci struct in6_addr tmp = {}; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci switch (addr->mode) { 9148c2ecf20Sopenharmony_ci case IEEE802154_ADDR_LONG: 9158c2ecf20Sopenharmony_ci ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr); 9168c2ecf20Sopenharmony_ci if (is_addr_mac_addr_based(ipaddr, extended_addr)) 9178c2ecf20Sopenharmony_ci lladdr_compress = true; 9188c2ecf20Sopenharmony_ci break; 9198c2ecf20Sopenharmony_ci case IEEE802154_ADDR_SHORT: 9208c2ecf20Sopenharmony_ci /* fe:80::ff:fe00:XXXX 9218c2ecf20Sopenharmony_ci * \__/ 9228c2ecf20Sopenharmony_ci * short_addr 9238c2ecf20Sopenharmony_ci * 9248c2ecf20Sopenharmony_ci * Universe/Local bit is zero. 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_ci tmp.s6_addr[0] = 0xFE; 9278c2ecf20Sopenharmony_ci tmp.s6_addr[1] = 0x80; 9288c2ecf20Sopenharmony_ci tmp.s6_addr[11] = 0xFF; 9298c2ecf20Sopenharmony_ci tmp.s6_addr[12] = 0xFE; 9308c2ecf20Sopenharmony_ci ieee802154_le16_to_be16(&tmp.s6_addr16[7], 9318c2ecf20Sopenharmony_ci &addr->short_addr); 9328c2ecf20Sopenharmony_ci if (ipv6_addr_equal(&tmp, ipaddr)) 9338c2ecf20Sopenharmony_ci lladdr_compress = true; 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci default: 9368c2ecf20Sopenharmony_ci /* should never handled and filtered by 802154 6lowpan */ 9378c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 9388c2ecf20Sopenharmony_ci break; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci return lladdr_compress; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev, 9458c2ecf20Sopenharmony_ci const struct in6_addr *ipaddr, 9468c2ecf20Sopenharmony_ci const unsigned char *lladdr, bool sam) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci u8 dam = LOWPAN_IPHC_DAM_01; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci switch (lowpan_dev(dev)->lltype) { 9518c2ecf20Sopenharmony_ci case LOWPAN_LLTYPE_IEEE802154: 9528c2ecf20Sopenharmony_ci if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) { 9538c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_11; /* 0-bits */ 9548c2ecf20Sopenharmony_ci pr_debug("address compression 0 bits\n"); 9558c2ecf20Sopenharmony_ci goto out; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci break; 9588c2ecf20Sopenharmony_ci default: 9598c2ecf20Sopenharmony_ci if (lowpan_iphc_addr_equal(dev, NULL, ipaddr, lladdr)) { 9608c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_11; 9618c2ecf20Sopenharmony_ci pr_debug("address compression 0 bits\n"); 9628c2ecf20Sopenharmony_ci goto out; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (lowpan_is_iid_16_bit_compressable(ipaddr)) { 9698c2ecf20Sopenharmony_ci /* compress IID to 16 bits xxxx::XXXX */ 9708c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2); 9718c2ecf20Sopenharmony_ci dam = LOWPAN_IPHC_DAM_10; /* 16-bits */ 9728c2ecf20Sopenharmony_ci raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", 9738c2ecf20Sopenharmony_ci *hc_ptr - 2, 2); 9748c2ecf20Sopenharmony_ci goto out; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* do not compress IID => xxxx::IID */ 9788c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8); 9798c2ecf20Sopenharmony_ci raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", 9808c2ecf20Sopenharmony_ci *hc_ptr - 8, 8); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ciout: 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (sam) 9858c2ecf20Sopenharmony_ci return lowpan_iphc_dam_to_sam_value[dam]; 9868c2ecf20Sopenharmony_ci else 9878c2ecf20Sopenharmony_ci return dam; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci/* lowpan_iphc_get_tc - get the ECN + DCSP fields in hc format */ 9918c2ecf20Sopenharmony_cistatic inline u8 lowpan_iphc_get_tc(const struct ipv6hdr *hdr) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci u8 dscp, ecn; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* hdr->priority contains the higher bits of dscp, lower are part of 9968c2ecf20Sopenharmony_ci * flow_lbl[0]. Note ECN, DCSP is swapped in ipv6 hdr. 9978c2ecf20Sopenharmony_ci */ 9988c2ecf20Sopenharmony_ci dscp = (hdr->priority << 2) | ((hdr->flow_lbl[0] & 0xc0) >> 6); 9998c2ecf20Sopenharmony_ci /* ECN is at the two lower bits from first nibble of flow_lbl[0] */ 10008c2ecf20Sopenharmony_ci ecn = (hdr->flow_lbl[0] & 0x30); 10018c2ecf20Sopenharmony_ci /* for pretty debug output, also shift ecn to get the ecn value */ 10028c2ecf20Sopenharmony_ci pr_debug("ecn 0x%02x dscp 0x%02x\n", ecn >> 4, dscp); 10038c2ecf20Sopenharmony_ci /* ECN is at 0x30 now, shift it to have ECN + DCSP */ 10048c2ecf20Sopenharmony_ci return (ecn << 2) | dscp; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/* lowpan_iphc_is_flow_lbl_zero - check if flow label is zero */ 10088c2ecf20Sopenharmony_cistatic inline bool lowpan_iphc_is_flow_lbl_zero(const struct ipv6hdr *hdr) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci return ((!(hdr->flow_lbl[0] & 0x0f)) && 10118c2ecf20Sopenharmony_ci !hdr->flow_lbl[1] && !hdr->flow_lbl[2]); 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/* lowpan_iphc_tf_compress - compress the traffic class which is set by 10158c2ecf20Sopenharmony_ci * ipv6hdr. Return the corresponding format identifier which is used. 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_cistatic u8 lowpan_iphc_tf_compress(u8 **hc_ptr, const struct ipv6hdr *hdr) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci /* get ecn dscp data in a byteformat as: ECN(hi) + DSCP(lo) */ 10208c2ecf20Sopenharmony_ci u8 tc = lowpan_iphc_get_tc(hdr), tf[4], val; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* printout the traffic class in hc format */ 10238c2ecf20Sopenharmony_ci pr_debug("tc 0x%02x\n", tc); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (lowpan_iphc_is_flow_lbl_zero(hdr)) { 10268c2ecf20Sopenharmony_ci if (!tc) { 10278c2ecf20Sopenharmony_ci /* 11: Traffic Class and Flow Label are elided. */ 10288c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_TF_11; 10298c2ecf20Sopenharmony_ci } else { 10308c2ecf20Sopenharmony_ci /* 10: ECN + DSCP (1 byte), Flow Label is elided. 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * 0 1 2 3 4 5 6 7 10338c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+ 10348c2ecf20Sopenharmony_ci * |ECN| DSCP | 10358c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+ 10368c2ecf20Sopenharmony_ci */ 10378c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &tc, sizeof(tc)); 10388c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_TF_10; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci } else { 10418c2ecf20Sopenharmony_ci /* check if dscp is zero, it's after the first two bit */ 10428c2ecf20Sopenharmony_ci if (!(tc & 0x3f)) { 10438c2ecf20Sopenharmony_ci /* 01: ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided 10448c2ecf20Sopenharmony_ci * 10458c2ecf20Sopenharmony_ci * 1 2 10468c2ecf20Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 10478c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10488c2ecf20Sopenharmony_ci * |ECN|rsv| Flow Label | 10498c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10508c2ecf20Sopenharmony_ci */ 10518c2ecf20Sopenharmony_ci memcpy(&tf[0], &hdr->flow_lbl[0], 3); 10528c2ecf20Sopenharmony_ci /* zero the highest 4-bits, contains DCSP + ECN */ 10538c2ecf20Sopenharmony_ci tf[0] &= ~0xf0; 10548c2ecf20Sopenharmony_ci /* set ECN */ 10558c2ecf20Sopenharmony_ci tf[0] |= (tc & 0xc0); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, tf, 3); 10588c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_TF_01; 10598c2ecf20Sopenharmony_ci } else { 10608c2ecf20Sopenharmony_ci /* 00: ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) 10618c2ecf20Sopenharmony_ci * 10628c2ecf20Sopenharmony_ci * 1 2 3 10638c2ecf20Sopenharmony_ci * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 10648c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10658c2ecf20Sopenharmony_ci * |ECN| DSCP | rsv | Flow Label | 10668c2ecf20Sopenharmony_ci * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci memcpy(&tf[0], &tc, sizeof(tc)); 10698c2ecf20Sopenharmony_ci /* highest nibble of flow_lbl[0] is part of DSCP + ECN 10708c2ecf20Sopenharmony_ci * which will be the 4-bit pad and will be filled with 10718c2ecf20Sopenharmony_ci * zeros afterwards. 10728c2ecf20Sopenharmony_ci */ 10738c2ecf20Sopenharmony_ci memcpy(&tf[1], &hdr->flow_lbl[0], 3); 10748c2ecf20Sopenharmony_ci /* zero the 4-bit pad, which is reserved */ 10758c2ecf20Sopenharmony_ci tf[1] &= ~0xf0; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, tf, 4); 10788c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_TF_00; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci return val; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, 10868c2ecf20Sopenharmony_ci const struct lowpan_iphc_ctx *ctx, 10878c2ecf20Sopenharmony_ci const struct in6_addr *ipaddr) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci u8 data[6]; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* flags/scope, reserved (RIID) */ 10928c2ecf20Sopenharmony_ci memcpy(data, &ipaddr->s6_addr[1], 2); 10938c2ecf20Sopenharmony_ci /* group ID */ 10948c2ecf20Sopenharmony_ci memcpy(&data[1], &ipaddr->s6_addr[11], 4); 10958c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, data, 6); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci return LOWPAN_IPHC_DAM_00; 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr, 11018c2ecf20Sopenharmony_ci const struct in6_addr *ipaddr) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci u8 val; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (lowpan_is_mcast_addr_compressable8(ipaddr)) { 11068c2ecf20Sopenharmony_ci pr_debug("compressed to 1 octet\n"); 11078c2ecf20Sopenharmony_ci /* use last byte */ 11088c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[15], 1); 11098c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_DAM_11; 11108c2ecf20Sopenharmony_ci } else if (lowpan_is_mcast_addr_compressable32(ipaddr)) { 11118c2ecf20Sopenharmony_ci pr_debug("compressed to 4 octets\n"); 11128c2ecf20Sopenharmony_ci /* second byte + the last three */ 11138c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[1], 1); 11148c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[13], 3); 11158c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_DAM_10; 11168c2ecf20Sopenharmony_ci } else if (lowpan_is_mcast_addr_compressable48(ipaddr)) { 11178c2ecf20Sopenharmony_ci pr_debug("compressed to 6 octets\n"); 11188c2ecf20Sopenharmony_ci /* second byte + the last five */ 11198c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[1], 1); 11208c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[11], 5); 11218c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_DAM_01; 11228c2ecf20Sopenharmony_ci } else { 11238c2ecf20Sopenharmony_ci pr_debug("using full address\n"); 11248c2ecf20Sopenharmony_ci lowpan_push_hc_data(hc_ptr, ipaddr->s6_addr, 16); 11258c2ecf20Sopenharmony_ci val = LOWPAN_IPHC_DAM_00; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return val; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ciint lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev, 11328c2ecf20Sopenharmony_ci const void *daddr, const void *saddr) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci u8 iphc0, iphc1, *hc_ptr, cid = 0; 11358c2ecf20Sopenharmony_ci struct ipv6hdr *hdr; 11368c2ecf20Sopenharmony_ci u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {}; 11378c2ecf20Sopenharmony_ci struct lowpan_iphc_ctx *dci, *sci, dci_entry, sci_entry; 11388c2ecf20Sopenharmony_ci int ret, ipv6_daddr_type, ipv6_saddr_type; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (skb->protocol != htons(ETH_P_IPV6)) 11418c2ecf20Sopenharmony_ci return -EINVAL; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci hdr = ipv6_hdr(skb); 11448c2ecf20Sopenharmony_ci hc_ptr = head + 2; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" 11478c2ecf20Sopenharmony_ci "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", 11488c2ecf20Sopenharmony_ci hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, 11498c2ecf20Sopenharmony_ci hdr->hop_limit, &hdr->daddr); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci raw_dump_table(__func__, "raw skb network header dump", 11528c2ecf20Sopenharmony_ci skb_network_header(skb), sizeof(struct ipv6hdr)); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* As we copy some bit-length fields, in the IPHC encoding bytes, 11558c2ecf20Sopenharmony_ci * we sometimes use |= 11568c2ecf20Sopenharmony_ci * If the field is 0, and the current bit value in memory is 1, 11578c2ecf20Sopenharmony_ci * this does not work. We therefore reset the IPHC encoding here 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci iphc0 = LOWPAN_DISPATCH_IPHC; 11608c2ecf20Sopenharmony_ci iphc1 = 0; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci raw_dump_table(__func__, "sending raw skb network uncompressed packet", 11638c2ecf20Sopenharmony_ci skb->data, skb->len); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci ipv6_daddr_type = ipv6_addr_type(&hdr->daddr); 11668c2ecf20Sopenharmony_ci spin_lock_bh(&lowpan_dev(dev)->ctx.lock); 11678c2ecf20Sopenharmony_ci if (ipv6_daddr_type & IPV6_ADDR_MULTICAST) 11688c2ecf20Sopenharmony_ci dci = lowpan_iphc_ctx_get_by_mcast_addr(dev, &hdr->daddr); 11698c2ecf20Sopenharmony_ci else 11708c2ecf20Sopenharmony_ci dci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->daddr); 11718c2ecf20Sopenharmony_ci if (dci) { 11728c2ecf20Sopenharmony_ci memcpy(&dci_entry, dci, sizeof(*dci)); 11738c2ecf20Sopenharmony_ci cid |= dci->id; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci spin_lock_bh(&lowpan_dev(dev)->ctx.lock); 11788c2ecf20Sopenharmony_ci sci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->saddr); 11798c2ecf20Sopenharmony_ci if (sci) { 11808c2ecf20Sopenharmony_ci memcpy(&sci_entry, sci, sizeof(*sci)); 11818c2ecf20Sopenharmony_ci cid |= (sci->id << 4); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* if cid is zero it will be compressed */ 11868c2ecf20Sopenharmony_ci if (cid) { 11878c2ecf20Sopenharmony_ci iphc1 |= LOWPAN_IPHC_CID; 11888c2ecf20Sopenharmony_ci lowpan_push_hc_data(&hc_ptr, &cid, sizeof(cid)); 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* Traffic Class, Flow Label compression */ 11928c2ecf20Sopenharmony_ci iphc0 |= lowpan_iphc_tf_compress(&hc_ptr, hdr); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* NOTE: payload length is always compressed */ 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Check if we provide the nhc format for nexthdr and compression 11978c2ecf20Sopenharmony_ci * functionality. If not nexthdr is handled inline and not compressed. 11988c2ecf20Sopenharmony_ci */ 11998c2ecf20Sopenharmony_ci ret = lowpan_nhc_check_compression(skb, hdr, &hc_ptr); 12008c2ecf20Sopenharmony_ci if (ret == -ENOENT) 12018c2ecf20Sopenharmony_ci lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, 12028c2ecf20Sopenharmony_ci sizeof(hdr->nexthdr)); 12038c2ecf20Sopenharmony_ci else 12048c2ecf20Sopenharmony_ci iphc0 |= LOWPAN_IPHC_NH; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* Hop limit 12078c2ecf20Sopenharmony_ci * if 1: compress, encoding is 01 12088c2ecf20Sopenharmony_ci * if 64: compress, encoding is 10 12098c2ecf20Sopenharmony_ci * if 255: compress, encoding is 11 12108c2ecf20Sopenharmony_ci * else do not compress 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_ci switch (hdr->hop_limit) { 12138c2ecf20Sopenharmony_ci case 1: 12148c2ecf20Sopenharmony_ci iphc0 |= LOWPAN_IPHC_HLIM_01; 12158c2ecf20Sopenharmony_ci break; 12168c2ecf20Sopenharmony_ci case 64: 12178c2ecf20Sopenharmony_ci iphc0 |= LOWPAN_IPHC_HLIM_10; 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci case 255: 12208c2ecf20Sopenharmony_ci iphc0 |= LOWPAN_IPHC_HLIM_11; 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci default: 12238c2ecf20Sopenharmony_ci lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit, 12248c2ecf20Sopenharmony_ci sizeof(hdr->hop_limit)); 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci ipv6_saddr_type = ipv6_addr_type(&hdr->saddr); 12288c2ecf20Sopenharmony_ci /* source address compression */ 12298c2ecf20Sopenharmony_ci if (ipv6_saddr_type == IPV6_ADDR_ANY) { 12308c2ecf20Sopenharmony_ci pr_debug("source address is unspecified, setting SAC\n"); 12318c2ecf20Sopenharmony_ci iphc1 |= LOWPAN_IPHC_SAC; 12328c2ecf20Sopenharmony_ci } else { 12338c2ecf20Sopenharmony_ci if (sci) { 12348c2ecf20Sopenharmony_ci iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev, 12358c2ecf20Sopenharmony_ci &hdr->saddr, 12368c2ecf20Sopenharmony_ci &sci_entry, saddr, 12378c2ecf20Sopenharmony_ci true); 12388c2ecf20Sopenharmony_ci iphc1 |= LOWPAN_IPHC_SAC; 12398c2ecf20Sopenharmony_ci } else { 12408c2ecf20Sopenharmony_ci if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL && 12418c2ecf20Sopenharmony_ci lowpan_is_linklocal_zero_padded(hdr->saddr)) { 12428c2ecf20Sopenharmony_ci iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev, 12438c2ecf20Sopenharmony_ci &hdr->saddr, 12448c2ecf20Sopenharmony_ci saddr, true); 12458c2ecf20Sopenharmony_ci pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n", 12468c2ecf20Sopenharmony_ci &hdr->saddr, iphc1); 12478c2ecf20Sopenharmony_ci } else { 12488c2ecf20Sopenharmony_ci pr_debug("send the full source address\n"); 12498c2ecf20Sopenharmony_ci lowpan_push_hc_data(&hc_ptr, 12508c2ecf20Sopenharmony_ci hdr->saddr.s6_addr, 16); 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* destination address compression */ 12568c2ecf20Sopenharmony_ci if (ipv6_daddr_type & IPV6_ADDR_MULTICAST) { 12578c2ecf20Sopenharmony_ci pr_debug("destination address is multicast: "); 12588c2ecf20Sopenharmony_ci iphc1 |= LOWPAN_IPHC_M; 12598c2ecf20Sopenharmony_ci if (dci) { 12608c2ecf20Sopenharmony_ci iphc1 |= lowpan_iphc_mcast_ctx_addr_compress(&hc_ptr, 12618c2ecf20Sopenharmony_ci &dci_entry, 12628c2ecf20Sopenharmony_ci &hdr->daddr); 12638c2ecf20Sopenharmony_ci iphc1 |= LOWPAN_IPHC_DAC; 12648c2ecf20Sopenharmony_ci } else { 12658c2ecf20Sopenharmony_ci iphc1 |= lowpan_iphc_mcast_addr_compress(&hc_ptr, 12668c2ecf20Sopenharmony_ci &hdr->daddr); 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } else { 12698c2ecf20Sopenharmony_ci if (dci) { 12708c2ecf20Sopenharmony_ci iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev, 12718c2ecf20Sopenharmony_ci &hdr->daddr, 12728c2ecf20Sopenharmony_ci &dci_entry, daddr, 12738c2ecf20Sopenharmony_ci false); 12748c2ecf20Sopenharmony_ci iphc1 |= LOWPAN_IPHC_DAC; 12758c2ecf20Sopenharmony_ci } else { 12768c2ecf20Sopenharmony_ci if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL && 12778c2ecf20Sopenharmony_ci lowpan_is_linklocal_zero_padded(hdr->daddr)) { 12788c2ecf20Sopenharmony_ci iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev, 12798c2ecf20Sopenharmony_ci &hdr->daddr, 12808c2ecf20Sopenharmony_ci daddr, false); 12818c2ecf20Sopenharmony_ci pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n", 12828c2ecf20Sopenharmony_ci &hdr->daddr, iphc1); 12838c2ecf20Sopenharmony_ci } else { 12848c2ecf20Sopenharmony_ci pr_debug("dest address unicast %pI6c\n", 12858c2ecf20Sopenharmony_ci &hdr->daddr); 12868c2ecf20Sopenharmony_ci lowpan_push_hc_data(&hc_ptr, 12878c2ecf20Sopenharmony_ci hdr->daddr.s6_addr, 16); 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* next header compression */ 12938c2ecf20Sopenharmony_ci if (iphc0 & LOWPAN_IPHC_NH) { 12948c2ecf20Sopenharmony_ci ret = lowpan_nhc_do_compression(skb, hdr, &hc_ptr); 12958c2ecf20Sopenharmony_ci if (ret < 0) 12968c2ecf20Sopenharmony_ci return ret; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci head[0] = iphc0; 13008c2ecf20Sopenharmony_ci head[1] = iphc1; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct ipv6hdr)); 13038c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 13048c2ecf20Sopenharmony_ci memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head); 13058c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci pr_debug("header len %d skb %u\n", (int)(hc_ptr - head), skb->len); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci raw_dump_table(__func__, "raw skb data dump compressed", 13108c2ecf20Sopenharmony_ci skb->data, skb->len); 13118c2ecf20Sopenharmony_ci return 0; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lowpan_header_compress); 1314