/*
 * Reproducer for 182-warning-in-lowpan-compress-addr-64
 */
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <linux/rtnetlink.h>

int main(void)
{
	struct { struct nlmsghdr n; struct ifinfomsg i; char buf[128]; } req;
	struct rtattr *a, *li;
	struct sockaddr_ll sll;
	struct ifreq ifr;
	unsigned char pkt[40];
	int idx = if_nametoindex("wpan0");
	int s;
	char *p;

	/* 1. RTM_NEWLINK: lowpan0, kind "lowpan", IFLA_LINK = wpan0 */
	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
	req.n.nlmsg_type = RTM_NEWLINK;
	p = (char *)&req + NLMSG_ALIGN(req.n.nlmsg_len);

	a = (struct rtattr *)p;
	a->rta_type = IFLA_LINK;
	a->rta_len = RTA_LENGTH(4);
	memcpy(RTA_DATA(a), &idx, 4);
	p += RTA_ALIGN(a->rta_len);
	req.n.nlmsg_len += RTA_ALIGN(a->rta_len);

	a = (struct rtattr *)p;
	a->rta_type = IFLA_IFNAME;
	a->rta_len = RTA_LENGTH(8);
	memcpy(RTA_DATA(a), "lowpan0", 8);
	p += RTA_ALIGN(a->rta_len);
	req.n.nlmsg_len += RTA_ALIGN(a->rta_len);

	li = (struct rtattr *)p;
	li->rta_type = IFLA_LINKINFO;
	p += RTA_LENGTH(0);
	a = (struct rtattr *)p;
	a->rta_type = IFLA_INFO_KIND;
	a->rta_len = RTA_LENGTH(7);
	memcpy(RTA_DATA(a), "lowpan", 7);
	p += RTA_ALIGN(a->rta_len);
	li->rta_len = p - (char *)li;
	req.n.nlmsg_len += RTA_ALIGN(li->rta_len);

	s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	send(s, &req, req.n.nlmsg_len, 0);
	close(s);

	/* 2. bring wpan0 and lowpan0 up */
	s = socket(AF_INET, SOCK_DGRAM, 0);
	memset(&ifr, 0, sizeof(ifr));
	ifr.ifr_flags = IFF_UP;
	strcpy(ifr.ifr_name, "lowpan0");
	ioctl(s, SIOCSIFFLAGS, &ifr);
	close(s);

	/* 3. raw IPv6 packet with a zero-padded link-local source address: that
	 *    is what steers lowpan_header_compress() into the 64-bit compressor. */
	memset(pkt, 0, sizeof(pkt));
	pkt[0] = 0x60;		/* version 6 */
	pkt[8] = 0xfe;		/* saddr fe80:: */
	pkt[9] = 0x80;

	memset(&sll, 0, sizeof(sll));
	sll.sll_family = AF_PACKET;
	sll.sll_protocol = htons(ETH_P_IPV6);
	sll.sll_ifindex = if_nametoindex("lowpan0");

	s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IPV6));
	sendto(s, pkt, sizeof(pkt), 0, (struct sockaddr *)&sll, sizeof(sll));
	return 0;
}
