Beispiel #1
0
static int create_session(struct l2tp_parm *p)
{
	GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
		     L2TP_CMD_SESSION_CREATE, NLM_F_REQUEST | NLM_F_ACK);

	addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
	addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
	addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
	addattr32(&req.n, 1024, L2TP_ATTR_PEER_SESSION_ID, p->peer_session_id);
	addattr16(&req.n, 1024, L2TP_ATTR_PW_TYPE, p->pw_type);
	addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type);
	addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);

	if (p->mtu)		addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
	if (p->recv_seq)	addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ);
	if (p->send_seq)	addattr(&req.n, 1024, L2TP_ATTR_SEND_SEQ);
	if (p->lns_mode)	addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE);
	if (p->data_seq)	addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq);
	if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
					  p->reorder_timeout);
	if (p->offset)		addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
	if (p->cookie_len)	addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
					  p->cookie, p->cookie_len);
	if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
					  p->peer_cookie,  p->peer_cookie_len);
	if (p->ifname && p->ifname[0])
		addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);

	if (rtnl_talk(&genl_rth, &req.n, 0, 0, NULL) < 0)
		return -2;

	return 0;
}
Beispiel #2
0
int
dbpci(Vga *vga, Ndbtuple *tuple)
{
	int did, vid;
	Ndbtuple *t, *td;
	Pcidev *pci;

	for(t = tuple->entry; t; t = t->entry){
		if(strcmp(t->attr, "vid") != 0 || (vid=atoi(t->val)) == 0)
			continue;
		for(td = t->line; td != t; td = td->line){
			if(strcmp(td->attr, "did") != 0)
				continue;
			if(strcmp(td->val, "*") == 0)
				did = 0;
			else if((did=atoi(td->val)) == 0)
				continue;
			for(pci=nil; pci=pcimatch(pci, vid, did);)
				if(pci->ccrb == 3)
					break;
			if(pci == nil)
				continue;
			vga->pci = pci;
			addattr(&vga->attr, t);
			addattr(&vga->attr, td);
			return 1;
		}
	}
	return 0;
}
Beispiel #3
0
static inline void 
ct_build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b)
{
	uint32_t data = nfct_get_attr_u32(ct, a);
	data = htonl(data);
	addattr(n, b, &data, sizeof(uint32_t));
}
Beispiel #4
0
static void
save(Vga *vga, Ndbtuple *tuple)
{
	Ctlr *c;
	Ndbtuple *t;

	for(t = tuple->entry; t; t = t->entry){
		if(strcmp(t->attr, "ctlr") == 0){
			vga->ctlr = addctlr(vga, t->val);
			if(strcmp(t->val, "vesa") == 0)
				vga->vesa = vga->ctlr;
		}else if(strcmp(t->attr, "ramdac") == 0)
			vga->ramdac = addctlr(vga, t->val);
		else if(strcmp(t->attr, "clock") == 0)
			vga->clock = addctlr(vga, t->val);
		else if(strcmp(t->attr, "hwgc") == 0)
			vga->hwgc = addctlr(vga, t->val);
		else if(strcmp(t->attr, "link") == 0){
			c = addctlr(vga, t->val);
			if(strcmp(t->val, "vesa") == 0)
				vga->vesa = c;
		}else if(strcmp(t->attr, "linear") == 0)
			vga->linear = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "membw") == 0)
			vga->membw = strtol(t->val, 0, 0)*1000000;
		else if(strcmp(t->attr, "vid")==0 || strcmp(t->attr, "did")==0)
			{}
		else if(strtol(t->attr, 0, 0) == 0)
			addattr(&vga->attr, t);
	}
}
Beispiel #5
0
/* Function to add, remove and update entries in the kernel routing
 * table */
int nl_kern_route(int action, int flags, int family,
        int index, struct in_addr *dst, struct in_addr *gw,
        struct in_addr *nm, int metric)
{
    struct {
        struct nlmsghdr nlh;
        struct rtmsg rtm;
        char attrbuf[1024];
    } req;

    if (!dst || !gw)
        return -1;

    req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    req.nlh.nlmsg_type = action;
    req.nlh.nlmsg_flags = NLM_F_REQUEST | flags;
    req.nlh.nlmsg_pid = 0;

    req.rtm.rtm_family = family;

    if (!nm)
        req.rtm.rtm_dst_len = sizeof(struct in_addr) * 8;
    else
        req.rtm.rtm_dst_len = prefix_length(AF_INET, nm);

