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