1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * link_gre.c	gre driver module
3dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
4dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		This program is free software; you can redistribute it and/or
5dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		modify it under the terms of the GNU General Public License
6dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		as published by the Free Software Foundation; either version
7dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		2 of the License, or (at your option) any later version.
8dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
9dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Authors:	Herbert Xu <herbert@gondor.apana.org.au>
10dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
11dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
12dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
13dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <string.h>
14dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <net/if.h>
15dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/types.h>
16dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/socket.h>
17dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <arpa/inet.h>
18dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
19dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <linux/ip.h>
20dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <linux/if_tunnel.h>
21dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "rt_names.h"
22dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "utils.h"
23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "ip_common.h"
24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tunnel.h"
25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void usage(void) __attribute__((noreturn));
27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void usage(void)
28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "          type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "\n");
34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "Where: NAME := STRING\n");
35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "       ADDR := { IP_ADDRESS | any }\n");
36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "       TOS  := { NUMBER | inherit }\n");
37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "       TTL  := { 1..255 | inherit }\n");
38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	exit(-1);
40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int gre_parse_opt(struct link_util *lu, int argc, char **argv,
43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			 struct nlmsghdr *n)
44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct {
46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		struct nlmsghdr n;
47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		struct ifinfomsg i;
48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		char buf[1024];
49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	} req;
50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tb[IFLA_MAX + 1];
52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u16 iflags = 0;
55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u16 oflags = 0;
56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned ikey = 0;
57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned okey = 0;
58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned saddr = 0;
59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned daddr = 0;
60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned link = 0;
61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u8 pmtudisc = 1;
62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u8 ttl = 0;
63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u8 tos = 0;
64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len;
65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		memset(&req, 0, sizeof(req));
68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		req.n.nlmsg_flags = NLM_F_REQUEST;
71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		req.n.nlmsg_type = RTM_GETLINK;
72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		req.i.ifi_family = preferred_family;
73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		req.i.ifi_index = ifi->ifi_index;
74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatget_failed:
77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr,
78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				"Failed to get existing tunnel info.\n");
79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		len = req.n.nlmsg_len;
83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		len -= NLMSG_LENGTH(sizeof(*ifi));
84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (len < 0)
85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			goto get_failed;
86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (!tb[IFLA_LINKINFO])
90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			goto get_failed;
91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (!linkinfo[IFLA_INFO_DATA])
95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			goto get_failed;
96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				    linkinfo[IFLA_INFO_DATA]);
99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_IKEY])
101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_OKEY])
104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_IFLAGS])
107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
108dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_OFLAGS])
110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_LOCAL])
113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_REMOTE])
116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_PMTUDISC])
119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			pmtudisc = *(__u8 *)RTA_DATA(
120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				greinfo[IFLA_GRE_PMTUDISC]);
121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_TTL])
123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_TOS])
126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (greinfo[IFLA_GRE_LINK])
129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (argc > 0) {
133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (!matches(*argv, "key")) {
134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			unsigned uval;
135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags |= GRE_KEY;
138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags |= GRE_KEY;
139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strchr(*argv, '.'))
140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				uval = get_addr32(*argv);
141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			else {
142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_unsigned(&uval, *argv, 0) < 0) {
143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					fprintf(stderr,
144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						"Invalid value for \"key\"\n");
145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					exit(-1);
146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				uval = htonl(uval);
148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			ikey = okey = uval;
151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "ikey")) {
152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			unsigned uval;
153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags |= GRE_KEY;
156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strchr(*argv, '.'))
157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				uval = get_addr32(*argv);
158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			else {
159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_unsigned(&uval, *argv, 0)<0) {
160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					fprintf(stderr, "invalid value of \"ikey\"\n");
161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					exit(-1);
162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				uval = htonl(uval);
164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			ikey = uval;
166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "okey")) {
167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			unsigned uval;
168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags |= GRE_KEY;
171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strchr(*argv, '.'))
172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				uval = get_addr32(*argv);
173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			else {
174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_unsigned(&uval, *argv, 0)<0) {
175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					fprintf(stderr, "invalid value of \"okey\"\n");
176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					exit(-1);
177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				uval = htonl(uval);
179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			okey = uval;
181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "seq")) {
182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags |= GRE_SEQ;
183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags |= GRE_SEQ;
184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "iseq")) {
185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags |= GRE_SEQ;
186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "oseq")) {
187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags |= GRE_SEQ;
188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "csum")) {
189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags |= GRE_CSUM;
190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags |= GRE_CSUM;
191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "icsum")) {
192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			iflags |= GRE_CSUM;
193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "ocsum")) {
194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			oflags |= GRE_CSUM;
195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "nopmtudisc")) {
196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			pmtudisc = 0;
197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "pmtudisc")) {
198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			pmtudisc = 1;
199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "remote")) {
200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strcmp(*argv, "any"))
202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				daddr = get_addr32(*argv);
203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "local")) {
204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strcmp(*argv, "any"))
206dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				saddr = get_addr32(*argv);
207dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "dev")) {
208dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
209dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			link = tnl_ioctl_get_ifindex(*argv);
210dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (link == 0)
211dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				exit(-1);
212dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "ttl") ||
213dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			   !matches(*argv, "hoplimit")) {
214dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			unsigned uval;
215dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
216dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
217dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strcmp(*argv, "inherit") != 0) {
218dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_unsigned(&uval, *argv, 0))
219dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					invarg("invalid TTL\n", *argv);
220dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (uval > 255)
221dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					invarg("TTL must be <= 255\n", *argv);
222dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				ttl = uval;
223dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
224dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (!matches(*argv, "tos") ||
225dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			   !matches(*argv, "tclass") ||
226dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			   !matches(*argv, "dsfield")) {
227dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			__u32 uval;
228dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
229dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
230dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (strcmp(*argv, "inherit") != 0) {
231dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (rtnl_dsfield_a2n(&uval, *argv))
232dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					invarg("bad TOS value", *argv);
233dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				tos = uval;
234dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			} else
235dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				tos = 1;
236dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else
237dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			usage();
238dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		argc--; argv++;
239dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
240dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
241dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (!ikey && IN_MULTICAST(ntohl(daddr))) {
242dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		ikey = daddr;
243dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		iflags |= GRE_KEY;
244dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
245dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (!okey && IN_MULTICAST(ntohl(daddr))) {
246dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		okey = daddr;
247dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		oflags |= GRE_KEY;
248dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
249dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
250dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "Broadcast tunnel requires a source address.\n");
251dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
252dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
253dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
254dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
255dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr32(n, 1024, IFLA_GRE_OKEY, okey);
256dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
257dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
258dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
259dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
260dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
261dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (link)
262dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		addattr32(n, 1024, IFLA_GRE_LINK, link);
263dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
264dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
265dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
266dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
267dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
268dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
269dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
270dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
271dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char s1[1024];
272dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char s2[64];
273dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	const char *local = "any";
274dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	const char *remote = "any";
275dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned iflags = 0;
276dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned oflags = 0;
277dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
278dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (!tb)
279dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return;
280dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
281dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_REMOTE]) {
282dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
283dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
284dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (addr)
285dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
286dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
287dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
288dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, "remote %s ", remote);
289dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
290dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_LOCAL]) {
291dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
292dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
293dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (addr)
294dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
295dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
296dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
297dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, "local %s ", local);
298dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
299dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
300dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
301dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		char *n = tnl_ioctl_get_ifname(link);
302dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
303dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (n)
304dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "dev %s ", n);
305dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		else
306dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "dev %u ", link);
307dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
308dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
309dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
310dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
311dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	else
312dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "ttl inherit ");
313dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
314dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
315dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
316dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
317dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fputs("tos ", f);
318dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (tos == 1)
319dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fputs("inherit ", f);
320dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		else
321dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "0x%x ", tos);
322dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
323dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
324dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_PMTUDISC] &&
325dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
326dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fputs("nopmtudisc ", f);
327dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
328dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_IFLAGS])
329dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
330dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
331dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[IFLA_GRE_OFLAGS])
332dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
333dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
334dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
335dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
336dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
337dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "ikey %s ", s2);
338dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
339dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
340dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
341dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    *(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
342dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
343dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "ikey %s ", s2);
344dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
345dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
346dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (iflags & GRE_SEQ)
347dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fputs("iseq ", f);
348dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (oflags & GRE_SEQ)
349dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fputs("oseq ", f);
350dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (iflags & GRE_CSUM)
351dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fputs("icsum ", f);
352dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (oflags & GRE_CSUM)
353dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fputs("ocsum ", f);
354dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
355dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
356dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct link_util gre_link_util = {
357dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.id = "gre",
358dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.maxattr = IFLA_GRE_MAX,
359dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.parse_opt = gre_parse_opt,
360dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_opt = gre_print_opt,
361dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
362dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
363dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct link_util gretap_link_util = {
364dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.id = "gretap",
365dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.maxattr = IFLA_GRE_MAX,
366dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.parse_opt = gre_parse_opt,
367dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_opt = gre_print_opt,
368dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
369