    req.rtm.rtm_src_len = 0;
    req.rtm.rtm_tos = 0;
    req.rtm.rtm_table = RT_TABLE_MAIN;
    req.rtm.rtm_protocol = 100;
    req.rtm.rtm_scope = RT_SCOPE_LINK;
    req.rtm.rtm_type = RTN_UNICAST;
    req.rtm.rtm_flags = 0;

    addattr(&req.nlh, RTA_DST, dst, sizeof(struct in_addr));

    if (memcmp(dst, gw, sizeof(struct in_addr)) != 0) {
        req.rtm.rtm_scope = RT_SCOPE_UNIVERSE;
        addattr(&req.nlh, RTA_GATEWAY, gw, sizeof(struct in_addr));
    }

    if (index > 0)
        addattr(&req.nlh, RTA_OIF, &index, sizeof(index));

    addattr(&req.nlh, RTA_PRIORITY, &metric, sizeof(metric));

    return nl_send(&rtsock, &req.nlh);
}
Beispiel #6
0
void
replumb(Client *c)
{
	int i;
	Plumbmsg *m;
	char name[128], *ctype, *ext, *p;

	if(!c->plumbed)
		return;
	m = emalloc(sizeof(Plumbmsg));
	m->src = "webfs";
	m->dst = nil;
	m->wdir = "/";
	m->type = "text";
	m->attr = nil;
	addattr(m, "url", c->url->url);
	ctype = c->contenttype;
	ext = nil;
	if(ctype != nil) {
		addattr(m, "content-type", ctype);
		for(i = 0; i < nelem(ctypes); i++) {
			if(strcmp(ctype, ctypes[i].ctype) == 0) {
				ext = ctypes[i].ext;
				break;
			}
		}
	}
	if(ext == nil) {
		p = strrchr(c->url->url, '/');
		if(p != nil)
			p = strrchr(p+1, '.');
		if(p != nil && strlen(p) <= 5)
			ext = p+1;
		else
			ext = "txt";		/* punt */
	}
	c->ext = ext;
if(0)fprint(2, "content type %s -> extension .%s\n", ctype, ext);
	m->ndata = snprint(name, sizeof name, "/mnt/web/%d/body.%s", c->num, ext);
	m->data = estrdup(name);
	proccreate(plumbsendproc, m, STACK);	/* separate proc to avoid a deadlock */
}
Beispiel #7
0
Attr*
addcap(Attr *a, char *sysuser, Ticket *t)
{
	Attr *newa;
	char *c;

//	c = mkcap(t->cuid, t->suid);
	c = mkcap(sysuser, t->suid);
	newa = addattr(a, "cuid=%q suid=%q cap=%s", t->cuid, t->suid, c);
	free(c);
	return newa;
}
Beispiel #8
0
static int create_tunnel(struct l2tp_parm *p)
{
	uint32_t local_attr = L2TP_ATTR_IP_SADDR;
	uint32_t peer_attr = L2TP_ATTR_IP_DADDR;

	GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
		     L2TP_CMD_TUNNEL_CREATE, NLM_F_REQUEST | NLM_F_ACK);

	addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
	addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
	addattr8(&req.n, 1024, L2TP_ATTR_PROTO_VERSION, 3);
	addattr16(&req.n, 1024, L2TP_ATTR_ENCAP_TYPE, p->encap);

	if (p->local_ip.family == AF_INET6)
		local_attr = L2TP_ATTR_IP6_SADDR;
	addattr_l(&req.n, 1024, local_attr, &p->local_ip.data,
		  p->local_ip.bytelen);

	if (p->peer_ip.family == AF_INET6)
		peer_attr = L2TP_ATTR_IP6_DADDR;
	addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data,
		  p->peer_ip.bytelen);

	if (p->encap == L2TP_ENCAPTYPE_UDP) {
		addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port);
		addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
		if (p->udp_csum)
			addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1);
		if (!p->udp6_csum_tx)
			addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
		if (!p->udp6_csum_rx)
			addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_RX);
	}

	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
		return -2;

	return 0;
}
Beispiel #9
0
int
dbbios(Vga *vga, Ndbtuple *tuple)
{
	char *bios, *p, *string;
	int len;
	long offset, offset1;
	Ndbtuple *t;

	for(t = tuple->entry; t; t = t->entry){
		if((offset = strtol(t->attr, 0, 0)) == 0)
			continue;

		string = t->val;
		len = strlen(string);

		if(p = strchr(t->attr, '-')) {
			if((offset1 = strtol(p+1, 0, 0)) < offset+len)
				continue;
		} else
			offset1 = offset+len;

		if(vga->offset) {
			if(offset > vga->offset || vga->offset+len > offset1)
				continue;
			offset = vga->offset;
			offset1 = offset+len;
		}

		for(; offset+len<=offset1; offset++) {
			if(vga->bios)
				bios = vga->bios;
			else
				bios = readbios(len, offset);
			if(strncmp(bios, string, len) == 0){
				if(vga->bios == 0){
					vga->bios = alloc(len+1);
					strncpy(vga->bios, bios, len);
				}
				addattr(&vga->attr, t);
				return 1;
			}
		}
	}
	return 0;
}
Beispiel #10
0
static inline void 
ct_build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n)
{
	struct nta_attr_natseqadj data = {
		.orig_seq_correction_pos =
		htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)),
		.orig_seq_offset_before = 
		htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)),
		.orig_seq_offset_after =
		htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)),
		.repl_seq_correction_pos = 
		htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)),
		.repl_seq_offset_before =
		htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)),
		.repl_seq_offset_after = 
		htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER))
	};
	addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj));
}
Beispiel #11
0
static inline void
ct_build_str(const struct nf_conntrack *ct, int a, struct nethdr *n, int b)
{
	const char *data = nfct_get_attr(ct, a);
	addattr(n, b, data, strlen(data)+1);
}
Beispiel #12
0
int main(int argc, char **argv)
{
    int c;
    char *progname;

    ingraph_state ig;

    Agraph_t *graph;
    Agnode_t *node;
    Agedge_t *edge;
    Agedge_t *nexte;
    Agsym_t *attr;

    char **files;

    generic_list_t *attr_list;
    generic_list_t *node_list;

    unsigned long i, j;

    opterr = 0;

    progname = strrchr(argv[0], '/');
    if (progname == NULL) {
	progname = argv[0];
    } else {
	progname++;		/* character after last '/' */
    }

    attr_list = new_generic_list(16);
    node_list = new_generic_list(16);

    while ((c = getopt(argc, argv, "hvn:N:")) != -1) {
	switch (c) {
	case 'N':
	    {
		attr_list = addattr(attr_list, optarg);
		break;
	    }
	case 'n':
	    {
		node_list = addnode(node_list, optarg);
		break;
	    }
	case 'h':
	    {
		help_message(progname);
		exit(EXIT_SUCCESS);
		break;
	    }
	case 'v':
	    {
		verbose = 1;
		break;
	    }
	case '?':
	    if (isprint(optopt)) {
		fprintf(stderr, "Unknown option `-%c'.\n", optopt);
	    } else {
		fprintf(stderr, "Unknown option character `\\x%X'.\n",
			optopt);
	    }
	    exit(EXIT_FAILURE);
	    break;

	default:
	    help_message(progname);
	    exit(EXIT_FAILURE);
	    break;
	}
    }

    /* Any arguments left? */
    if (optind < argc) {
	files = &argv[optind];
    } else {
	files = NULL;
    }

    newIngraph(&ig, files, gread);
    while ((graph = nextGraph(&ig)) != NULL) {
	if (agisdirected(graph) == 0) {
	    fprintf(stderr,
		    "*** Error: Graph is undirected! Pruning works only with directed graphs!\n");
	    exit(EXIT_FAILURE);
	}

	/* attach node data for marking to all nodes */
	aginit(graph, AGNODE, NDNAME, sizeof(ndata), 1);

	/* prune all nodes specified on the commandline */
	for (i = 0; i < node_list->used; i++) {
	    if (verbose == 1)
		fprintf(stderr, "Pruning node %s\n",
			(char *) node_list->data[i]);

	    /* check whether a node of that name exists at all */
	    node = agnode(graph, (char *) node_list->data[i], 0);
	    if (node == NULL) {
		fprintf(stderr,
			"*** Warning: No such node: %s -- gracefully skipping this one\n",
			(char *) node_list->data[i]);
	    } else {
		MARK(node);	/* Avoid cycles */
		/* Iterate over all outgoing edges */
		for (edge = agfstout(node); edge; edge = nexte) {
		    nexte = agnxtout(edge);
		    if (aghead(edge) != node) {	/* non-loop edges */
			if (verbose == 1)
			    fprintf(stderr, "Processing descendant: %s\n",
				    agnameof(aghead(edge)));
			remove_child(graph, aghead(edge));
			agdelete(graph, edge);
		    }
		}
		UNMARK(node);	/* Unmark so that it can be removed in later passes */

		/* Change attribute (e.g. border style) to show that node has been pruneed */
		for (j = 0; j < attr_list->used; j++) {
		    /* create attribute if it doesn't exist and set it */
		    attr =
			agattr(graph, AGNODE,
			       ((strattr_t *) attr_list->data[j])->n, "");
		    if (attr == NULL) {
			fprintf(stderr, "Couldn't create attribute: %s\n",
				((strattr_t *) attr_list->data[j])->n);
			exit(EXIT_FAILURE);
		    }
		    agxset(node, attr,
			   ((strattr_t *) attr_list->data[j])->v);
		}
	    }
	}
	agwrite(graph, stdout);
	agclose(graph);
    }
    free(attr_list);
    free(node_list);
    exit(EXIT_SUCCESS);
}
Beispiel #13
0
static int
dbmonitor(Ndb* db, Mode* mode, char* type, char* size)
{
	Ndbs s;
	Ndbtuple *t, *tuple;
	char *p, attr[Namelen+1], val[Namelen+1], buf[2*Namelen+1];
	int clock, x, i;

	/*
	 * Clock rate hack.
	 * If the size is 'XxYxZ@NMHz' then override the database entry's
	 * 'clock=' with 'N*1000000'.
	 */
	clock = 0;
	strcpy(buf, size);
	if(p = strchr(buf, '@')){
		*p++ = 0;
		if((clock = strtol(p, &p, 0)) && strcmp(p, "MHz") == 0)
			clock *= 1000000;
	}

	memset(mode, 0, sizeof(Mode));

	if((p = strchr(buf, 'x')) && (p = strchr(p+1, 'x'))){
		*p++ = 0;
		mode->z = atoi(p);
	}

	strcpy(attr, type);
	strcpy(val, buf);

	if(p = ndbgetvalue(db, &s, attr, "", "videobw", nil)){
		mode->videobw = atol(p)*1000000UL;
		free(p);
	}

	if(mode->x == 0 && ((mode->x = strtol(val, &p, 0)) == 0 || *p++ != 'x'))
		return 0;
	if(mode->y == 0 && (mode->y = strtol(p, &p, 0)) == 0)
		return 0;
	i = 0;
buggery:
	if((tuple = ndbsearch(db, &s, attr, val)) == 0)
		return 0;

	for(t = tuple->entry; t; t = t->entry){
		if(strcmp(t->attr, "clock") == 0 && mode->frequency == 0)
			mode->frequency = strtod(t->val, 0)*1000000;
		else if(strcmp(t->attr, "defaultclock") == 0 && mode->deffrequency == 0)
			mode->deffrequency = strtod(t->val, 0)*1000000;
		else if(strcmp(t->attr, "ht") == 0 && mode->ht == 0)
			mode->ht = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "shb") == 0 && mode->shb == 0)
			mode->shb = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "ehb") == 0 && mode->ehb == 0)
			mode->ehb = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "shs") == 0 && mode->shs == 0)
			mode->shs = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "ehs") == 0 && mode->ehs == 0)
			mode->ehs = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "vt") == 0 && mode->vt == 0)
			mode->vt = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "vrs") == 0 && mode->vrs == 0)
			mode->vrs = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "vre") == 0 && mode->vre == 0)
			mode->vre = strtol(t->val, 0, 0);
		else if(strcmp(t->attr, "hsync") == 0)
			mode->hsync = *t->val;
		else if(strcmp(t->attr, "vsync") == 0)
			mode->vsync = *t->val;
		else if(strcmp(t->attr, "interlace") == 0)
			mode->interlace = *t->val;
		else if(strcmp(t->attr, "include") == 0 /*&& strcmp(t->val, val) != 0*/){
			strcpy(attr, t->attr);
			strcpy(val, t->val);
			ndbfree(tuple);
			if(i++ > 5)
				error("dbmonitor: implausible include depth at %s=%s\n", attr, val);
			goto buggery;
		}
		else if(strcmp(t->attr, "include") == 0){
			print("warning: bailed out of infinite loop in attr %s=%s\n", attr, val);
		}
		else
			addattr(&mode->attr, t);
	}
	ndbfree(tuple);

	if((x = strtol(size, &p, 0)) == 0 || x != mode->x || *p++ != 'x')
		return 0;
	if((x = strtol(p, &p, 0)) == 0 || x != mode->y || *p++ != 'x')
		return 0;
	if((x = strtol(p, &p, 0)) == 0 || x != mode->z)
		return 0;

	if(clock)
		mode->frequency = clock;

	return 1;
}
Beispiel #14
0
static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
			    struct nlmsghdr *n)
{
	__u32 val;

