162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2011, Siemens AG 362306a36Sopenharmony_ci * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* 762306a36Sopenharmony_ci * Based on patches from Jon Smirl <jonsmirl@gmail.com> 862306a36Sopenharmony_ci * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1162306a36Sopenharmony_ci * it under the terms of the GNU General Public License version 2 1262306a36Sopenharmony_ci * as published by the Free Software Foundation. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, 1562306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1762306a36Sopenharmony_ci * GNU General Public License for more details. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License along 2062306a36Sopenharmony_ci * with this program; if not, write to the Free Software Foundation, Inc., 2162306a36Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Jon's code is based on 6lowpan implementation for Contiki which is: 2562306a36Sopenharmony_ci * Copyright (c) 2008, Swedish Institute of Computer Science. 2662306a36Sopenharmony_ci * All rights reserved. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 2962306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 3062306a36Sopenharmony_ci * are met: 3162306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 3262306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 3362306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 3462306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 3562306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 3662306a36Sopenharmony_ci * 3. Neither the name of the Institute nor the names of its contributors 3762306a36Sopenharmony_ci * may be used to endorse or promote products derived from this software 3862306a36Sopenharmony_ci * without specific prior written permission. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 4162306a36Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4262306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4362306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 4462306a36Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4562306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4662306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4762306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4862306a36Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4962306a36Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5062306a36Sopenharmony_ci * SUCH DAMAGE. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#ifndef __6LOWPAN_H__ 5462306a36Sopenharmony_ci#define __6LOWPAN_H__ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <linux/debugfs.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include <net/ipv6.h> 5962306a36Sopenharmony_ci#include <net/net_namespace.h> 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* special link-layer handling */ 6262306a36Sopenharmony_ci#include <net/mac802154.h> 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define EUI64_ADDR_LEN 8 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define LOWPAN_NHC_MAX_ID_LEN 1 6762306a36Sopenharmony_ci/* Maximum next header compression length which we currently support inclusive 6862306a36Sopenharmony_ci * possible inline data. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci#define LOWPAN_NHC_MAX_HDR_LEN (sizeof(struct udphdr)) 7162306a36Sopenharmony_ci/* Max IPHC Header len without IPv6 hdr specific inline data. 7262306a36Sopenharmony_ci * Useful for getting the "extra" bytes we need at worst case compression. 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci#define LOWPAN_IPHC_MAX_HEADER_LEN (2 + 1 + LOWPAN_NHC_MAX_ID_LEN) 7762306a36Sopenharmony_ci/* Maximum worst case IPHC header buffer size */ 7862306a36Sopenharmony_ci#define LOWPAN_IPHC_MAX_HC_BUF_LEN (sizeof(struct ipv6hdr) + \ 7962306a36Sopenharmony_ci LOWPAN_IPHC_MAX_HEADER_LEN + \ 8062306a36Sopenharmony_ci LOWPAN_NHC_MAX_HDR_LEN) 8162306a36Sopenharmony_ci/* SCI/DCI is 4 bit width, so we have maximum 16 entries */ 8262306a36Sopenharmony_ci#define LOWPAN_IPHC_CTX_TABLE_SIZE (1 << 4) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define LOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */ 8562306a36Sopenharmony_ci#define LOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */ 8662306a36Sopenharmony_ci#define LOWPAN_DISPATCH_IPHC_MASK 0xe0 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic inline bool lowpan_is_ipv6(u8 dispatch) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci return dispatch == LOWPAN_DISPATCH_IPV6; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic inline bool lowpan_is_iphc(u8 dispatch) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return (dispatch & LOWPAN_DISPATCH_IPHC_MASK) == LOWPAN_DISPATCH_IPHC; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define LOWPAN_PRIV_SIZE(llpriv_size) \ 9962306a36Sopenharmony_ci (sizeof(struct lowpan_dev) + llpriv_size) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cienum lowpan_lltypes { 10262306a36Sopenharmony_ci LOWPAN_LLTYPE_BTLE, 10362306a36Sopenharmony_ci LOWPAN_LLTYPE_IEEE802154, 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cienum lowpan_iphc_ctx_flags { 10762306a36Sopenharmony_ci LOWPAN_IPHC_CTX_FLAG_ACTIVE, 10862306a36Sopenharmony_ci LOWPAN_IPHC_CTX_FLAG_COMPRESSION, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct lowpan_iphc_ctx { 11262306a36Sopenharmony_ci u8 id; 11362306a36Sopenharmony_ci struct in6_addr pfx; 11462306a36Sopenharmony_ci u8 plen; 11562306a36Sopenharmony_ci unsigned long flags; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct lowpan_iphc_ctx_table { 11962306a36Sopenharmony_ci spinlock_t lock; 12062306a36Sopenharmony_ci const struct lowpan_iphc_ctx_ops *ops; 12162306a36Sopenharmony_ci struct lowpan_iphc_ctx table[LOWPAN_IPHC_CTX_TABLE_SIZE]; 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic inline bool lowpan_iphc_ctx_is_active(const struct lowpan_iphc_ctx *ctx) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci return test_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic inline bool 13062306a36Sopenharmony_cilowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistruct lowpan_dev { 13662306a36Sopenharmony_ci enum lowpan_lltypes lltype; 13762306a36Sopenharmony_ci struct dentry *iface_debugfs; 13862306a36Sopenharmony_ci struct lowpan_iphc_ctx_table ctx; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* must be last */ 14162306a36Sopenharmony_ci u8 priv[] __aligned(sizeof(void *)); 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct lowpan_802154_neigh { 14562306a36Sopenharmony_ci __le16 short_addr; 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic inline 14962306a36Sopenharmony_cistruct lowpan_802154_neigh *lowpan_802154_neigh(void *neigh_priv) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return neigh_priv; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic inline 15562306a36Sopenharmony_cistruct lowpan_dev *lowpan_dev(const struct net_device *dev) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci return netdev_priv(dev); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* private device info */ 16162306a36Sopenharmony_cistruct lowpan_802154_dev { 16262306a36Sopenharmony_ci struct net_device *wdev; /* wpan device ptr */ 16362306a36Sopenharmony_ci u16 fragment_tag; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic inline struct 16762306a36Sopenharmony_cilowpan_802154_dev *lowpan_802154_dev(const struct net_device *dev) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci return (struct lowpan_802154_dev *)lowpan_dev(dev)->priv; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistruct lowpan_802154_cb { 17362306a36Sopenharmony_ci u16 d_tag; 17462306a36Sopenharmony_ci unsigned int d_size; 17562306a36Sopenharmony_ci u8 d_offset; 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic inline 17962306a36Sopenharmony_cistruct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct lowpan_802154_cb) > sizeof(skb->cb)); 18262306a36Sopenharmony_ci return (struct lowpan_802154_cb *)skb->cb; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr, 18662306a36Sopenharmony_ci const void *lladdr) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci /* fe:80::XXXX:XXXX:XXXX:XXXX 18962306a36Sopenharmony_ci * \_________________/ 19062306a36Sopenharmony_ci * hwaddr 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci ipaddr->s6_addr[0] = 0xFE; 19362306a36Sopenharmony_ci ipaddr->s6_addr[1] = 0x80; 19462306a36Sopenharmony_ci memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN); 19562306a36Sopenharmony_ci /* second bit-flip (Universe/Local) 19662306a36Sopenharmony_ci * is done according RFC2464 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci ipaddr->s6_addr[8] ^= 0x02; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic inline void lowpan_iphc_uncompress_eui48_lladdr(struct in6_addr *ipaddr, 20262306a36Sopenharmony_ci const void *lladdr) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci /* fe:80::XXXX:XXff:feXX:XXXX 20562306a36Sopenharmony_ci * \_________________/ 20662306a36Sopenharmony_ci * hwaddr 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci ipaddr->s6_addr[0] = 0xFE; 20962306a36Sopenharmony_ci ipaddr->s6_addr[1] = 0x80; 21062306a36Sopenharmony_ci memcpy(&ipaddr->s6_addr[8], lladdr, 3); 21162306a36Sopenharmony_ci ipaddr->s6_addr[11] = 0xFF; 21262306a36Sopenharmony_ci ipaddr->s6_addr[12] = 0xFE; 21362306a36Sopenharmony_ci memcpy(&ipaddr->s6_addr[13], lladdr + 3, 3); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci#ifdef DEBUG 21762306a36Sopenharmony_ci/* print data in line */ 21862306a36Sopenharmony_cistatic inline void raw_dump_inline(const char *caller, char *msg, 21962306a36Sopenharmony_ci const unsigned char *buf, int len) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci if (msg) 22262306a36Sopenharmony_ci pr_debug("%s():%s: ", caller, msg); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* print data in a table format: 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * addr: xx xx xx xx xx xx 23062306a36Sopenharmony_ci * addr: xx xx xx xx xx xx 23162306a36Sopenharmony_ci * ... 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic inline void raw_dump_table(const char *caller, char *msg, 23462306a36Sopenharmony_ci const unsigned char *buf, int len) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci if (msg) 23762306a36Sopenharmony_ci pr_debug("%s():%s:\n", caller, msg); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci#else 24262306a36Sopenharmony_cistatic inline void raw_dump_table(const char *caller, char *msg, 24362306a36Sopenharmony_ci const unsigned char *buf, int len) { } 24462306a36Sopenharmony_cistatic inline void raw_dump_inline(const char *caller, char *msg, 24562306a36Sopenharmony_ci const unsigned char *buf, int len) { } 24662306a36Sopenharmony_ci#endif 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/** 24962306a36Sopenharmony_ci * lowpan_fetch_skb - getting inline data from 6LoWPAN header 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * This function will pull data from sk buffer and put it into data to 25262306a36Sopenharmony_ci * remove the 6LoWPAN inline data. This function returns true if the 25362306a36Sopenharmony_ci * sk buffer is too small to pull the amount of data which is specified 25462306a36Sopenharmony_ci * by len. 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * @skb: the buffer where the inline data should be pulled from. 25762306a36Sopenharmony_ci * @data: destination buffer for the inline data. 25862306a36Sopenharmony_ci * @len: amount of data which should be pulled in bytes. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistatic inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data, 26162306a36Sopenharmony_ci unsigned int len) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, len))) 26462306a36Sopenharmony_ci return true; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci skb_copy_from_linear_data(skb, data, len); 26762306a36Sopenharmony_ci skb_pull(skb, len); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return false; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic inline bool lowpan_802154_is_valid_src_short_addr(__le16 addr) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci /* First bit of addr is multicast, reserved or 802.15.4 specific */ 27562306a36Sopenharmony_ci return !(addr & cpu_to_le16(0x8000)); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data, 27962306a36Sopenharmony_ci const size_t len) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci memcpy(*hc_ptr, data, len); 28262306a36Sopenharmony_ci *hc_ptr += len; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciint lowpan_register_netdevice(struct net_device *dev, 28662306a36Sopenharmony_ci enum lowpan_lltypes lltype); 28762306a36Sopenharmony_ciint lowpan_register_netdev(struct net_device *dev, 28862306a36Sopenharmony_ci enum lowpan_lltypes lltype); 28962306a36Sopenharmony_civoid lowpan_unregister_netdevice(struct net_device *dev); 29062306a36Sopenharmony_civoid lowpan_unregister_netdev(struct net_device *dev); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/** 29362306a36Sopenharmony_ci * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header 29462306a36Sopenharmony_ci * 29562306a36Sopenharmony_ci * This function replaces the IPHC 6LoWPAN header which should be pointed at 29662306a36Sopenharmony_ci * skb->data and skb_network_header, with the IPv6 header. 29762306a36Sopenharmony_ci * It would be nice that the caller have the necessary headroom of IPv6 header 29862306a36Sopenharmony_ci * and greatest Transport layer header, this would reduce the overhead for 29962306a36Sopenharmony_ci * reallocate headroom. 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * @skb: the buffer which should be manipulate. 30262306a36Sopenharmony_ci * @dev: the lowpan net device pointer. 30362306a36Sopenharmony_ci * @daddr: destination lladdr of mac header which is used for compression 30462306a36Sopenharmony_ci * methods. 30562306a36Sopenharmony_ci * @saddr: source lladdr of mac header which is used for compression 30662306a36Sopenharmony_ci * methods. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_ciint lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev, 30962306a36Sopenharmony_ci const void *daddr, const void *saddr); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/** 31262306a36Sopenharmony_ci * lowpan_header_compress - replace IPv6 header with 6LoWPAN header 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * This function replaces the IPv6 header which should be pointed at 31562306a36Sopenharmony_ci * skb->data and skb_network_header, with the IPHC 6LoWPAN header. 31662306a36Sopenharmony_ci * The caller need to be sure that the sk buffer is not shared and at have 31762306a36Sopenharmony_ci * at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN, 31862306a36Sopenharmony_ci * which is the IPHC "more bytes than IPv6 header" at worst case. 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * @skb: the buffer which should be manipulate. 32162306a36Sopenharmony_ci * @dev: the lowpan net device pointer. 32262306a36Sopenharmony_ci * @daddr: destination lladdr of mac header which is used for compression 32362306a36Sopenharmony_ci * methods. 32462306a36Sopenharmony_ci * @saddr: source lladdr of mac header which is used for compression 32562306a36Sopenharmony_ci * methods. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ciint lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev, 32862306a36Sopenharmony_ci const void *daddr, const void *saddr); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#endif /* __6LOWPAN_H__ */ 331