/* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/if_arp.h>

#include <net/6lowpan.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>

#include "6lowpan_i.h"

#define LOWPAN_DISPATCH_FIRST		0xc0
#define LOWPAN_DISPATCH_FRAG_MASK	0xf8

#define LOWPAN_DISPATCH_NALP		0x00
#define LOWPAN_DISPATCH_ESC		0x40
#define LOWPAN_DISPATCH_HC1		0x42
#define LOWPAN_DISPATCH_DFF		0x43
#define LOWPAN_DISPATCH_BC0		0x50
#define LOWPAN_DISPATCH_MESH		0x80

static int lowpan_give_skb_to_device(struct sk_buff *skb)
{
	skb->protocol = htons(ETH_P_IPV6);
	skb->dev->stats.rx_packets++;
	skb->dev->stats.rx_bytes += skb->len;

	return netif_rx(skb);
}

static int lowpan_rx_handlers_result(struct sk_buff *skb, lowpan_rx_result res)
{
	switch (res) {
	case RX_CONTINUE:
		/* nobody cared about this packet */
		net_warn_ratelimited("%s: received unknown dispatch\n",
				     __func__);

		/* fall-through */
	case RX_DROP_UNUSABLE:
		kfree_skb(skb);

		/* fall-through */
	case RX_DROP:
		return NET_RX_DROP;
	case RX_QUEUED:
		return lowpan_give_skb_to_device(skb);
	default:
		break;
	}

	return NET_RX_DROP;
}

static inline bool lowpan_is_frag1(u8 dispatch)
{
	return (dispatch & LOWPAN_DISPATCH_FRAG_MASK) == LOWPAN_DISPATCH_FRAG1;
}

static inline bool lowpan_is_fragn(u8 dispatch)
{
	return (dispatch & LOWPAN_DISPATCH_FRAG_MASK) == LOWPAN_DISPATCH_FRAGN;
}

static lowpan_rx_result lowpan_rx_h_frag(struct sk_buff *skb)
{
	int ret;

	if (!(lowpan_is_frag1(*skb_network_header(skb)) ||
	      lowpan_is_fragn(*skb_network_header(skb))))
		return RX_CONTINUE;

	ret = lowpan_frag_rcv(skb, *skb_network_header(skb) &
			      LOWPAN_DISPATCH_FRAG_MASK);
	if (ret == 1)
		return RX_QUEUED;

	/* Packet is freed by lowpan_frag_rcv on error or put into the frag
	 * bucket.
	 */
	return RX_DROP;
}

int lowpan_iphc_decompress(struct sk_buff *skb)
{
	struct ieee802154_hdr hdr;

	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
		return -EINVAL;

	return lowpan_header_decompress(skb, skb->dev, &hdr.dest, &hdr.source);
}

static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)
{
	int ret;

	if (!lowpan_is_iphc(*skb_network_header(skb)))
		return RX_CONTINUE;

	/* Setting datagram_offset to zero indicates non frag handling
	 * while doing lowpan_header_decompress.
	 */
	lowpan_802154_cb(skb)->d_size = 0;

	ret = lowpan_iphc_decompress(skb);
	if (ret < 0)
		return RX_DROP_UNUSABLE;

	return RX_QUEUED;
}

lowpan_rx_result lowpan_rx_h_ipv6(struct sk_buff *skb)
{
	if (!lowpan_is_ipv6(*skb_network_header(skb)))
		return RX_CONTINUE;

	/* Pull off the 1-byte of 6lowpan header. */
	skb_pull(skb, 1);
	return RX_QUEUED;
}

static inline bool lowpan_is_esc(u8 dispatch)
{
	return dispatch == LOWPAN_DISPATCH_ESC;
}

static lowpan_rx_result lowpan_rx_h_esc(struct sk_buff *skb)
{
	if (!lowpan_is_esc(*skb_network_header(skb)))
		return RX_CONTINUE;

	net_warn_ratelimited("%s: %s\n", skb->dev->name,
			     "6LoWPAN ESC not supported\n");

	return RX_DROP_UNUSABLE;
}

static inline bool lowpan_is_hc1(u8 dispatch)
{
	return dispatch == LOWPAN_DISPATCH_HC1;
}

static lowpan_rx_result lowpan_rx_h_hc1(struct sk_buff *skb)
{
	if (!lowpan_is_hc1(*skb_network_header(skb)))
		return RX_CONTINUE;

	net_warn_ratelimited("%s: %s\n", skb->dev->name,
			     "6LoWPAN HC1 not supported\n");

	return RX_DROP_UNUSABLE;
}

static inline bool lowpan_is_dff(u8 dispatch)
{
	return dispatch == LOWPAN_DISPATCH_DFF;
}

static lowpan_rx_result lowpan_rx_h_dff(struct sk_buff *skb)
{
	if (!lowpan_is_dff(*skb_network_header(skb)))
		return RX_CONTINUE;

	net_warn_ratelimited("%s: %s\n", skb->dev->name,
			     "6LoWPAN DFF not supported\n");

	return RX_DROP_UNUSABLE;
}