	while (argc > 0) {
		if (matches(*argv, "forward_delay") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid forward_delay", *argv);

			addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
		} else if (matches(*argv, "hello_time") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid hello_time", *argv);

			addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
		} else if (matches(*argv, "max_age") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid max_age", *argv);

			addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
		} else if (matches(*argv, "ageing_time") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid ageing_time", *argv);

			addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
		} else if (matches(*argv, "stp_state") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid stp_state", *argv);

			addattr32(n, 1024, IFLA_BR_STP_STATE, val);
		} else if (matches(*argv, "priority") == 0) {
			__u16 prio;

			NEXT_ARG();
			if (get_u16(&prio, *argv, 0))
				invarg("invalid priority", *argv);

			addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
		} else if (matches(*argv, "vlan_filtering") == 0) {
			__u8 vlan_filter;

			NEXT_ARG();
			if (get_u8(&vlan_filter, *argv, 0))
				invarg("invalid vlan_filtering", *argv);

			addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
		} else if (matches(*argv, "vlan_protocol") == 0) {
			__u16 vlan_proto;

			NEXT_ARG();
			if (ll_proto_a2n(&vlan_proto, *argv))
				invarg("invalid vlan_protocol", *argv);

			addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
		} else if (matches(*argv, "group_fwd_mask") == 0) {
			__u16 fwd_mask;

			NEXT_ARG();
			if (get_u16(&fwd_mask, *argv, 0))
				invarg("invalid group_fwd_mask", *argv);

			addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
		} else if (matches(*argv, "group_address") == 0) {
			char llabuf[32];
			int len;

			NEXT_ARG();
			len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len);
		} else if (matches(*argv, "fdb_flush") == 0) {
			addattr(n, 1024, IFLA_BR_FDB_FLUSH);
		} else if (matches(*argv, "vlan_default_pvid") == 0) {
			__u16 default_pvid;

			NEXT_ARG();
			if (get_u16(&default_pvid, *argv, 0))
				invarg("invalid vlan_default_pvid", *argv);

			addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID,
				  default_pvid);
		} else if (matches(*argv, "vlan_stats_enabled") == 0) {
			__u8 vlan_stats_enabled;

			NEXT_ARG();
			if (get_u8(&vlan_stats_enabled, *argv, 0))
				invarg("invalid vlan_stats_enabled", *argv);
			addattr8(n, 1024, IFLA_BR_VLAN_STATS_ENABLED,
				  vlan_stats_enabled);
		} else if (matches(*argv, "mcast_router") == 0) {
			__u8 mcast_router;

			NEXT_ARG();
			if (get_u8(&mcast_router, *argv, 0))
				invarg("invalid mcast_router", *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router);
		} else if (matches(*argv, "mcast_snooping") == 0) {
			__u8 mcast_snoop;

			NEXT_ARG();
			if (get_u8(&mcast_snoop, *argv, 0))
				invarg("invalid mcast_snooping", *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop);
		} else if (matches(*argv, "mcast_query_use_ifaddr") == 0) {
			__u8 mcast_qui;

			NEXT_ARG();
			if (get_u8(&mcast_qui, *argv, 0))
				invarg("invalid mcast_query_use_ifaddr",
				       *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR,
				 mcast_qui);
		} else if (matches(*argv, "mcast_querier") == 0) {
			__u8 mcast_querier;

			NEXT_ARG();
			if (get_u8(&mcast_querier, *argv, 0))
				invarg("invalid mcast_querier", *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier);
		} else if (matches(*argv, "mcast_hash_elasticity") == 0) {
			__u32 mcast_hash_el;

			NEXT_ARG();
			if (get_u32(&mcast_hash_el, *argv, 0))
				invarg("invalid mcast_hash_elasticity",
				       *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY,
				  mcast_hash_el);
		} else if (matches(*argv, "mcast_hash_max") == 0) {
			__u32 mcast_hash_max;

			NEXT_ARG();
			if (get_u32(&mcast_hash_max, *argv, 0))
				invarg("invalid mcast_hash_max", *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX,
				  mcast_hash_max);
		} else if (matches(*argv, "mcast_last_member_count") == 0) {
			__u32 mcast_lmc;

			NEXT_ARG();
			if (get_u32(&mcast_lmc, *argv, 0))
				invarg("invalid mcast_last_member_count",
				       *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT,
				  mcast_lmc);
		} else if (matches(*argv, "mcast_startup_query_count") == 0) {
			__u32 mcast_sqc;

			NEXT_ARG();
			if (get_u32(&mcast_sqc, *argv, 0))
				invarg("invalid mcast_startup_query_count",
				       *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT,
				  mcast_sqc);
		} else if (matches(*argv, "mcast_last_member_interval") == 0) {
			__u64 mcast_last_member_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_last_member_intvl, *argv, 0))
				invarg("invalid mcast_last_member_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL,
				  mcast_last_member_intvl);
		} else if (matches(*argv, "mcast_membership_interval") == 0) {
			__u64 mcast_membership_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_membership_intvl, *argv, 0))
				invarg("invalid mcast_membership_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL,
				  mcast_membership_intvl);
		} else if (matches(*argv, "mcast_querier_interval") == 0) {
			__u64 mcast_querier_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_querier_intvl, *argv, 0))
				invarg("invalid mcast_querier_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL,
				  mcast_querier_intvl);
		} else if (matches(*argv, "mcast_query_interval") == 0) {
			__u64 mcast_query_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_query_intvl, *argv, 0))
				invarg("invalid mcast_query_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL,
				  mcast_query_intvl);
		} else if (!matches(*argv, "mcast_query_response_interval")) {
			__u64 mcast_query_resp_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_query_resp_intvl, *argv, 0))
				invarg("invalid mcast_query_response_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
				  mcast_query_resp_intvl);
		} else if (!matches(*argv, "mcast_startup_query_interval")) {
			__u64 mcast_startup_query_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_startup_query_intvl, *argv, 0))
				invarg("invalid mcast_startup_query_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
				  mcast_startup_query_intvl);
		} else if (matches(*argv, "mcast_stats_enabled") == 0) {
			__u8 mcast_stats_enabled;

			NEXT_ARG();
			if (get_u8(&mcast_stats_enabled, *argv, 0))
				invarg("invalid mcast_stats_enabled", *argv);
			addattr8(n, 1024, IFLA_BR_MCAST_STATS_ENABLED,
				  mcast_stats_enabled);
		} else if (matches(*argv, "mcast_igmp_version") == 0) {
			__u8 igmp_version;

			NEXT_ARG();
			if (get_u8(&igmp_version, *argv, 0))
				invarg("invalid mcast_igmp_version", *argv);
			addattr8(n, 1024, IFLA_BR_MCAST_IGMP_VERSION,
				  igmp_version);
		} else if (matches(*argv, "mcast_mld_version") == 0) {
			__u8 mld_version;

			NEXT_ARG();
			if (get_u8(&mld_version, *argv, 0))
				invarg("invalid mcast_mld_version", *argv);
			addattr8(n, 1024, IFLA_BR_MCAST_MLD_VERSION,
				  mld_version);
		} else if (matches(*argv, "nf_call_iptables") == 0) {
			__u8 nf_call_ipt;

			NEXT_ARG();
			if (get_u8(&nf_call_ipt, *argv, 0))
				invarg("invalid nf_call_iptables", *argv);

			addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES,
				 nf_call_ipt);
		} else if (matches(*argv, "nf_call_ip6tables") == 0) {
			__u8 nf_call_ip6t;

			NEXT_ARG();
			if (get_u8(&nf_call_ip6t, *argv, 0))
				invarg("invalid nf_call_ip6tables", *argv);

			addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES,
				 nf_call_ip6t);
		} else if (matches(*argv, "nf_call_arptables") == 0) {
			__u8 nf_call_arpt;

			NEXT_ARG();
			if (get_u8(&nf_call_arpt, *argv, 0))
				invarg("invalid nf_call_arptables", *argv);

			addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES,
				 nf_call_arpt);
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	return 0;
}
static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
			  struct nlmsghdr *n)
{
	__u32 vni = 0;
	int vni_set = 0;
	__u32 daddr = 0;
	struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
	__u32 label = 0;
	__u8 ttl = 0;
	__u8 tos = 0;
	__u16 dstport = 0;
	bool metadata = 0;
	__u8 udpcsum = 0;
	bool udpcsum_set = false;
	__u8 udp6zerocsumtx = 0;
	bool udp6zerocsumtx_set = false;
	__u8 udp6zerocsumrx = 0;
	bool udp6zerocsumrx_set = false;

