/*1* Copyright 2011, Siemens AG2* written by Alexander Smirnov <[email protected]>3*/45/*6* Based on patches from Jon Smirl <[email protected]>7* Copyright (c) 2011 Jon Smirl <[email protected]>8*9* This program is free software; you can redistribute it and/or modify10* it under the terms of the GNU General Public License version 211* as published by the Free Software Foundation.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License along19* with this program; if not, write to the Free Software Foundation, Inc.,20* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.21*/2223/* Jon's code is based on 6lowpan implementation for Contiki which is:24* Copyright (c) 2008, Swedish Institute of Computer Science.25* All rights reserved.26*27* Redistribution and use in source and binary forms, with or without28* modification, are permitted provided that the following conditions29* are met:30* 1. Redistributions of source code must retain the above copyright31* notice, this list of conditions and the following disclaimer.32* 2. Redistributions in binary form must reproduce the above copyright33* notice, this list of conditions and the following disclaimer in the34* documentation and/or other materials provided with the distribution.35* 3. Neither the name of the Institute nor the names of its contributors36* may be used to endorse or promote products derived from this software37* without specific prior written permission.38*39* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND40* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE41* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE42* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE43* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL44* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS45* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)46* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT47* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY48* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF49* SUCH DAMAGE.50*/5152#ifndef __6LOWPAN_H__53#define __6LOWPAN_H__5455#include <linux/debugfs.h>5657#include <net/ipv6.h>58#include <net/net_namespace.h>5960/* special link-layer handling */61#include <net/mac802154.h>6263#define EUI64_ADDR_LEN 86465#define LOWPAN_NHC_MAX_ID_LEN 166/* Maximum next header compression length which we currently support inclusive67* possible inline data.68*/69#define LOWPAN_NHC_MAX_HDR_LEN (sizeof(struct udphdr))70/* Max IPHC Header len without IPv6 hdr specific inline data.71* Useful for getting the "extra" bytes we need at worst case compression.72*73* LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN74*/75#define LOWPAN_IPHC_MAX_HEADER_LEN (2 + 1 + LOWPAN_NHC_MAX_ID_LEN)76/* Maximum worst case IPHC header buffer size */77#define LOWPAN_IPHC_MAX_HC_BUF_LEN (sizeof(struct ipv6hdr) + \78LOWPAN_IPHC_MAX_HEADER_LEN + \79LOWPAN_NHC_MAX_HDR_LEN)80/* SCI/DCI is 4 bit width, so we have maximum 16 entries */81#define LOWPAN_IPHC_CTX_TABLE_SIZE (1 << 4)8283#define LOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */84#define LOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */85#define LOWPAN_DISPATCH_IPHC_MASK 0xe08687static inline bool lowpan_is_ipv6(u8 dispatch)88{89return dispatch == LOWPAN_DISPATCH_IPV6;90}9192static inline bool lowpan_is_iphc(u8 dispatch)93{94return (dispatch & LOWPAN_DISPATCH_IPHC_MASK) == LOWPAN_DISPATCH_IPHC;95}9697#define LOWPAN_PRIV_SIZE(llpriv_size) \98(sizeof(struct lowpan_dev) + llpriv_size)99100enum lowpan_lltypes {101LOWPAN_LLTYPE_BTLE,102LOWPAN_LLTYPE_IEEE802154,103};104105enum lowpan_iphc_ctx_flags {106LOWPAN_IPHC_CTX_FLAG_ACTIVE,107LOWPAN_IPHC_CTX_FLAG_COMPRESSION,108};109110struct lowpan_iphc_ctx {111u8 id;112struct in6_addr pfx;113u8 plen;114unsigned long flags;115};116117struct lowpan_iphc_ctx_table {118spinlock_t lock;119const struct lowpan_iphc_ctx_ops *ops;120struct lowpan_iphc_ctx table[LOWPAN_IPHC_CTX_TABLE_SIZE];121};122123static inline bool lowpan_iphc_ctx_is_active(const struct lowpan_iphc_ctx *ctx)124{125return test_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);126}127128static inline bool129lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx)130{131return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);132}133134struct lowpan_dev {135enum lowpan_lltypes lltype;136struct dentry *iface_debugfs;137struct lowpan_iphc_ctx_table ctx;138139/* must be last */140u8 priv[] __aligned(sizeof(void *));141};142143struct lowpan_802154_neigh {144__le16 short_addr;145};146147static inline148struct lowpan_802154_neigh *lowpan_802154_neigh(void *neigh_priv)149{150return neigh_priv;151}152153static inline154struct lowpan_dev *lowpan_dev(const struct net_device *dev)155{156return netdev_priv(dev);157}158159/* private device info */160struct lowpan_802154_dev {161struct net_device *wdev; /* wpan device ptr */162u16 fragment_tag;163};164165static inline struct166lowpan_802154_dev *lowpan_802154_dev(const struct net_device *dev)167{168return (struct lowpan_802154_dev *)lowpan_dev(dev)->priv;169}170171struct lowpan_802154_cb {172u16 d_tag;173unsigned int d_size;174u8 d_offset;175};176177static inline178struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb)179{180BUILD_BUG_ON(sizeof(struct lowpan_802154_cb) > sizeof(skb->cb));181return (struct lowpan_802154_cb *)skb->cb;182}183184static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,185const void *lladdr)186{187/* fe:80::XXXX:XXXX:XXXX:XXXX188* \_________________/189* hwaddr190*/191ipaddr->s6_addr[0] = 0xFE;192ipaddr->s6_addr[1] = 0x80;193memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);194/* second bit-flip (Universe/Local)195* is done according RFC2464196*/197ipaddr->s6_addr[8] ^= 0x02;198}199200static inline void lowpan_iphc_uncompress_eui48_lladdr(struct in6_addr *ipaddr,201const void *lladdr)202{203/* fe:80::XXXX:XXff:feXX:XXXX204* \_________________/205* hwaddr206*/207ipaddr->s6_addr[0] = 0xFE;208ipaddr->s6_addr[1] = 0x80;209memcpy(&ipaddr->s6_addr[8], lladdr, 3);210ipaddr->s6_addr[11] = 0xFF;211ipaddr->s6_addr[12] = 0xFE;212memcpy(&ipaddr->s6_addr[13], lladdr + 3, 3);213}214215#ifdef DEBUG216/* print data in line */217static inline void raw_dump_inline(const char *caller, char *msg,218const unsigned char *buf, int len)219{220if (msg)221pr_debug("%s():%s: ", caller, msg);222223print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);224}225226/* print data in a table format:227*228* addr: xx xx xx xx xx xx229* addr: xx xx xx xx xx xx230* ...231*/232static inline void raw_dump_table(const char *caller, char *msg,233const unsigned char *buf, int len)234{235if (msg)236pr_debug("%s():%s:\n", caller, msg);237238print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);239}240#else241static inline void raw_dump_table(const char *caller, char *msg,242const unsigned char *buf, int len) { }243static inline void raw_dump_inline(const char *caller, char *msg,244const unsigned char *buf, int len) { }245#endif246247/**248* lowpan_fetch_skb - getting inline data from 6LoWPAN header249*250* This function will pull data from sk buffer and put it into data to251* remove the 6LoWPAN inline data. This function returns true if the252* sk buffer is too small to pull the amount of data which is specified253* by len.254*255* @skb: the buffer where the inline data should be pulled from.256* @data: destination buffer for the inline data.257* @len: amount of data which should be pulled in bytes.258*/259static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data,260unsigned int len)261{262if (unlikely(!pskb_may_pull(skb, len)))263return true;264265skb_copy_from_linear_data(skb, data, len);266skb_pull(skb, len);267268return false;269}270271static inline bool lowpan_802154_is_valid_src_short_addr(__le16 addr)272{273/* First bit of addr is multicast, reserved or 802.15.4 specific */274return !(addr & cpu_to_le16(0x8000));275}276277static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,278const size_t len)279{280memcpy(*hc_ptr, data, len);281*hc_ptr += len;282}283284int lowpan_register_netdevice(struct net_device *dev,285enum lowpan_lltypes lltype);286int lowpan_register_netdev(struct net_device *dev,287enum lowpan_lltypes lltype);288void lowpan_unregister_netdevice(struct net_device *dev);289void lowpan_unregister_netdev(struct net_device *dev);290291/**292* lowpan_header_decompress - replace 6LoWPAN header with IPv6 header293*294* This function replaces the IPHC 6LoWPAN header which should be pointed at295* skb->data and skb_network_header, with the IPv6 header.296* It would be nice that the caller have the necessary headroom of IPv6 header297* and greatest Transport layer header, this would reduce the overhead for298* reallocate headroom.299*300* @skb: the buffer which should be manipulate.301* @dev: the lowpan net device pointer.302* @daddr: destination lladdr of mac header which is used for compression303* methods.304* @saddr: source lladdr of mac header which is used for compression305* methods.306*/307int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,308const void *daddr, const void *saddr);309310/**311* lowpan_header_compress - replace IPv6 header with 6LoWPAN header312*313* This function replaces the IPv6 header which should be pointed at314* skb->data and skb_network_header, with the IPHC 6LoWPAN header.315* The caller need to be sure that the sk buffer is not shared and at have316* at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN,317* which is the IPHC "more bytes than IPv6 header" at worst case.318*319* @skb: the buffer which should be manipulate.320* @dev: the lowpan net device pointer.321* @daddr: destination lladdr of mac header which is used for compression322* methods.323* @saddr: source lladdr of mac header which is used for compression324* methods.325*/326int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,327const void *daddr, const void *saddr);328329#endif /* __6LOWPAN_H__ */330331332