static inline bool lowpan_is_bc0(u8 dispatch)
{
	return dispatch == LOWPAN_DISPATCH_BC0;
}

static lowpan_rx_result lowpan_rx_h_bc0(struct sk_buff *skb)
{
	if (!lowpan_is_bc0(*skb_network_header(skb)))
		return RX_CONTINUE;

	net_warn_ratelimited("%s: %s\n", skb->dev->name,
			     "6LoWPAN BC0 not supported\n");

	return RX_DROP_UNUSABLE;
}

static inline bool lowpan_is_mesh(u8 dispatch)
{
	return (dispatch & LOWPAN_DISPATCH_FIRST) == LOWPAN_DISPATCH_MESH;
}

static lowpan_rx_result lowpan_rx_h_mesh(struct sk_buff *skb)
{
	if (!lowpan_is_mesh(*skb_network_header(skb)))
		return RX_CONTINUE;

	net_warn_ratelimited("%s: %s\n", skb->dev->name,
			     "6LoWPAN MESH not supported\n");

	return RX_DROP_UNUSABLE;
}

static int lowpan_invoke_rx_handlers(struct sk_buff *skb)
{
	lowpan_rx_result res;

#define CALL_RXH(rxh)			\
	do {				\
		res = rxh(skb);	\
		if (res != RX_CONTINUE)	\
			goto rxh_next;	\
	} while (0)

	/* likely at first */
	CALL_RXH(lowpan_rx_h_iphc);
	CALL_RXH(lowpan_rx_h_frag);
	CALL_RXH(lowpan_rx_h_ipv6);
	CALL_RXH(lowpan_rx_h_esc);
	CALL_RXH(lowpan_rx_h_hc1);
	CALL_RXH(lowpan_rx_h_dff);
	CALL_RXH(lowpan_rx_h_bc0);
	CALL_RXH(lowpan_rx_h_mesh);

rxh_next:
	return lowpan_rx_handlers_result(skb, res);
#undef CALL_RXH
}

static inline bool lowpan_is_nalp(u8 dispatch)
{
	return (dispatch & LOWPAN_DISPATCH_FIRST) == LOWPAN_DISPATCH_NALP;
}

/* Lookup for reserved dispatch values at:
 * https://www.iana.org/assignments/_6lowpan-parameters/_6lowpan-parameters.xhtml#_6lowpan-parameters-1
 *
 * Last Updated: 2015-01-22
 */
static inline bool lowpan_is_reserved(u8 dispatch)
{
	return ((dispatch >= 0x44 && dispatch <= 0x4F) ||
		(dispatch >= 0x51 && dispatch <= 0x5F) ||
		(dispatch >= 0xc8 && dispatch <= 0xdf) ||
		(dispatch >= 0xe8 && dispatch <= 0xff));
}

/* lowpan_rx_h_check checks on generic 6LoWPAN requirements
 * in MAC and 6LoWPAN header.
 *
 * Don't manipulate the skb here, it could be shared buffer.
 */
static inline bool lowpan_rx_h_check(struct sk_buff *skb)
{
	__le16 fc = ieee802154_get_fc_from_skb(skb);

	/* check on ieee802154 conform 6LoWPAN header */
	if (!ieee802154_is_data(fc) ||
	    !ieee802154_skb_is_intra_pan_addressing(fc, skb))
		return false;

	/* check if we can dereference the dispatch */
	if (unlikely(!skb->len))
		return false;

	if (lowpan_is_nalp(*skb_network_header(skb)) ||
	    lowpan_is_reserved(*skb_network_header(skb)))
		return false;

	return true;
}

static int lowpan_rcv(struct sk_buff *skb, struct net_device *wdev,
		      struct packet_type *pt, struct net_device *orig_wdev)
{
	struct net_device *ldev;

	if (wdev->type != ARPHRD_IEEE802154 ||
	    skb->pkt_type == PACKET_OTHERHOST ||
	    !lowpan_rx_h_check(skb))
		goto drop;

	ldev = wdev->ieee802154_ptr->lowpan_dev;
	if (!ldev || !netif_running(ldev))
		goto drop;

	/* Replacing skb->dev and followed rx handlers will manipulate skb. */
	skb = skb_share_check(skb, GFP_ATOMIC);
	if (!skb)
		goto out;
	skb->dev = ldev;

	/* When receive frag1 it's likely that we manipulate the buffer.
	 * When recevie iphc we manipulate the data buffer. So we need
	 * to unshare the buffer.
	 */
	if (lowpan_is_frag1(*skb_network_header(skb)) ||
	    lowpan_is_iphc(*skb_network_header(skb))) {
		skb = skb_unshare(skb, GFP_ATOMIC);
		if (!skb)
			goto out;
	}

	return lowpan_invoke_rx_handlers(skb);

drop:
	kfree_skb(skb);
out:
	return NET_RX_DROP;
}

static struct packet_type lowpan_packet_type = {
	.type = htons(ETH_P_IEEE802154),
	.func = lowpan_rcv,
};

void lowpan_rx_init(void)
{
	dev_add_pack(&lowpan_packet_type);
}

void lowpan_rx_exit(void)
{
	dev_remove_pack(&lowpan_packet_type);
}