	while (argc > 0) {
		if (!matches(*argv, "id") ||
		    !matches(*argv, "vni")) {
			NEXT_ARG();
			if (get_u32(&vni, *argv, 0) ||
			    vni >= 1u << 24)
				invarg("invalid id", *argv);
			vni_set = 1;
		} else if (!matches(*argv, "remote")) {
			NEXT_ARG();
			if (!inet_get_addr(*argv, &daddr, &daddr6)) {
				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
				return -1;
			}
			if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
				invarg("invalid remote address", *argv);
		} else if (!matches(*argv, "ttl") ||
			   !matches(*argv, "hoplimit")) {
			unsigned int uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (get_unsigned(&uval, *argv, 0))
					invarg("invalid TTL", *argv);
				if (uval > 255)
					invarg("TTL must be <= 255", *argv);
				ttl = uval;
			}
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "dsfield")) {
			__u32 uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
		} else if (!matches(*argv, "label") ||
			   !matches(*argv, "flowlabel")) {
			__u32 uval;

			NEXT_ARG();
			if (get_u32(&uval, *argv, 0) ||
			    (uval & ~LABEL_MAX_MASK))
				invarg("invalid flowlabel", *argv);
			label = htonl(uval);
		} else if (!matches(*argv, "dstport")) {
			NEXT_ARG();
			if (get_u16(&dstport, *argv, 0))
				invarg("dstport", *argv);
		} else if (!matches(*argv, "external")) {
			metadata = true;
		} else if (!matches(*argv, "noexternal")) {
			metadata = false;
		} else if (!matches(*argv, "udpcsum")) {
			udpcsum = 1;
			udpcsum_set = true;
		} else if (!matches(*argv, "noudpcsum")) {
			udpcsum = 0;
			udpcsum_set = true;
		} else if (!matches(*argv, "udp6zerocsumtx")) {
			udp6zerocsumtx = 1;
			udp6zerocsumtx_set = true;
		} else if (!matches(*argv, "noudp6zerocsumtx")) {
			udp6zerocsumtx = 0;
			udp6zerocsumtx_set = true;
		} else if (!matches(*argv, "udp6zerocsumrx")) {
			udp6zerocsumrx = 1;
			udp6zerocsumrx_set = true;
		} else if (!matches(*argv, "noudp6zerocsumrx")) {
			udp6zerocsumrx = 0;
			udp6zerocsumrx_set = true;
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "geneve: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	if (metadata && vni_set) {
		fprintf(stderr, "geneve: both 'external' and vni cannot be specified\n");
		return -1;
	}

	if (!metadata) {
		/* parameter checking make sense only for full geneve tunnels */
		if (!vni_set) {
			fprintf(stderr, "geneve: missing virtual network identifier\n");
			return -1;
		}

		if (!daddr && IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
			fprintf(stderr, "geneve: remote link partner not specified\n");
			return -1;
		}
	}

	addattr32(n, 1024, IFLA_GENEVE_ID, vni);
	if (daddr)
		addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4);
	if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6))
		addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr));
	addattr32(n, 1024, IFLA_GENEVE_LABEL, label);
	addattr8(n, 1024, IFLA_GENEVE_TTL, ttl);
	addattr8(n, 1024, IFLA_GENEVE_TOS, tos);
	if (dstport)
		addattr16(n, 1024, IFLA_GENEVE_PORT, htons(dstport));
	if (metadata)
		addattr(n, 1024, IFLA_GENEVE_COLLECT_METADATA);
	if (udpcsum_set)
		addattr8(n, 1024, IFLA_GENEVE_UDP_CSUM, udpcsum);
	if (udp6zerocsumtx_set)
		addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, udp6zerocsumtx);
	if (udp6zerocsumrx_set)
		addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, udp6zerocsumrx);

	return 0;
}