int iplink_parse(int argc, char **argv, struct iplink_req *req,
		char **name, char **type, char **link, char **dev)
{
	int ret, len;
	char abuf[32];
	int qlen = -1;
	int mtu = -1;
	int netns = -1;
	int vf = -1;

	ret = argc;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			*name = *argv;
		} else if (matches(*argv, "link") == 0) {
			NEXT_ARG();
			*link = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
		} else if (matches(*argv, "broadcast") == 0 ||
				strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
		} else if (matches(*argv, "txqueuelen") == 0 ||
				strcmp(*argv, "qlen") == 0 ||
				matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
                } else if (strcmp(*argv, "netns") == 0) {
                        NEXT_ARG();
                        if (netns != -1)
                                duparg("netns", *argv);
                        if (get_integer(&netns, *argv, 0))
                                invarg("Invalid \"netns\" value\n", *argv);
                        addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast");
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast");
		} else if (strcmp(*argv, "multipath") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOMULTIPATH;
			req->i.ifi_change |= IFF_MPBACKUP;
			req->i.ifi_change |= IFF_MPHANDOVER;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOMULTIPATH;
				req->i.ifi_flags &= ~IFF_MPBACKUP;
				req->i.ifi_flags &= ~IFF_MPHANDOVER;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOMULTIPATH;
			} else if (strcmp(*argv, "backup") == 0) {
				req->i.ifi_flags &= ~IFF_NOMULTIPATH;
				req->i.ifi_flags |= IFF_MPBACKUP;
			} else if (strcmp(*argv, "handover") == 0) {
				req->i.ifi_flags &= ~IFF_NOMULTIPATH;
				req->i.ifi_flags |= IFF_MPHANDOVER;
			} else {
				fprintf(stderr, "Error: argument of \"multipath\" must be"
						"\"on\", \"off\", \"backup\" or \"handover\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc");
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers");
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOARP;
			} else
				return on_off("noarp");
		} else if (strcmp(*argv, "vf") == 0) {
			struct rtattr *vflist;
			NEXT_ARG();
			if (get_integer(&vf,  *argv, 0)) {
				invarg("Invalid \"vf\" value\n", *argv);
			}
			vflist = addattr_nest(&req->n, sizeof(*req),
					      IFLA_VFINFO_LIST);
			len = iplink_parse_vf(vf, &argc, &argv, req);
			if (len < 0)
				return -1;
			addattr_nest_end(&req->n, vflist);
#ifdef IFF_DYNAMIC
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic");
#endif
		} else if (matches(*argv, "type") == 0) {
			NEXT_ARG();
			*type = *argv;
			argc--; argv++;
			break;
		} else if (matches(*argv, "alias") == 0) {
			NEXT_ARG();
			addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
				  *argv, strlen(*argv));
			argc--; argv++;
			break;
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (*dev)
				duparg2("dev", *argv);
			*dev = *argv;
		}
		argc--; argv++;
	}

	return ret - argc;
}
static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct xfrm_usersa_info xsinfo;
		char   			buf[RTA_BUF_SIZE];
	} req;
	struct xfrm_replay_state replay;
	char *idp = NULL;
	char *aeadop = NULL;
	char *ealgop = NULL;
	char *aalgop = NULL;
	char *calgop = NULL;
	char *coap = NULL;
	char *sctxp = NULL;
	struct xfrm_mark mark = {0, 0};
	struct {
		struct xfrm_user_sec_ctx sctx;
		char    str[CTX_BUF_SIZE];
	} ctx;

	memset(&req, 0, sizeof(req));
	memset(&replay, 0, sizeof(replay));
	memset(&ctx, 0, sizeof(ctx));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.xsinfo.family = preferred_family;

	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
	req.xsinfo.lft.hard_packet_limit = XFRM_INF;

	while (argc > 0) {
		if (strcmp(*argv, "mode") == 0) {
			NEXT_ARG();
			xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
		} else if (strcmp(*argv, "mark") == 0) {
			xfrm_parse_mark(&mark, &argc, &argv);
		} else if (strcmp(*argv, "reqid") == 0) {
			NEXT_ARG();
			xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
		} else if (strcmp(*argv, "seq") == 0) {
			NEXT_ARG();
			xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
		} else if (strcmp(*argv, "replay-window") == 0) {
			NEXT_ARG();
			if (get_u8(&req.xsinfo.replay_window, *argv, 0))
				invarg("\"replay-window\" value is invalid", *argv);
		} else if (strcmp(*argv, "replay-seq") == 0) {
			NEXT_ARG();
			if (get_u32(&replay.seq, *argv, 0))
				invarg("\"replay-seq\" value is invalid", *argv);
		} else if (strcmp(*argv, "replay-oseq") == 0) {
			NEXT_ARG();
			if (get_u32(&replay.oseq, *argv, 0))
				invarg("\"replay-oseq\" value is invalid", *argv);
		} else if (strcmp(*argv, "flag") == 0) {
			NEXT_ARG();
			xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
		} else if (strcmp(*argv, "sel") == 0) {
			NEXT_ARG();
			xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
		} else if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
		} else if (strcmp(*argv, "encap") == 0) {
			struct xfrm_encap_tmpl encap;
			inet_prefix oa;
		        NEXT_ARG();
			xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
			NEXT_ARG();
			if (get_u16(&encap.encap_sport, *argv, 0))
				invarg("\"encap\" sport value is invalid", *argv);
			encap.encap_sport = htons(encap.encap_sport);
			NEXT_ARG();
			if (get_u16(&encap.encap_dport, *argv, 0))
				invarg("\"encap\" dport value is invalid", *argv);
			encap.encap_dport = htons(encap.encap_dport);
			NEXT_ARG();
			get_addr(&oa, *argv, AF_UNSPEC);
			memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
			addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
				  (void *)&encap, sizeof(encap));
		} else if (strcmp(*argv, "coa") == 0) {
			inet_prefix coa;
			xfrm_address_t xcoa;

			if (coap)
				duparg("coa", *argv);
			coap = *argv;

			NEXT_ARG();

			get_prefix(&coa, *argv, preferred_family);
			if (coa.family == AF_UNSPEC)
				invarg("\"coa\" address family is AF_UNSPEC", *argv);
			if (coa.bytelen > sizeof(xcoa))
				invarg("\"coa\" address length is too large", *argv);

			memset(&xcoa, 0, sizeof(xcoa));
			memcpy(&xcoa, &coa.data, coa.bytelen);

			addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
				  (void *)&xcoa, sizeof(xcoa));
		} else if (strcmp(*argv, "ctx") == 0) {
			char *context;

			if (sctxp)
				duparg("ctx", *argv);
			sctxp = *argv;

			NEXT_ARG();
			context = *argv;

			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
			addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX,
				  (void *)&ctx, ctx.sctx.len);
		} else {
			
			int type = xfrm_algotype_getbyname(*argv);
			switch (type) {
			case XFRMA_ALG_AEAD:
			case XFRMA_ALG_CRYPT:
			case XFRMA_ALG_AUTH:
			case XFRMA_ALG_AUTH_TRUNC:
			case XFRMA_ALG_COMP:
			{
				
				struct {
					union {
						struct xfrm_algo alg;
						struct xfrm_algo_aead aead;
						struct xfrm_algo_auth auth;
					} u;
					char buf[XFRM_ALGO_KEY_BUF_SIZE];
				} alg = {};
				int len;
				__u32 icvlen, trunclen;
				char *name;
				char *key;
				char *buf;

				switch (type) {
				case XFRMA_ALG_AEAD:
					if (aeadop)
						duparg("ALGO-TYPE", *argv);
					aeadop = *argv;
					break;
				case XFRMA_ALG_CRYPT:
					if (ealgop)
						duparg("ALGO-TYPE", *argv);
					ealgop = *argv;
					break;
				case XFRMA_ALG_AUTH:
				case XFRMA_ALG_AUTH_TRUNC:
					if (aalgop)
						duparg("ALGO-TYPE", *argv);
					aalgop = *argv;
					break;
				case XFRMA_ALG_COMP:
					if (calgop)
						duparg("ALGO-TYPE", *argv);
					calgop = *argv;
					break;
				default:
					
					invarg("\"ALGO-TYPE\" is invalid\n", *argv);
				}

				if (!NEXT_ARG_OK())
					missarg("ALGO-NAME");
				NEXT_ARG();
				name = *argv;

				if (!NEXT_ARG_OK())
					missarg("ALGO-KEY");
				NEXT_ARG();
				key = *argv;

				buf = alg.u.alg.alg_key;
				len = sizeof(alg.u.alg);

				switch (type) {
				case XFRMA_ALG_AEAD:
					if (!NEXT_ARG_OK())
						missarg("ALGO-ICV-LEN");
					NEXT_ARG();
					if (get_u32(&icvlen, *argv, 0))
						invarg("\"aead\" ICV length is invalid",
						       *argv);
					alg.u.aead.alg_icv_len = icvlen;

					buf = alg.u.aead.alg_key;
					len = sizeof(alg.u.aead);
					break;
				case XFRMA_ALG_AUTH_TRUNC:
					if (!NEXT_ARG_OK())
						missarg("ALGO-TRUNC-LEN");
					NEXT_ARG();
					if (get_u32(&trunclen, *argv, 0))
						invarg("\"auth\" trunc length is invalid",
						       *argv);
					alg.u.auth.alg_trunc_len = trunclen;

					buf = alg.u.auth.alg_key;
					len = sizeof(alg.u.auth);
					break;
				}

				xfrm_algo_parse((void *)&alg, type, name, key,
						buf, sizeof(alg.buf));
				len += alg.u.alg.alg_key_len;

				addattr_l(&req.n, sizeof(req.buf), type,
					  (void *)&alg, len);
				break;
			}
			default:
				
				if (idp)
					invarg("unknown", *argv);
				idp = *argv;

				
				xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
					      &req.xsinfo.family, 0, &argc, &argv);
				if (preferred_family == AF_UNSPEC)
					preferred_family = req.xsinfo.family;
			}
		}
		argc--; argv++;
	}

	if (replay.seq || replay.oseq)
		addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
			  (void *)&replay, sizeof(replay));

	if (!idp) {
		fprintf(stderr, "Not enough information: \"ID\" is required\n");
		exit(1);
	}

	if (mark.m & mark.v) {
		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
				  (void *)&mark, sizeof(mark));
		if (r < 0) {
			fprintf(stderr, "XFRMA_MARK failed\n");
			exit(1);
		}
	}

	switch (req.xsinfo.mode) {
	case XFRM_MODE_TRANSPORT:
	case XFRM_MODE_TUNNEL:
		if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
			fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
		break;
	case XFRM_MODE_ROUTEOPTIMIZATION:
	case XFRM_MODE_IN_TRIGGER:
		if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
			fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
		if (req.xsinfo.id.spi != 0) {
			fprintf(stderr, "\"spi\" must be 0 with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
		break;
	default:
		break;
	}

	if (aeadop || ealgop || aalgop || calgop) {
		if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
			fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
	} else {
		if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
			fprintf(stderr, "\"ALGO\" is required with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit (1);
		}
	}

	if (coap) {
		if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
			fprintf(stderr, "\"coa\" is invalid with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
	} else {
		if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
			fprintf(stderr, "\"coa\" is required with proto=%s\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit (1);
		}
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xsinfo.family == AF_UNSPEC)
		req.xsinfo.family = AF_INET;

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Beispiel #3
0
int iplink_parse(int argc, char **argv, struct iplink_req *req,
		char **name, char **type, char **link, char **dev, int *group, int *index)
{
	int ret, len;
	char abuf[32];
	int qlen = -1;
	int mtu = -1;
	int netns = -1;
	int vf = -1;
	int numtxqueues = -1;
	int numrxqueues = -1;
	int dev_index = 0;

	*group = -1;
	ret = argc;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			*name = *argv;
		} else if (strcmp(*argv, "index") == 0) {
			NEXT_ARG();
			*index = atoi(*argv);
		} else if (matches(*argv, "link") == 0) {
			NEXT_ARG();
			*link = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
		} else if (matches(*argv, "broadcast") == 0 ||
				strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
		} else if (matches(*argv, "txqueuelen") == 0 ||
				strcmp(*argv, "qlen") == 0 ||
				matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
		} else if (strcmp(*argv, "netns") == 0) {
			NEXT_ARG();
			if (netns != -1)
				duparg("netns", *argv);
			if ((netns = get_netns_fd(*argv)) >= 0)
				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
			else if (get_integer(&netns, *argv, 0) == 0)
				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
			else
				invarg("Invalid \"netns\" value\n", *argv);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast", *argv);
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast", *argv);
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc", *argv);
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers", *argv);
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOARP;
			} else
				return on_off("noarp", *argv);
		} else if (strcmp(*argv, "vf") == 0) {
			struct rtattr *vflist;
			NEXT_ARG();
			if (get_integer(&vf,  *argv, 0)) {
				invarg("Invalid \"vf\" value\n", *argv);
			}
			vflist = addattr_nest(&req->n, sizeof(*req),
					      IFLA_VFINFO_LIST);
			if (dev_index == 0)
				missarg("dev");

			len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
			if (len < 0)
				return -1;
			addattr_nest_end(&req->n, vflist);
		} else if (matches(*argv, "master") == 0) {
			int ifindex;
			NEXT_ARG();
			ifindex = ll_name_to_index(*argv);
			if (!ifindex)
				invarg("Device does not exist\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
				  &ifindex, 4);
		} else if (matches(*argv, "nomaster") == 0) {
			int ifindex = 0;
			addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
				  &ifindex, 4);
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic", *argv);
		} else if (matches(*argv, "type") == 0) {
			NEXT_ARG();
			*type = *argv;
			argc--; argv++;
			break;
		} else if (matches(*argv, "alias") == 0) {
			NEXT_ARG();
			addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
				  *argv, strlen(*argv));
			argc--; argv++;
			break;
		} else if (strcmp(*argv, "group") == 0) {
			NEXT_ARG();
			if (*group != -1)
				duparg("group", *argv);
			if (rtnl_group_a2n(group, *argv))
				invarg("Invalid \"group\" value\n", *argv);
		} else if (strcmp(*argv, "mode") == 0) {
			int mode;
			NEXT_ARG();
			mode = get_link_mode(*argv);
			if (mode < 0)
				invarg("Invalid link mode\n", *argv);
			addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
		} else if (strcmp(*argv, "state") == 0) {
			int state;
			NEXT_ARG();
			state = get_operstate(*argv);
			if (state < 0)
				invarg("Invalid operstate\n", *argv);

			addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
		} else if (matches(*argv, "numtxqueues") == 0) {
			NEXT_ARG();
			if (numtxqueues != -1)
				duparg("numtxqueues", *argv);
			if (get_integer(&numtxqueues, *argv, 0))
				invarg("Invalid \"numtxqueues\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
				  &numtxqueues, 4);
		} else if (matches(*argv, "numrxqueues") == 0) {
			NEXT_ARG();
			if (numrxqueues != -1)
				duparg("numrxqueues", *argv);
			if (get_integer(&numrxqueues, *argv, 0))
				invarg("Invalid \"numrxqueues\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
				  &numrxqueues, 4);
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (*dev)
				duparg2("dev", *argv);
			*dev = *argv;
			dev_index = ll_name_to_index(*dev);
			if (dev_index == 0)
				invarg("Unknown device", *argv);
		}
		argc--; argv++;
	}

	return ret - argc;
}
Beispiel #4
0
static int xfrm_spd_setinfo(int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr			n;
		__u32				flags;
		char				buf[RTA_BUF_SIZE];
	} req;

	char *thr4 = NULL;
	char *thr6 = NULL;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = XFRM_MSG_NEWSPDINFO;
	req.flags = 0XFFFFFFFF;

	while (argc > 0) {
		if (strcmp(*argv, "hthresh4") == 0) {
			struct xfrmu_spdhthresh thr;

			if (thr4)
				duparg("hthresh4", *argv);
			thr4 = *argv;
			NEXT_ARG();
			if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 32)
				invarg("hthresh4 LBITS value is invalid", *argv);
			NEXT_ARG();
			if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 32)
				invarg("hthresh4 RBITS value is invalid", *argv);

			addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV4_HTHRESH,
				  (void *)&thr, sizeof(thr));
		} else if (strcmp(*argv, "hthresh6") == 0) {
			struct xfrmu_spdhthresh thr;

			if (thr6)
				duparg("hthresh6", *argv);
			thr6 = *argv;
			NEXT_ARG();
			if (get_u8(&thr.lbits, *argv, 0) || thr.lbits > 128)
				invarg("hthresh6 LBITS value is invalid", *argv);
			NEXT_ARG();
			if (get_u8(&thr.rbits, *argv, 0) || thr.rbits > 128)
				invarg("hthresh6 RBITS value is invalid", *argv);

			addattr_l(&req.n, sizeof(req), XFRMA_SPD_IPV6_HTHRESH,
				  (void *)&thr, sizeof(thr));
		} else {
			invarg("unknown", *argv);
		}

		argc--; argv++;
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Beispiel #5
0
static int xfrm_state_allocspi(int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct xfrm_userspi_info xspi;
		char   			buf[RTA_BUF_SIZE];
	} req;
	char *idp = NULL;
	char *minp = NULL;
	char *maxp = NULL;
	char res_buf[NLMSG_BUF_SIZE];
	struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;

	memset(res_buf, 0, sizeof(res_buf));

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
	req.xspi.info.family = preferred_family;

#if 0
	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
	req.xsinfo.lft.hard_packet_limit = XFRM_INF;
#endif

	while (argc > 0) {
		if (strcmp(*argv, "mode") == 0) {
			NEXT_ARG();
			xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
		} else if (strcmp(*argv, "reqid") == 0) {
			NEXT_ARG();
			xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
		} else if (strcmp(*argv, "seq") == 0) {
			NEXT_ARG();
			xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
		} else if (strcmp(*argv, "min") == 0) {
			if (minp)
				duparg("min", *argv);
			minp = *argv;

			NEXT_ARG();

			if (get_u32(&req.xspi.min, *argv, 0))
				invarg("\"min\" value is invalid", *argv);
		} else if (strcmp(*argv, "max") == 0) {
			if (maxp)
				duparg("max", *argv);
			maxp = *argv;

			NEXT_ARG();

			if (get_u32(&req.xspi.max, *argv, 0))
				invarg("\"max\" value is invalid", *argv);
		} else {
			/* try to assume ID */
			if (idp)
				invarg("unknown", *argv);
			idp = *argv;

			/* ID */
			xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
				      &req.xspi.info.family, 0, &argc, &argv);
			if (req.xspi.info.id.spi) {
				fprintf(stderr, "\"SPI\" must be zero\n");
				exit(1);
			}
			if (preferred_family == AF_UNSPEC)
				preferred_family = req.xspi.info.family;
		}
		argc--; argv++;
	}

	if (!idp) {
		fprintf(stderr, "Not enough information: \"ID\" is required\n");
		exit(1);
	}

	if (minp) {
		if (!maxp) {
			fprintf(stderr, "\"max\" is missing\n");
			exit(1);
		}
		if (req.xspi.min > req.xspi.max) {
			fprintf(stderr, "\"min\" valie is larger than \"max\" one\n");
			exit(1);
		}
	} else {
		if (maxp) {
			fprintf(stderr, "\"min\" is missing\n");
			exit(1);
		}

		/* XXX: Default value defined in PF_KEY;
		 * See kernel's net/key/af_key.c(pfkey_getspi).
		 */
		req.xspi.min = 0x100;
		req.xspi.max = 0x0fffffff;

		/* XXX: IPCOMP spi is 16-bits;
		 * See kernel's net/xfrm/xfrm_user(verify_userspi_info).
		 */
		if (req.xspi.info.id.proto == IPPROTO_COMP)
			req.xspi.max = 0xffff;
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xspi.info.family == AF_UNSPEC)
		req.xspi.info.family = AF_INET;


	if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
		exit(2);

	if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
		fprintf(stderr, "An error :-)\n");
		exit(1);
	}

	rtnl_close(&rth);

	return 0;
}
Beispiel #6
0
static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct ndmsg 		ndm;
		char   			buf[256];
	} req;
	char  *d = NULL;
	int dst_ok = 0;
	int lladdr_ok = 0;
	char * lla = NULL;
	inet_prefix dst;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.ndm.ndm_family = preferred_family;
	req.ndm.ndm_state = NUD_PERMANENT;

	while (argc > 0) {
		if (matches(*argv, "lladdr") == 0) {
			NEXT_ARG();
			if (lladdr_ok)
				duparg("lladdr", *argv);
			lla = *argv;
			lladdr_ok = 1;
		} else if (strcmp(*argv, "nud") == 0) {
			unsigned state;
			NEXT_ARG();
			if (nud_state_a2n(&state, *argv))
				invarg("nud state is bad", *argv);
			req.ndm.ndm_state = state;
		} else if (matches(*argv, "proxy") == 0) {
			NEXT_ARG();
			if (matches(*argv, "help") == 0)
				usage();
			if (dst_ok)
				duparg("address", *argv);
			get_addr(&dst, *argv, preferred_family);
			dst_ok = 1;
			req.ndm.ndm_flags |= NTF_PROXY;
		} else if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			d = *argv;
		} else {
			if (strcmp(*argv, "to") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0) {
				NEXT_ARG();
			}
			if (dst_ok)
				duparg2("to", *argv);
			get_addr(&dst, *argv, preferred_family);
			dst_ok = 1;
		}
		argc--; argv++;
	}
	if (d == NULL || !dst_ok || dst.family == AF_UNSPEC) {
		fprintf(stderr, "Device and destination are required arguments.\n");
		exit(-1);
	}
	req.ndm.ndm_family = dst.family;
	addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);

	if (lla && strcmp(lla, "null")) {
		__u8 llabuf[16];
		int l;

		l = ll_addr_a2n(llabuf, sizeof(llabuf), lla);
		addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l);
	}

	if (rtnl_open(&rth, 0) < 0)
		exit(1);

	ll_init_map(&rth);

	if ((req.ndm.ndm_ifindex = ll_name_to_index(d)) == 0) {
		fprintf(stderr, "Cannot find device \"%s\"\n", d);
		return -1;
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	exit(0);
}
Beispiel #7
0
static int
parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
		int tca_id, struct nlmsghdr *n)
{

	int argc = *argc_p;
	char **argv = *argv_p;
	int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
	struct tc_mirred p = {};
	struct rtattr *tail;
	char d[IFNAMSIZ] = {};

	while (argc > 0) {

		if (matches(*argv, "action") == 0) {
			NEXT_ARG();
			break;
		} else if (!egress && matches(*argv, "egress") == 0) {
			egress = 1;
			if (ingress) {
				fprintf(stderr,
					"Can't have both egress and ingress\n");
				return -1;
			}
			NEXT_ARG();
			ok++;
			continue;
		} else if (!ingress && matches(*argv, "ingress") == 0) {
			ingress = 1;
			if (egress) {
				fprintf(stderr,
					"Can't have both ingress and egress\n");
				return -1;
			}
			NEXT_ARG();
			ok++;
			continue;
		} else {

			if (matches(*argv, "index") == 0) {
				NEXT_ARG();
				if (get_u32(&p.index, *argv, 10)) {
					fprintf(stderr, "Illegal \"index\"\n");
					return -1;
				}
				iok++;
				if (!ok) {
					argc--;
					argv++;
					break;
				}
			} else if (!ok) {
				fprintf(stderr,
					"was expecting egress or ingress (%s)\n",
					*argv);
				break;

			} else if (!mirror && matches(*argv, "mirror") == 0) {
				mirror = 1;
				if (redir) {
					fprintf(stderr,
						"Can't have both mirror and redir\n");
					return -1;
				}
				p.eaction = egress ? TCA_EGRESS_MIRROR :
					TCA_INGRESS_MIRROR;
				p.action = TC_ACT_PIPE;
				ok++;
			} else if (!redir && matches(*argv, "redirect") == 0) {
				redir = 1;
				if (mirror) {
					fprintf(stderr,
						"Can't have both mirror and redir\n");
					return -1;
				}
				p.eaction = egress ? TCA_EGRESS_REDIR :
					TCA_INGRESS_REDIR;
				p.action = TC_ACT_STOLEN;
				ok++;
			} else if ((redir || mirror) &&
				   matches(*argv, "dev") == 0) {
				NEXT_ARG();
				if (strlen(d))
					duparg("dev", *argv);

				strncpy(d, *argv, sizeof(d)-1);
				argc--;
				argv++;

				break;

			}
		}

		NEXT_ARG();
	}

	if (!ok && !iok)
		return -1;

	if (d[0])  {
		int idx;

		ll_init_map(&rth);

		idx = ll_name_to_index(d);
		if (!idx)
			return nodev(d);

		p.ifindex = idx;
	}


	if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
		parse_action_control(&argc, &argv, &p.action, false);

	if (argc) {
		if (iok && matches(*argv, "index") == 0) {
			fprintf(stderr, "mirred: Illegal double index\n");
			return -1;
		}

		if (matches(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&p.index, *argv, 10)) {
				fprintf(stderr,
					"mirred: Illegal \"index\"\n");
				return -1;
			}
			argc--;
			argv++;
		}
	}

	tail = addattr_nest(n, MAX_MSG, tca_id);
	addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
	addattr_nest_end(n, tail);

	*argc_p = argc;
	*argv_p = argv;
	return 0;
}
int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp)
{
	char **argv = *argvp;
	int argc = *argcp;
	struct tc_sizespec s;

	memset(&s, 0, sizeof(s));

	NEXT_ARG();
	if (matches(*argv, "help") == 0) {
		stab_help();
		return -1;
	}
	while (argc > 0) {
		if (matches(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (s.mtu)
				duparg("mtu", *argv);
			if (get_u32(&s.mtu, *argv, 10)) {
				invarg("mtu", "invalid mtu");
				return -1;
			}
		} else if (matches(*argv, "mpu") == 0) {
			NEXT_ARG();
			if (s.mpu)
				duparg("mpu", *argv);
			if (get_u32(&s.mpu, *argv, 10)) {
				invarg("mpu", "invalid mpu");
				return -1;
			}
		} else if (matches(*argv, "overhead") == 0) {
			NEXT_ARG();
			if (s.overhead)
				duparg("overhead", *argv);
			if (get_integer(&s.overhead, *argv, 10)) {
				invarg("overhead", "invalid overhead");
				return -1;
			}
		} else if (matches(*argv, "tsize") == 0) {
			NEXT_ARG();
			if (s.tsize)
				duparg("tsize", *argv);
			if (get_u32(&s.tsize, *argv, 10)) {
				invarg("tsize", "invalid table size");
				return -1;
			}
		} else if (matches(*argv, "linklayer") == 0) {
			NEXT_ARG();
			if (s.linklayer != LINKLAYER_UNSPEC)
				duparg("linklayer", *argv);
			if (get_linklayer(&s.linklayer, *argv)) {
				invarg("linklayer", "invalid linklayer");
				return -1;
			}
		} else
			break;
		argc--; argv++;
	}

	if (!check_size_table_opts(&s))
		return -1;

	*sp = s;
	*argvp = argv;
	*argcp = argc;
	return 0;
}
Beispiel #9
0
static int ipntable_modify(int cmd, int flags, int argc, char **argv)
{
	struct {
		struct nlmsghdr	n;
		struct ndtmsg		ndtm;
		char			buf[1024];
	} req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
		.n.nlmsg_flags = NLM_F_REQUEST | flags,
		.n.nlmsg_type = cmd,
		.ndtm.ndtm_family = preferred_family,
	};
	char *namep = NULL;
	char *threshsp = NULL;
	char *gc_intp = NULL;
	char parms_buf[1024] = {};
	struct rtattr *parms_rta = (struct rtattr *)parms_buf;
	int parms_change = 0;

	parms_rta->rta_type = NDTA_PARMS;
	parms_rta->rta_len = RTA_LENGTH(0);

	while (argc > 0) {
		if (strcmp(*argv, "name") == 0) {
			int len;

			NEXT_ARG();
			if (namep)
				duparg("NAME", *argv);

			namep = *argv;
			len = strlen(namep) + 1;
			addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len);
		} else if (strcmp(*argv, "thresh1") == 0) {
			__u32 thresh1;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh1, *argv, 0))
				invarg("\"thresh1\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1);
		} else if (strcmp(*argv, "thresh2") == 0) {
			__u32 thresh2;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh2, *argv, 0))
				invarg("\"thresh2\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2);
		} else if (strcmp(*argv, "thresh3") == 0) {
			__u32 thresh3;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh3, *argv, 0))
				invarg("\"thresh3\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3);
		} else if (strcmp(*argv, "gc_int") == 0) {
			__u64 gc_int;

			NEXT_ARG();
			gc_intp = *argv;

			if (get_u64(&gc_int, *argv, 0))
				invarg("\"gc_int\" value is invalid", *argv);

			addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL,
				  &gc_int, sizeof(gc_int));
		} else if (strcmp(*argv, "dev") == 0) {
			__u32 ifindex;

			NEXT_ARG();
			ifindex = ll_name_to_index(*argv);
			if (!ifindex)
				return nodev(*argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_IFINDEX, ifindex);
		} else if (strcmp(*argv, "base_reachable") == 0) {
			__u64 breachable;

			NEXT_ARG();

			if (get_u64(&breachable, *argv, 0))
				invarg("\"base_reachable\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_BASE_REACHABLE_TIME,
				      &breachable, sizeof(breachable));
			parms_change = 1;
		} else if (strcmp(*argv, "retrans") == 0) {
			__u64 retrans;

			NEXT_ARG();

			if (get_u64(&retrans, *argv, 0))
				invarg("\"retrans\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_RETRANS_TIME,
				      &retrans, sizeof(retrans));
			parms_change = 1;
		} else if (strcmp(*argv, "gc_stale") == 0) {
			__u64 gc_stale;

			NEXT_ARG();

			if (get_u64(&gc_stale, *argv, 0))
				invarg("\"gc_stale\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_GC_STALETIME,
				      &gc_stale, sizeof(gc_stale));
			parms_change = 1;
		} else if (strcmp(*argv, "delay_probe") == 0) {
			__u64 delay_probe;

			NEXT_ARG();

			if (get_u64(&delay_probe, *argv, 0))
				invarg("\"delay_probe\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_DELAY_PROBE_TIME,
				      &delay_probe, sizeof(delay_probe));
			parms_change = 1;
		} else if (strcmp(*argv, "queue") == 0) {
			__u32 queue;

			NEXT_ARG();

			if (get_u32(&queue, *argv, 0))
				invarg("\"queue\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_QUEUE_LEN, queue);
			parms_change = 1;
		} else if (strcmp(*argv, "app_probes") == 0) {
			__u32 aprobe;

			NEXT_ARG();

			if (get_u32(&aprobe, *argv, 0))
				invarg("\"app_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_APP_PROBES, aprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "ucast_probes") == 0) {
			__u32 uprobe;

			NEXT_ARG();

			if (get_u32(&uprobe, *argv, 0))
				invarg("\"ucast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_UCAST_PROBES, uprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "mcast_probes") == 0) {
			__u32 mprobe;

			NEXT_ARG();

			if (get_u32(&mprobe, *argv, 0))
				invarg("\"mcast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_MCAST_PROBES, mprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "anycast_delay") == 0) {
			__u64 anycast_delay;

			NEXT_ARG();

			if (get_u64(&anycast_delay, *argv, 0))
				invarg("\"anycast_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_ANYCAST_DELAY,
				      &anycast_delay, sizeof(anycast_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_delay") == 0) {
			__u64 proxy_delay;

			NEXT_ARG();

			if (get_u64(&proxy_delay, *argv, 0))
				invarg("\"proxy_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_DELAY,
				      &proxy_delay, sizeof(proxy_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_queue") == 0) {
			__u32 pqueue;

			NEXT_ARG();

			if (get_u32(&pqueue, *argv, 0))
				invarg("\"proxy_queue\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_QLEN, pqueue);
			parms_change = 1;
		} else if (strcmp(*argv, "locktime") == 0) {
			__u64 locktime;

			NEXT_ARG();

			if (get_u64(&locktime, *argv, 0))
				invarg("\"locktime\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_LOCKTIME,
				      &locktime, sizeof(locktime));
			parms_change = 1;
		} else {
			invarg("unknown", *argv);
		}

		argc--; argv++;
	}

	if (!namep)
		missarg("NAME");
	if (!threshsp && !gc_intp && !parms_change) {
		fprintf(stderr, "Not enough information: changeable attributes required.\n");
		exit(-1);
	}

	if (parms_rta->rta_len > RTA_LENGTH(0)) {
		addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta),
			  RTA_PAYLOAD(parms_rta));
	}

	if (rtnl_talk(&rth, &req.n, NULL) < 0)
		exit(2);

	return 0;
}

static const char *ntable_strtime_delta(__u32 msec)
{
	static char str[32];
	struct timeval now = {};
	time_t t;
	struct tm *tp;

	if (msec == 0)
		goto error;

	if (gettimeofday(&now, NULL) < 0) {
		perror("gettimeofday");
		goto error;
	}

	t = now.tv_sec - (msec / 1000);
	tp = localtime(&t);
	if (!tp)
		goto error;

	strftime(str, sizeof(str), "%Y-%m-%d %T", tp);

	return str;
 error:
	strcpy(str, "(error)");
	return str;
}

static void print_ndtconfig(const struct ndt_config *ndtc)
{

	print_uint(PRINT_ANY, "key_length",
		   "    config key_len %u ", ndtc->ndtc_key_len);
	print_uint(PRINT_ANY, "entry_size",
		   "entry_size %u ", ndtc->ndtc_entry_size);
	print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries);

	print_nl();

	print_string(PRINT_ANY, "last_flush",
		     "        last_flush %s ",
		     ntable_strtime_delta(ndtc->ndtc_last_flush));
	print_string(PRINT_ANY, "last_rand",
		     "last_rand %s ",
		     ntable_strtime_delta(ndtc->ndtc_last_rand));

	print_nl();

	print_uint(PRINT_ANY, "hash_rnd",
		   "        hash_rnd %u ", ndtc->ndtc_hash_rnd);
	print_0xhex(PRINT_ANY, "hash_mask",
		    "hash_mask %08llx ", ndtc->ndtc_hash_mask);

	print_uint(PRINT_ANY, "hash_chain_gc",
		   "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
	print_uint(PRINT_ANY, "proxy_qlen",
		   "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);

	print_nl();
}
int ipaddr_modify(int cmd, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct ifaddrmsg 	ifa;
		char   			buf[256];
	} req;
	char  *d = NULL;
	char  *l = NULL;
	char  *valid_lftp = NULL;
	char  *preferred_lftp = NULL;
	inet_prefix lcl;
	inet_prefix peer;
	int local_len = 0;
	int peer_len = 0;
	int brd_len = 0;
	int any_len = 0;
	int scoped = 0;
	__u32 preferred_lft = INFINITY_LIFE_TIME;
	__u32 valid_lft = INFINITY_LIFE_TIME;
	struct ifa_cacheinfo cinfo;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = cmd;
	req.ifa.ifa_family = preferred_family;

	while (argc > 0) {
		if (strcmp(*argv, "peer") == 0 ||
		    strcmp(*argv, "remote") == 0) {
			NEXT_ARG();

			if (peer_len)
				duparg("peer", *argv);
			get_prefix(&peer, *argv, req.ifa.ifa_family);
			peer_len = peer.bytelen;
			if (req.ifa.ifa_family == AF_UNSPEC)
				req.ifa.ifa_family = peer.family;
			addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
			req.ifa.ifa_prefixlen = peer.bitlen;
		} else if (matches(*argv, "broadcast") == 0 ||
			   strcmp(*argv, "brd") == 0) {
			inet_prefix addr;
			NEXT_ARG();
			if (brd_len)
				duparg("broadcast", *argv);
			if (strcmp(*argv, "+") == 0)
				brd_len = -1;
			else if (strcmp(*argv, "-") == 0)
				brd_len = -2;
			else {
				get_addr(&addr, *argv, req.ifa.ifa_family);
				if (req.ifa.ifa_family == AF_UNSPEC)
					req.ifa.ifa_family = addr.family;
				addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
				brd_len = addr.bytelen;
			}
		} else if (strcmp(*argv, "anycast") == 0) {
			inet_prefix addr;
			NEXT_ARG();
			if (any_len)
				duparg("anycast", *argv);
			get_addr(&addr, *argv, req.ifa.ifa_family);
			if (req.ifa.ifa_family == AF_UNSPEC)
				req.ifa.ifa_family = addr.family;
			addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
			any_len = addr.bytelen;
		} else if (strcmp(*argv, "scope") == 0) {
			int scope = 0;
			NEXT_ARG();
			if (rtnl_rtscope_a2n(&scope, *argv))
				invarg(*argv, "invalid scope value.");
			req.ifa.ifa_scope = scope;
			scoped = 1;
		} else if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			d = *argv;
		} else if (strcmp(*argv, "label") == 0) {
			NEXT_ARG();
			l = *argv;
			addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
		} else if (matches(*argv, "valid_lft") == 0) {
			if (valid_lftp)
				duparg("valid_lft", *argv);
			NEXT_ARG();
			valid_lftp = *argv;
			if (set_lifetime(&valid_lft, *argv))
				invarg("valid_lft value", *argv);
		} else if (matches(*argv, "preferred_lft") == 0) {
			if (preferred_lftp)
				duparg("preferred_lft", *argv);
			NEXT_ARG();
			preferred_lftp = *argv;
			if (set_lifetime(&preferred_lft, *argv))
				invarg("preferred_lft value", *argv);
		} else {
			if (strcmp(*argv, "local") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (local_len)
				duparg2("local", *argv);
			get_prefix(&lcl, *argv, req.ifa.ifa_family);
			if (req.ifa.ifa_family == AF_UNSPEC)
				req.ifa.ifa_family = lcl.family;
			addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
			local_len = lcl.bytelen;
		}
		argc--; argv++;
	}
	if (d == NULL) {
		fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
		return -1;
	}
	if (l && matches(d, l) != 0) {
		fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l);
		exit(1);
	}

	if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
		peer = lcl;
		addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
	}
	if (req.ifa.ifa_prefixlen == 0)
		req.ifa.ifa_prefixlen = lcl.bitlen;

	if (brd_len < 0 && cmd != RTM_DELADDR) {
		inet_prefix brd;
		int i;
		if (req.ifa.ifa_family != AF_INET) {
			fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n");
			return -1;
		}
		brd = peer;
		if (brd.bitlen <= 30) {
			for (i=31; i>=brd.bitlen; i--) {
				if (brd_len == -1)
					brd.data[0] |= htonl(1<<(31-i));
				else
					brd.data[0] &= ~htonl(1<<(31-i));
			}
			addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
			brd_len = brd.bytelen;
		}
	}
	if (!scoped && cmd != RTM_DELADDR)
		req.ifa.ifa_scope = default_scope(&lcl);

	if (rtnl_open(&rth, 0) < 0)
		exit(1);

	ll_init_map(&rth);

	if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
		fprintf(stderr, "Cannot find device \"%s\"\n", d);
		return -1;
	}

	if (valid_lftp || preferred_lftp) {
		if (!valid_lft) {
			fprintf(stderr, "valid_lft is zero\n");
			return -1;
		}
		if (valid_lft < preferred_lft) {
			fprintf(stderr, "preferred_lft is greater than valid_lft\n");
			return -1;
		}

		memset(&cinfo, 0, sizeof(cinfo));
		cinfo.ifa_prefered = preferred_lft;
		cinfo.ifa_valid = valid_lft;
		addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo,
			  sizeof(cinfo));
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	exit(0);
}
Beispiel #11
0
static int do_set(int argc, char **argv)
{
	char *dev = NULL;
	__u32 mask = 0;
	__u32 flags = 0;
	int qlen = -1;
	int mtu = -1;
	char *newaddr = NULL;
	char *newbrd = NULL;
	struct ifreq ifr0, ifr1;
	char *newname = NULL;
	int htype, halen;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			mask |= IFF_UP;
			flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			newname = *argv;
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			mask |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast");
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			mask |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				flags |= IFF_NOARP;
			} else
				return on_off("noarp");
		} else if (strcmp(*argv, "addr") == 0) {
			NEXT_ARG();
			newaddr = *argv;
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		}
		argc--; argv++;
	}

	if (!dev) {
		bb_error_msg("Not enough of information: \"dev\" argument is required.");
		exit(-1);
	}

	if (newaddr || newbrd) {
		halen = get_address(dev, &htype);
		if (halen < 0)
			return -1;
		if (newaddr) {
			if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
				return -1;
		}
		if (newbrd) {
			if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
				return -1;
		}
	}

	if (newname && strcmp(dev, newname)) {
		if (do_changename(dev, newname) < 0)
			return -1;
		dev = newname;
	}
	if (qlen != -1) {
		if (set_qlen(dev, qlen) < 0)
			return -1;
	}
	if (mtu != -1) {
		if (set_mtu(dev, mtu) < 0)
			return -1;
	}
	if (newaddr || newbrd) {
		if (newbrd) {
			if (set_address(&ifr1, 1) < 0)
				return -1;
		}
		if (newaddr) {
			if (set_address(&ifr0, 0) < 0)
				return -1;
		}
	}
	if (mask)
		return do_chflags(dev, flags, mask);
	return 0;
}
Beispiel #12
0
int iplink_parse(int argc, char **argv, struct iplink_req *req,
		char **name, char **type, char **link, char **dev)
{
	int ret, len;
	char abuf[32];
	int qlen = -1;
	int mtu = -1;
	int netns = -1;

	ret = argc;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			*name = *argv;
		} else if (matches(*argv, "link") == 0) {
			NEXT_ARG();
			*link = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
		} else if (matches(*argv, "broadcast") == 0 ||
				strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
		} else if (matches(*argv, "txqueuelen") == 0 ||
				strcmp(*argv, "qlen") == 0 ||
				matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
                } else if (strcmp(*argv, "netns") == 0) {
                        NEXT_ARG();
                        if (netns != -1)
                                duparg("netns", *argv);
                        if (get_integer(&netns, *argv, 0))
                                invarg("Invalid \"netns\" value\n", *argv);
                        addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast");
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast");
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc");
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers");
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOARP;
			} else
				return on_off("noarp");
#ifdef IFF_DYNAMIC
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic");
#endif
		} else if (matches(*argv, "type") == 0) {
			NEXT_ARG();
			*type = *argv;
			argc--; argv++;
			break;
		} else if (matches(*argv, "alias") == 0) {
			NEXT_ARG();
			addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
				  *argv, strlen(*argv));
			argc--; argv++;
			break;
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (*dev)
				duparg2("dev", *argv);
			*dev = *argv;
		}
		argc--; argv++;
	}

	return ret - argc;
}
Beispiel #13
0
int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct qdisc_util *q = NULL;
	struct tc_estimator est;
	char  d[16];
	char  k[16];
	struct {
		struct nlmsghdr 	n;
		struct tcmsg 		t;
		char   			buf[TCA_BUF_MAX];
	} req;

	memset(&req, 0, sizeof(req));
	memset(&est, 0, sizeof(est));
	memset(&d, 0, sizeof(d));
	memset(&k, 0, sizeof(k));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.t.tcm_family = AF_UNSPEC;

	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			if (d[0])
				duparg("dev", *argv);
			strncpy(d, *argv, sizeof(d)-1);
		} else if (strcmp(*argv, "handle") == 0) {
			__u32 handle;
			if (req.t.tcm_handle)
				duparg("handle", *argv);
			NEXT_ARG();
			if (get_qdisc_handle(&handle, *argv))
				invarg(*argv, "invalid qdisc ID");
			req.t.tcm_handle = handle;
		} else if (strcmp(*argv, "root") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_ROOT;
#ifdef TC_H_INGRESS
		} else if (strcmp(*argv, "ingress") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_INGRESS;
			strncpy(k, "ingress", sizeof(k)-1);
			q = get_qdisc_kind(k);
			req.t.tcm_handle = 0xffff0000;

			argc--; argv++;
			break;
#endif
		} else if (strcmp(*argv, "parent") == 0) {
			__u32 handle;
			NEXT_ARG();
			if (req.t.tcm_parent)
				duparg("parent", *argv);
			if (get_tc_classid(&handle, *argv))
				invarg(*argv, "invalid parent ID");
			req.t.tcm_parent = handle;
		} else if (matches(*argv, "estimator") == 0) {
			if (parse_estimator(&argc, &argv, &est))
				return -1;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else {
			strncpy(k, *argv, sizeof(k)-1);

			q = get_qdisc_kind(k);
			argc--; argv++;
			break;
		}
		argc--; argv++;
	}

	if (k[0])
		addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
	if (est.ewma_log)
		addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));

	if (q) {
		if (!q->parse_qopt) {
			fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
			return -1;
		}
		if (q->parse_qopt(q, argc, argv, &req.n))
			return 1;
	} else {
		if (argc) {
			if (matches(*argv, "help") == 0)
				usage();

			fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv);
			return -1;
		}
	}

	if (d[0])  {
		int idx;

 		ll_init_map(&rth);

		if ((idx = ll_name_to_index(d)) == 0) {
			fprintf(stderr, "Cannot find device \"%s\"\n", d);
			return 1;
		}
		req.t.tcm_ifindex = idx;
	}

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

	return 0;
}
Beispiel #14
0
int ipaddr_modify(int cmd, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct ifaddrmsg 	ifa;
		char   			buf[256];
	} req;
	char  *d = NULL;
	char  *l = NULL;
	char  *lcl_arg = NULL;
	inet_prefix lcl;
	inet_prefix peer;
	int local_len = 0;
	int peer_len = 0;
	int brd_len = 0;
	int any_len = 0;
	int scoped = 0;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = cmd;
	req.ifa.ifa_family = preferred_family;

	while (argc > 0) {
		if (strcmp(*argv, "peer") == 0 ||
		    strcmp(*argv, "remote") == 0) {
			NEXT_ARG();

			if (peer_len)
				duparg("peer", *argv);
			get_prefix(&peer, *argv, req.ifa.ifa_family);
			peer_len = peer.bytelen;
			if (req.ifa.ifa_family == AF_UNSPEC)
				req.ifa.ifa_family = peer.family;
			addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
			req.ifa.ifa_prefixlen = peer.bitlen;
		} else if (matches(*argv, "broadcast") == 0 ||
			   strcmp(*argv, "brd") == 0) {
			inet_prefix addr;
			NEXT_ARG();
			if (brd_len)
				duparg("broadcast", *argv);
			if (strcmp(*argv, "+") == 0)
				brd_len = -1;
			else if (strcmp(*argv, "-") == 0)
				brd_len = -2;
			else {
				get_addr(&addr, *argv, req.ifa.ifa_family);
				if (req.ifa.ifa_family == AF_UNSPEC)
					req.ifa.ifa_family = addr.family;
				addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
				brd_len = addr.bytelen;
			}
		} else if (strcmp(*argv, "anycast") == 0) {
			inet_prefix addr;
			NEXT_ARG();
			if (any_len)
				duparg("anycast", *argv);
			get_addr(&addr, *argv, req.ifa.ifa_family);
			if (req.ifa.ifa_family == AF_UNSPEC)
				req.ifa.ifa_family = addr.family;
			addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
			any_len = addr.bytelen;
		} else if (strcmp(*argv, "scope") == 0) {
			int scope = 0;
			NEXT_ARG();
			if (rtnl_rtscope_a2n(&scope, *argv))
				invarg(*argv, "invalid scope value.");
			req.ifa.ifa_scope = scope;
			scoped = 1;
		} else if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			d = *argv;
		} else if (strcmp(*argv, "label") == 0) {
			NEXT_ARG();
			l = *argv;
			addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
		} else {
			if (strcmp(*argv, "local") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (local_len)
				duparg2("local", *argv);
			lcl_arg = *argv;
			get_prefix(&lcl, *argv, req.ifa.ifa_family);
			if (req.ifa.ifa_family == AF_UNSPEC)
				req.ifa.ifa_family = lcl.family;
			addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
			local_len = lcl.bytelen;
		}
		argc--; argv++;
	}
	if (d == NULL) {
		fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
		return -1;
	}
	if (l && matches(d, l) != 0) {
		fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l);
		exit(1);
	}

	if (peer_len == 0 && local_len) {
		if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) {
			fprintf(stderr,
			    "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \
			    "         Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \
			    "         This special behaviour is likely to disappear in further releases,\n" \
			    "         fix your scripts!\n", lcl_arg, local_len*8);
		} else {
			peer = lcl;
			addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
		}
	}
	if (req.ifa.ifa_prefixlen == 0)
		req.ifa.ifa_prefixlen = lcl.bitlen;

	if (brd_len < 0 && cmd != RTM_DELADDR) {
		inet_prefix brd;
		int i;
		if (req.ifa.ifa_family != AF_INET) {
			fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n");
			return -1;
		}
		brd = peer;
		if (brd.bitlen <= 30) {
			for (i=31; i>=brd.bitlen; i--) {
				if (brd_len == -1)
					brd.data[0] |= htonl(1<<(31-i));
				else
					brd.data[0] &= ~htonl(1<<(31-i));
			}
			addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
			brd_len = brd.bytelen;
		}
	}
	if (!scoped && cmd != RTM_DELADDR)
		req.ifa.ifa_scope = default_scope(&lcl);

	if (rtnl_open(&rth, 0) < 0)
		exit(1);

	ll_init_map(&rth);

	if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
		fprintf(stderr, "Cannot find device \"%s\"\n", d);
		return -1;
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	exit(0);
}
Beispiel #15
0
/* Return value becomes exitcode. It's okay to not return at all */
static int do_add_or_delete(char **argv, const unsigned rtm)
{
	static const char keywords[] ALIGN1 =
		"link\0""name\0""type\0""dev\0""address\0";
	enum {
		ARG_link,
		ARG_name,
		ARG_type,
		ARG_dev,
		ARG_address,
	};
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr  n;
		struct ifinfomsg i;
		char             buf[1024];
	} req;
	smalluint arg;
	char *name_str = NULL;
	char *link_str = NULL;
	char *type_str = NULL;
	char *dev_str = NULL;
	char *address_str = NULL;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = rtm;
	req.i.ifi_family = preferred_family;
	if (rtm == RTM_NEWLINK)
		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;

	while (*argv) {
		arg = index_in_substrings(keywords, *argv);
		if (arg == ARG_type) {
			NEXT_ARG();
			type_str = *argv++;
			dbg("type_str:'%s'", type_str);
			break;
		}
		if (arg == ARG_link) {
			NEXT_ARG();
			link_str = *argv;
			dbg("link_str:'%s'", link_str);
		} else if (arg == ARG_name) {
			NEXT_ARG();
			name_str = *argv;
			dbg("name_str:'%s'", name_str);
		} else if (arg == ARG_address) {
			NEXT_ARG();
			address_str = *argv;
			dbg("address_str:'%s'", name_str);
		} else {
			if (arg == ARG_dev) {
				if (dev_str)
					duparg(*argv, "dev");
				NEXT_ARG();
			}
			dev_str = *argv;
			dbg("dev_str:'%s'", dev_str);
		}
		argv++;
	}
	xrtnl_open(&rth);
	ll_init_map(&rth);
	if (type_str) {
		struct rtattr *linkinfo = NLMSG_TAIL(&req.n);

		addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
		addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
				strlen(type_str));

		if (*argv) {
			struct rtattr *data = NLMSG_TAIL(&req.n);
			addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);

			if (strcmp(type_str, "vlan") == 0)
				vlan_parse_opt(argv, &req.n, sizeof(req));

			data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
		}

		linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
	}
	if (rtm != RTM_NEWLINK) {
		if (!dev_str)
			return 1; /* Need a device to delete */
		req.i.ifi_index = xll_name_to_index(dev_str);
	} else {
		if (!name_str)
			name_str = dev_str;
		if (link_str) {
			int idx = xll_name_to_index(link_str);
			addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
		}
		if (address_str) {
			unsigned char abuf[32];
			int len = ll_addr_a2n(abuf, sizeof(abuf), address_str);
			dbg("address len:%d", len);
			if (len < 0)
				return -1;
			addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
		}
	}
	if (name_str) {
		const size_t name_len = strlen(name_str) + 1;
		if (name_len < 2 || name_len > IFNAMSIZ)
			invarg_1_to_2(name_str, "name");
		addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len);
	}
	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		return 2;
	return 0;
}
Beispiel #16
0
static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr	n;
		struct xfrm_usersa_info xsinfo;
		char  			buf[RTA_BUF_SIZE];
	} req;
	struct xfrm_replay_state replay;
	struct xfrm_replay_state_esn replay_esn;
	__u32 replay_window = 0;
	__u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0;
	char *idp = NULL;
	char *aeadop = NULL;
	char *ealgop = NULL;
	char *aalgop = NULL;
	char *calgop = NULL;
	char *coap = NULL;
	char *sctxp = NULL;
	__u32 extra_flags = 0;
	struct xfrm_mark mark = {0, 0};
	struct {
		struct xfrm_user_sec_ctx sctx;
		char    str[CTX_BUF_SIZE];
	} ctx;

	memset(&req, 0, sizeof(req));
	memset(&replay, 0, sizeof(replay));
	memset(&replay_esn, 0, sizeof(replay_esn));
	memset(&ctx, 0, sizeof(ctx));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.xsinfo.family = preferred_family;

	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
	req.xsinfo.lft.hard_packet_limit = XFRM_INF;

	while (argc > 0) {
		if (strcmp(*argv, "mode") == 0) {
			NEXT_ARG();
			xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
		} else if (strcmp(*argv, "mark") == 0) {
			xfrm_parse_mark(&mark, &argc, &argv);
		} else if (strcmp(*argv, "reqid") == 0) {
			NEXT_ARG();
			xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
		} else if (strcmp(*argv, "seq") == 0) {
			NEXT_ARG();
			xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
		} else if (strcmp(*argv, "replay-window") == 0) {
			NEXT_ARG();
			if (get_u32(&replay_window, *argv, 0))
				invarg("value after \"replay-window\" is invalid", *argv);
		} else if (strcmp(*argv, "replay-seq") == 0) {
			NEXT_ARG();
			if (get_u32(&seq, *argv, 0))
				invarg("value after \"replay-seq\" is invalid", *argv);
		} else if (strcmp(*argv, "replay-seq-hi") == 0) {
			NEXT_ARG();
			if (get_u32(&seq_hi, *argv, 0))
				invarg("value after \"replay-seq-hi\" is invalid", *argv);
		} else if (strcmp(*argv, "replay-oseq") == 0) {
			NEXT_ARG();
			if (get_u32(&oseq, *argv, 0))
				invarg("value after \"replay-oseq\" is invalid", *argv);
		} else if (strcmp(*argv, "replay-oseq-hi") == 0) {
			NEXT_ARG();
			if (get_u32(&oseq_hi, *argv, 0))
				invarg("value after \"replay-oseq-hi\" is invalid", *argv);
		} else if (strcmp(*argv, "flag") == 0) {
			NEXT_ARG();
			xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
		} else if (strcmp(*argv, "extra-flag") == 0) {
			NEXT_ARG();
			xfrm_state_extra_flag_parse(&extra_flags, &argc, &argv);
		} else if (strcmp(*argv, "sel") == 0) {
			NEXT_ARG();
			preferred_family = AF_UNSPEC;
			xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
			preferred_family = req.xsinfo.sel.family;
		} else if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
		} else if (strcmp(*argv, "encap") == 0) {
			struct xfrm_encap_tmpl encap;
			inet_prefix oa;
		        NEXT_ARG();
			xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
			NEXT_ARG();
			if (get_u16(&encap.encap_sport, *argv, 0))
				invarg("SPORT value after \"encap\" is invalid", *argv);
			encap.encap_sport = htons(encap.encap_sport);
			NEXT_ARG();
			if (get_u16(&encap.encap_dport, *argv, 0))
				invarg("DPORT value after \"encap\" is invalid", *argv);
			encap.encap_dport = htons(encap.encap_dport);
			NEXT_ARG();
			get_addr(&oa, *argv, AF_UNSPEC);
			memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
			addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
				  (void *)&encap, sizeof(encap));
		} else if (strcmp(*argv, "coa") == 0) {
			inet_prefix coa;
			xfrm_address_t xcoa;

			if (coap)
				duparg("coa", *argv);
			coap = *argv;

			NEXT_ARG();

			get_prefix(&coa, *argv, preferred_family);
			if (coa.family == AF_UNSPEC)
				invarg("value after \"coa\" has an unrecognized address family", *argv);
			if (coa.bytelen > sizeof(xcoa))
				invarg("value after \"coa\" is too large", *argv);

			memset(&xcoa, 0, sizeof(xcoa));
			memcpy(&xcoa, &coa.data, coa.bytelen);

			addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
				  (void *)&xcoa, sizeof(xcoa));
		} else if (strcmp(*argv, "ctx") == 0) {
			char *context;

			if (sctxp)
				duparg("ctx", *argv);
			sctxp = *argv;

			NEXT_ARG();
			context = *argv;

			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
			addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX,
				  (void *)&ctx, ctx.sctx.len);
		} else {
			/* try to assume ALGO */
			int type = xfrm_algotype_getbyname(*argv);
			switch (type) {
			case XFRMA_ALG_AEAD:
			case XFRMA_ALG_CRYPT:
			case XFRMA_ALG_AUTH:
			case XFRMA_ALG_AUTH_TRUNC:
			case XFRMA_ALG_COMP:
			{
				/* ALGO */
				struct {
					union {
						struct xfrm_algo alg;
						struct xfrm_algo_aead aead;
						struct xfrm_algo_auth auth;
					} u;
					char buf[XFRM_ALGO_KEY_BUF_SIZE];
				} alg = {};
				int len;
				__u32 icvlen, trunclen;
				char *name;
				char *key = "";
				char *buf;

				switch (type) {
				case XFRMA_ALG_AEAD:
					if (ealgop || aalgop || aeadop)
						duparg("ALGO-TYPE", *argv);
					aeadop = *argv;
					break;
				case XFRMA_ALG_CRYPT:
					if (ealgop || aeadop)
						duparg("ALGO-TYPE", *argv);
					ealgop = *argv;
					break;
				case XFRMA_ALG_AUTH:
				case XFRMA_ALG_AUTH_TRUNC:
					if (aalgop || aeadop)
						duparg("ALGO-TYPE", *argv);
					aalgop = *argv;
					break;
				case XFRMA_ALG_COMP:
					if (calgop)
						duparg("ALGO-TYPE", *argv);
					calgop = *argv;
					break;
				default:
					/* not reached */
					invarg("ALGO-TYPE value is invalid\n", *argv);
				}

				if (!NEXT_ARG_OK())
					missarg("ALGO-NAME");
				NEXT_ARG();
				name = *argv;

				switch (type) {
				case XFRMA_ALG_AEAD:
				case XFRMA_ALG_CRYPT:
				case XFRMA_ALG_AUTH:
				case XFRMA_ALG_AUTH_TRUNC:
					if (!NEXT_ARG_OK())
						missarg("ALGO-KEYMAT");
					NEXT_ARG();
					key = *argv;
					break;
				}

				buf = alg.u.alg.alg_key;
				len = sizeof(alg.u.alg);

				switch (type) {
				case XFRMA_ALG_AEAD:
					if (!NEXT_ARG_OK())
						missarg("ALGO-ICV-LEN");
					NEXT_ARG();
					if (get_u32(&icvlen, *argv, 0))
						invarg("ALGO-ICV-LEN value is invalid",
						       *argv);
					alg.u.aead.alg_icv_len = icvlen;

					buf = alg.u.aead.alg_key;
					len = sizeof(alg.u.aead);
					break;
				case XFRMA_ALG_AUTH_TRUNC:
					if (!NEXT_ARG_OK())
						missarg("ALGO-TRUNC-LEN");
					NEXT_ARG();
					if (get_u32(&trunclen, *argv, 0))
						invarg("ALGO-TRUNC-LEN value is invalid",
						       *argv);
					alg.u.auth.alg_trunc_len = trunclen;

					buf = alg.u.auth.alg_key;
					len = sizeof(alg.u.auth);
					break;
				}

				xfrm_algo_parse((void *)&alg, type, name, key,
						buf, sizeof(alg.buf));
				len += alg.u.alg.alg_key_len;

				addattr_l(&req.n, sizeof(req.buf), type,
					  (void *)&alg, len);
				break;
			}
			default:
				/* try to assume ID */
				if (idp)
					invarg("unknown", *argv);
				idp = *argv;

				/* ID */
				xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
					      &req.xsinfo.family, 0, &argc, &argv);
				if (preferred_family == AF_UNSPEC)
					preferred_family = req.xsinfo.family;
			}
		}
		argc--; argv++;
	}

	if (req.xsinfo.flags & XFRM_STATE_ESN &&
	    replay_window == 0) {
		fprintf(stderr, "Error: esn flag set without replay-window.\n");
		exit(-1);
	}

	if (replay_window > XFRMA_REPLAY_ESN_MAX) {
		fprintf(stderr,
			"Error: replay-window (%u) > XFRMA_REPLAY_ESN_MAX (%u).\n",
			replay_window, XFRMA_REPLAY_ESN_MAX);
		exit(-1);
	}

	if (req.xsinfo.flags & XFRM_STATE_ESN ||
	    replay_window > (sizeof(replay.bitmap) * 8)) {
		replay_esn.seq = seq;
		replay_esn.oseq = oseq;
		replay_esn.seq_hi = seq_hi;
		replay_esn.oseq_hi = oseq_hi;
		replay_esn.replay_window = replay_window;
		replay_esn.bmp_len = (replay_window + sizeof(__u32) * 8 - 1) /
				     (sizeof(__u32) * 8);
		addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_ESN_VAL,
			  &replay_esn, sizeof(replay_esn));
	} else {
		if (seq || oseq) {
			replay.seq = seq;
			replay.oseq = oseq;
			addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
				  &replay, sizeof(replay));
		}
		req.xsinfo.replay_window = replay_window;
	}

	if (extra_flags)
		addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS,
			  extra_flags);

	if (!idp) {
		fprintf(stderr, "Not enough information: ID is required\n");
		exit(1);
	}

	if (mark.m) {
		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
				  (void *)&mark, sizeof(mark));
		if (r < 0) {
			fprintf(stderr, "XFRMA_MARK failed\n");
			exit(1);
		}
	}

	if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
		switch (req.xsinfo.mode) {
		case XFRM_MODE_TRANSPORT:
		case XFRM_MODE_TUNNEL:
			break;
		case XFRM_MODE_BEET:
			if (req.xsinfo.id.proto == IPPROTO_ESP)
				break;
		default:
			fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}

		switch (req.xsinfo.id.proto) {
		case IPPROTO_ESP:
			if (calgop) {
				fprintf(stderr, "ALGO-TYPE value \"%s\" is invalid with XFRM-PROTO value \"%s\"\n",
					strxf_algotype(XFRMA_ALG_COMP),
					strxf_xfrmproto(req.xsinfo.id.proto));
				exit(1);
			}
			if (!ealgop && !aeadop) {
				fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n",
					strxf_algotype(XFRMA_ALG_CRYPT),
					strxf_algotype(XFRMA_ALG_AEAD),
					strxf_xfrmproto(req.xsinfo.id.proto));
				exit(1);
			}
			break;
		case IPPROTO_AH:
			if (ealgop || aeadop || calgop) {
				fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n",
					strxf_algotype(XFRMA_ALG_CRYPT),
					strxf_algotype(XFRMA_ALG_AEAD),
					strxf_algotype(XFRMA_ALG_COMP),
					strxf_xfrmproto(req.xsinfo.id.proto));
				exit(1);
			}
			if (!aalgop) {
				fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n",
					strxf_algotype(XFRMA_ALG_AUTH),
					strxf_algotype(XFRMA_ALG_AUTH_TRUNC),
					strxf_xfrmproto(req.xsinfo.id.proto));
				exit(1);
			}
			break;
		case IPPROTO_COMP:
			if (ealgop || aalgop || aeadop) {
				fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n",
					strxf_algotype(XFRMA_ALG_CRYPT),
					strxf_algotype(XFRMA_ALG_AUTH),
					strxf_algotype(XFRMA_ALG_AUTH_TRUNC),
					strxf_algotype(XFRMA_ALG_AEAD),
					strxf_xfrmproto(req.xsinfo.id.proto));
				exit(1);
			}
			if (!calgop) {
				fprintf(stderr, "ALGO-TYPE value \"%s\" is required with XFRM-PROTO value \"%s\"\n",
					strxf_algotype(XFRMA_ALG_COMP),
					strxf_xfrmproto(req.xsinfo.id.proto));
				exit(1);
			}
			break;
		}
	} else {
		if (ealgop || aalgop || aeadop || calgop) {
			fprintf(stderr, "ALGO is invalid with XFRM-PROTO value \"%s\"\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
	}

	if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
		switch (req.xsinfo.mode) {
		case XFRM_MODE_ROUTEOPTIMIZATION:
		case XFRM_MODE_IN_TRIGGER:
			break;
		case 0:
			fprintf(stderr, "\"mode\" is required with XFRM-PROTO value \"%s\"\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		default:
			fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}

		if (!coap) {
			fprintf(stderr, "\"coa\" is required with XFRM-PROTO value \"%s\"\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
	} else {
		if (coap) {
			fprintf(stderr, "\"coa\" is invalid with XFRM-PROTO value \"%s\"\n",
				strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xsinfo.family == AF_UNSPEC)
		req.xsinfo.family = AF_INET;

	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Beispiel #17
0
static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr			n;
		struct xfrm_userpolicy_info	xpinfo;
		char				buf[RTA_BUF_SIZE];
	} req;
	char *dirp = NULL;
	char *selp = NULL;
	char *ptypep = NULL;
	struct xfrm_userpolicy_type upt;
	char tmpls_buf[XFRM_TMPLS_BUF_SIZE];
	int tmpls_len = 0;

	memset(&req, 0, sizeof(req));
	memset(&upt, 0, sizeof(upt));
	memset(&tmpls_buf, 0, sizeof(tmpls_buf));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.xpinfo.sel.family = preferred_family;

	req.xpinfo.lft.soft_byte_limit = XFRM_INF;
	req.xpinfo.lft.hard_byte_limit = XFRM_INF;
	req.xpinfo.lft.soft_packet_limit = XFRM_INF;
	req.xpinfo.lft.hard_packet_limit = XFRM_INF;

	while (argc > 0) {
		if (strcmp(*argv, "dir") == 0) {
			if (dirp)
				duparg("dir", *argv);
			dirp = *argv;

			NEXT_ARG();
			xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv);

			filter.dir_mask = XFRM_FILTER_MASK_FULL;

		} else if (strcmp(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&req.xpinfo.index, *argv, 0))
				invarg("\"INDEX\" is invalid", *argv);

			filter.index_mask = XFRM_FILTER_MASK_FULL;

		} else if (strcmp(*argv, "ptype") == 0) {
			if (ptypep)
				duparg("ptype", *argv);
			ptypep = *argv;

			NEXT_ARG();
			xfrm_policy_ptype_parse(&upt.type, &argc, &argv);

			filter.dir_mask = XFRM_FILTER_MASK_FULL;

		} else if (strcmp(*argv, "action") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "allow") == 0)
				req.xpinfo.action = XFRM_POLICY_ALLOW;
			else if (strcmp(*argv, "block") == 0)
				req.xpinfo.action = XFRM_POLICY_BLOCK;
			else
				invarg("\"action\" value is invalid\n", *argv);

			filter.action_mask = XFRM_FILTER_MASK_FULL;

		} else if (strcmp(*argv, "priority") == 0) {
			NEXT_ARG();
			if (get_u32(&req.xpinfo.priority, *argv, 0))
				invarg("\"PRIORITY\" is invalid", *argv);

			filter.priority_mask = XFRM_FILTER_MASK_FULL;

		} else if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv);
		} else if (strcmp(*argv, "tmpl") == 0) {
			struct xfrm_user_tmpl *tmpl;

			if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) {
				fprintf(stderr, "Too many tmpls: buffer overflow\n");
				exit(1);
			}
			tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len);

			tmpl->family = preferred_family;
			tmpl->aalgos = (~(__u32)0);
			tmpl->ealgos = (~(__u32)0);
			tmpl->calgos = (~(__u32)0);

			NEXT_ARG();
			xfrm_tmpl_parse(tmpl, &argc, &argv);

			tmpls_len += sizeof(*tmpl);
		} else {
			if (selp)
				duparg("unknown", *argv);
			selp = *argv;

			xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv);
			if (preferred_family == AF_UNSPEC)
				preferred_family = req.xpinfo.sel.family;
		}

		argc--; argv++;
	}

	if (!dirp) {
		fprintf(stderr, "Not enough information: \"DIR\" is required.\n");
		exit(1);
	}

	if (ptypep) {
		addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
			  (void *)&upt, sizeof(upt));
	}

	if (tmpls_len > 0) {
		addattr_l(&req.n, sizeof(req), XFRMA_TMPL,
			  (void *)tmpls_buf, tmpls_len);
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xpinfo.sel.family == AF_UNSPEC)
		req.xpinfo.sel.family = AF_INET;

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Beispiel #18
0
static int ipaddr_modify(int cmd, int argc, char **argv)
{
	static const char *const option[] = {
		"peer", "remote", "broadcast", "brd",
		"anycast", "scope", "dev", "label", "local", 0
	};

	struct rtnl_handle rth;
	struct {
		struct nlmsghdr		n;
		struct ifaddrmsg	ifa;
		char			buf[256];
	} req;
	char  *d = NULL;
	char  *l = NULL;
	inet_prefix lcl;
	inet_prefix peer;
	int local_len = 0;
	int peer_len = 0;
	int brd_len = 0;
	int any_len = 0;
	int scoped = 0;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = cmd;
	req.ifa.ifa_family = preferred_family;

	while (argc > 0) {
		const int option_num = compare_string_array(option, *argv);
		switch (option_num) {
			case 0: /* peer */
			case 1: /* remote */
				NEXT_ARG();

				if (peer_len) {
					duparg("peer", *argv);
				}
				get_prefix(&peer, *argv, req.ifa.ifa_family);
				peer_len = peer.bytelen;
				if (req.ifa.ifa_family == AF_UNSPEC) {
					req.ifa.ifa_family = peer.family;
				}
				addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
				req.ifa.ifa_prefixlen = peer.bitlen;
				break;
			case 2: /* broadcast */
			case 3: /* brd */
			{
				inet_prefix addr;
				NEXT_ARG();
				if (brd_len) {
					duparg("broadcast", *argv);
				}
				if (strcmp(*argv, "+") == 0) {
					brd_len = -1;
				}
				else if (strcmp(*argv, "-") == 0) {
					brd_len = -2;
				} else {
					get_addr(&addr, *argv, req.ifa.ifa_family);
					if (req.ifa.ifa_family == AF_UNSPEC)
						req.ifa.ifa_family = addr.family;
					addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
					brd_len = addr.bytelen;
				}
				break;
			}
			case 4: /* anycast */
			{
				inet_prefix addr;
				NEXT_ARG();
				if (any_len) {
					duparg("anycast", *argv);
				}
				get_addr(&addr, *argv, req.ifa.ifa_family);
				if (req.ifa.ifa_family == AF_UNSPEC) {
					req.ifa.ifa_family = addr.family;
				}
				addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
				any_len = addr.bytelen;
				break;
			}
			case 5: /* scope */
			{
				uint32_t scope = 0;
				NEXT_ARG();
				if (rtnl_rtscope_a2n(&scope, *argv)) {
					invarg(*argv, "invalid scope value");
				}
				req.ifa.ifa_scope = scope;
				scoped = 1;
				break;
			}
			case 6: /* dev */
				NEXT_ARG();
				d = *argv;
				break;
			case 7: /* label */
				NEXT_ARG();
				l = *argv;
				addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
				break;
			case 8:	/* local */
				NEXT_ARG();
			default:
				if (local_len) {
					duparg2("local", *argv);
				}
				get_prefix(&lcl, *argv, req.ifa.ifa_family);
				if (req.ifa.ifa_family == AF_UNSPEC) {
					req.ifa.ifa_family = lcl.family;
				}
				addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
				local_len = lcl.bytelen;
		}
		argc--;
		argv++;
	}

	if (d == NULL) {
		bb_error_msg("Not enough information: \"dev\" argument is required");
		return -1;
	}
	if (l && matches(d, l) != 0) {
		bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l);
	}

	if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
		peer = lcl;
		addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
	}
	if (req.ifa.ifa_prefixlen == 0)
		req.ifa.ifa_prefixlen = lcl.bitlen;

	if (brd_len < 0 && cmd != RTM_DELADDR) {
		inet_prefix brd;
		int i;
		if (req.ifa.ifa_family != AF_INET) {
			bb_error_msg("Broadcast can be set only for IPv4 addresses");
			return -1;
		}
		brd = peer;
		if (brd.bitlen <= 30) {
			for (i=31; i>=brd.bitlen; i--) {
				if (brd_len == -1)
					brd.data[0] |= htonl(1<<(31-i));
				else
					brd.data[0] &= ~htonl(1<<(31-i));
			}
			addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
			brd_len = brd.bytelen;
		}
	}
	if (!scoped && cmd != RTM_DELADDR)
		req.ifa.ifa_scope = default_scope(&lcl);

	if (rtnl_open(&rth, 0) < 0)
		exit(1);

	ll_init_map(&rth);

	if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
		bb_error_msg("Cannot find device \"%s\"", d);
		return -1;
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	exit(0);
}
Beispiel #19
0
int do_show_or_flush(int argc, char **argv, int flush)
{
	char *filter_dev = NULL;
	struct rtnl_handle rth;
	int state_given = 0;

	ipneigh_reset_filter();

	if (!filter.family)
		filter.family = preferred_family;

	if (flush) {
		if (argc <= 0) {
			fprintf(stderr, "Flush requires arguments.\n");
			return -1;
		}
		filter.state = ~(NUD_PERMANENT|NUD_NOARP);
	} else
		filter.state = 0xFF & ~NUD_NOARP;

	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			if (filter_dev)
				duparg("dev", *argv);
			filter_dev = *argv;
		} else if (strcmp(*argv, "unused") == 0) {
			filter.unused_only = 1;
		} else if (strcmp(*argv, "nud") == 0) {
			unsigned state;
			NEXT_ARG();
			if (!state_given) {
				state_given = 1;
				filter.state = 0;
			}
			if (nud_state_a2n(&state, *argv)) {
				if (strcmp(*argv, "all") != 0)
					invarg("nud state is bad", *argv);
				state = ~0;
				if (flush)
					state &= ~NUD_NOARP;
			}
			if (state == 0)
				state = 0x100;
			filter.state |= state;
		} else {
			if (strcmp(*argv, "to") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			get_prefix(&filter.pfx, *argv, filter.family);
			if (filter.family == AF_UNSPEC)
				filter.family = filter.pfx.family;
		}
		argc--; argv++;
	}

	if (rtnl_open(&rth, 0) < 0)
		exit(1);

	ll_init_map(&rth);

	if (filter_dev) {
		if ((filter.index = ll_name_to_index(filter_dev)) == 0) {
			fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
			return -1;
		}
	}

	if (flush) {
		int round = 0;
		static char flushb[4096-512];

		filter.flushb = flushb;
		filter.flushp = 0;
		filter.flushe = sizeof(flushb);
		filter.rth = &rth;
		filter.state &= ~NUD_FAILED;

		for (;;) {
			if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) {
				perror("Cannot send dump request");
				exit(1);
			}
			filter.flushed = 0;
			if (rtnl_dump_filter(&rth, print_neigh, stdout, NULL, NULL) < 0) {
				fprintf(stderr, "Flush terminated\n");
				exit(1);
			}
			if (filter.flushed == 0) {
				if (round == 0) {
					fprintf(stderr, "Nothing to flush.\n");
				} else if (show_stats)
					printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
				fflush(stdout);
				return 0;
			}
			round++;
			if (flush_update() < 0)
				exit(1);
			if (show_stats) {
				printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
				fflush(stdout);
			}
		}
	}

	if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) {
		perror("Cannot send dump request");
		exit(1);
	}

	if (rtnl_dump_filter(&rth, print_neigh, stdout, NULL, NULL) < 0) {
		fprintf(stderr, "Dump terminated\n");
		exit(1);
	}

	return 0;
}
Beispiel #20
0
static int
parse_egress(struct action_util *a, int *argc_p, char ***argv_p,
             int tca_id, struct nlmsghdr *n)
{

    int argc = *argc_p;
    char **argv = *argv_p;
    int ok = 0, iok = 0, mirror=0,redir=0;
    struct tc_mirred p;
    struct rtattr *tail;
    char d[16];

    memset(d,0,sizeof(d)-1);
    memset(&p,0,sizeof(struct tc_mirred));

    while (argc > 0) {

        if (matches(*argv, "action") == 0) {
            break;
        } else if (matches(*argv, "egress") == 0) {
            NEXT_ARG();
            ok++;
            continue;
        } else {

            if (matches(*argv, "index") == 0) {
                NEXT_ARG();
                if (get_u32(&p.index, *argv, 10)) {
                    fprintf(stderr, "Illegal \"index\"\n");
                    return -1;
                }
                iok++;
                if (!ok) {
                    argc--;
                    argv++;
                    break;
                }
            } else if(!ok) {
                fprintf(stderr, "was expecting egress (%s)\n", *argv);
                break;

            } else if (!mirror && matches(*argv, "mirror") == 0) {
                mirror=1;
                if (redir) {
                    fprintf(stderr, "Cant have both mirror and redir\n");
                    return -1;
                }
                p.eaction = TCA_EGRESS_MIRROR;
                p.action = TC_ACT_PIPE;
                ok++;
            } else if (!redir && matches(*argv, "redirect") == 0) {
                redir=1;
                if (mirror) {
                    fprintf(stderr, "Cant have both mirror and redir\n");
                    return -1;
                }
                p.eaction = TCA_EGRESS_REDIR;
                p.action = TC_ACT_STOLEN;
                ok++;
            } else if ((redir || mirror) && matches(*argv, "dev") == 0) {
                NEXT_ARG();
                if (strlen(d))
                    duparg("dev", *argv);

                strncpy(d, *argv, sizeof(d)-1);
                argc--;
                argv++;

                break;

            }
        }

        NEXT_ARG();
    }

    if (!ok && !iok) {
        return -1;
    }



    if (d[0])  {
        int idx;
        ll_init_map(&rth);

        if ((idx = ll_name_to_index(d)) == 0) {
            fprintf(stderr, "Cannot find device \"%s\"\n", d);
            return -1;
        }

        p.ifindex = idx;
    }


    if (argc && p.eaction == TCA_EGRESS_MIRROR) {

        if (matches(*argv, "reclassify") == 0) {
            p.action = TC_POLICE_RECLASSIFY;
            NEXT_ARG();
        } else if (matches(*argv, "pipe") == 0) {
            p.action = TC_POLICE_PIPE;
            NEXT_ARG();
        } else if (matches(*argv, "drop") == 0 ||
                   matches(*argv, "shot") == 0) {
            p.action = TC_POLICE_SHOT;
            NEXT_ARG();
        } else if (matches(*argv, "continue") == 0) {
            p.action = TC_POLICE_UNSPEC;
            NEXT_ARG();
        } else if (matches(*argv, "pass") == 0) {
            p.action = TC_POLICE_OK;
            NEXT_ARG();
        }

    }

    if (argc) {
        if (iok && matches(*argv, "index") == 0) {
            fprintf(stderr, "mirred: Illegal double index\n");
            return -1;
        } else {
            if (matches(*argv, "index") == 0) {
                NEXT_ARG();
                if (get_u32(&p.index, *argv, 10)) {
                    fprintf(stderr, "mirred: Illegal \"index\"\n");
                    return -1;
                }
                argc--;
                argv++;
            }
        }
    }

    tail = NLMSG_TAIL(n);
    addattr_l(n, MAX_MSG, tca_id, NULL, 0);
    addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof (p));
    tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;

    *argc_p = argc;
    *argv_p = argv;
    return 0;
}
Beispiel #21
0
static int ipntable_modify(int cmd, int flags, int argc, char **argv)
{
	struct {
		struct nlmsghdr 	n;
		struct ndtmsg		ndtm;
		char   			buf[1024];
	} req;
	char *namep = NULL;
	char *threshsp = NULL;
	char *gc_intp = NULL;
	char parms_buf[1024];
	struct rtattr *parms_rta = (struct rtattr *)parms_buf;
	int parms_change = 0;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;

	req.ndtm.ndtm_family = preferred_family;
	req.ndtm.ndtm_pad1 = 0;
	req.ndtm.ndtm_pad2 = 0;

	memset(&parms_buf, 0, sizeof(parms_buf));

	parms_rta->rta_type = NDTA_PARMS;
	parms_rta->rta_len = RTA_LENGTH(0);

	while (argc > 0) {
		if (strcmp(*argv, "name") == 0) {
			int len;

			NEXT_ARG();
			if (namep)
				duparg("NAME", *argv);

			namep = *argv;
			len = strlen(namep) + 1;
			addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len);
		} else if (strcmp(*argv, "thresh1") == 0) {
			__u32 thresh1;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh1, *argv, 0))
				invarg("\"thresh1\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1);
		} else if (strcmp(*argv, "thresh2") == 0) {
			__u32 thresh2;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh2, *argv, 0))
				invarg("\"thresh2\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2);
		} else if (strcmp(*argv, "thresh3") == 0) {
			__u32 thresh3;

			NEXT_ARG();
			threshsp = *argv;

			if (get_u32(&thresh3, *argv, 0))
				invarg("\"thresh3\" value is invalid", *argv);

			addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3);
		} else if (strcmp(*argv, "gc_int") == 0) {
			__u64 gc_int;

			NEXT_ARG();
			gc_intp = *argv;

			if (get_u64(&gc_int, *argv, 0))
				invarg("\"gc_int\" value is invalid", *argv);

			addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL,
				  &gc_int, sizeof(gc_int));
		} else if (strcmp(*argv, "dev") == 0) {
			__u32 ifindex;

			NEXT_ARG();
			ifindex = ll_name_to_index(*argv);
			if (ifindex == 0) {
				fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
				return -1;
			}

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_IFINDEX, ifindex);
		} else if (strcmp(*argv, "base_reachable") == 0) {
			__u64 breachable;

			NEXT_ARG();

			if (get_u64(&breachable, *argv, 0))
				invarg("\"base_reachable\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_BASE_REACHABLE_TIME,
				      &breachable, sizeof(breachable));
			parms_change = 1;
		} else if (strcmp(*argv, "retrans") == 0) {
			__u64 retrans;

			NEXT_ARG();

			if (get_u64(&retrans, *argv, 0))
				invarg("\"retrans\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_RETRANS_TIME,
				      &retrans, sizeof(retrans));
			parms_change = 1;
		} else if (strcmp(*argv, "gc_stale") == 0) {
			__u64 gc_stale;

			NEXT_ARG();

			if (get_u64(&gc_stale, *argv, 0))
				invarg("\"gc_stale\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_GC_STALETIME,
				      &gc_stale, sizeof(gc_stale));
			parms_change = 1;
		} else if (strcmp(*argv, "delay_probe") == 0) {
			__u64 delay_probe;

			NEXT_ARG();

			if (get_u64(&delay_probe, *argv, 0))
				invarg("\"delay_probe\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_DELAY_PROBE_TIME,
				      &delay_probe, sizeof(delay_probe));
			parms_change = 1;
		} else if (strcmp(*argv, "queue") == 0) {
			__u32 queue;

			NEXT_ARG();

			if (get_u32(&queue, *argv, 0))
				invarg("\"queue\" value is invalid", *argv);

			if (!parms_rta)
				parms_rta = (struct rtattr *)&parms_buf;
			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_QUEUE_LEN, queue);
			parms_change = 1;
		} else if (strcmp(*argv, "app_probes") == 0) {
			__u32 aprobe;

			NEXT_ARG();

			if (get_u32(&aprobe, *argv, 0))
				invarg("\"app_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_APP_PROBES, aprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "ucast_probes") == 0) {
			__u32 uprobe;

			NEXT_ARG();

			if (get_u32(&uprobe, *argv, 0))
				invarg("\"ucast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_UCAST_PROBES, uprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "mcast_probes") == 0) {
			__u32 mprobe;

			NEXT_ARG();

			if (get_u32(&mprobe, *argv, 0))
				invarg("\"mcast_probes\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_MCAST_PROBES, mprobe);
			parms_change = 1;
		} else if (strcmp(*argv, "anycast_delay") == 0) {
			__u64 anycast_delay;

			NEXT_ARG();

			if (get_u64(&anycast_delay, *argv, 0))
				invarg("\"anycast_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_ANYCAST_DELAY,
				      &anycast_delay, sizeof(anycast_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_delay") == 0) {
			__u64 proxy_delay;

			NEXT_ARG();

			if (get_u64(&proxy_delay, *argv, 0))
				invarg("\"proxy_delay\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_DELAY,
				      &proxy_delay, sizeof(proxy_delay));
			parms_change = 1;
		} else if (strcmp(*argv, "proxy_queue") == 0) {
			__u32 pqueue;

			NEXT_ARG();

			if (get_u32(&pqueue, *argv, 0))
				invarg("\"proxy_queue\" value is invalid", *argv);

			rta_addattr32(parms_rta, sizeof(parms_buf),
				      NDTPA_PROXY_QLEN, pqueue);
			parms_change = 1;
		} else if (strcmp(*argv, "locktime") == 0) {
			__u64 locktime;

			NEXT_ARG();

			if (get_u64(&locktime, *argv, 0))
				invarg("\"locktime\" value is invalid", *argv);

			rta_addattr_l(parms_rta, sizeof(parms_buf),
				      NDTPA_LOCKTIME,
				      &locktime, sizeof(locktime));
			parms_change = 1;
		} else {
			invarg("unknown", *argv);
		}

		argc--; argv++;
	}

	if (!namep)
		missarg("NAME");
	if (!threshsp && !gc_intp && !parms_change) {
		fprintf(stderr, "Not enough information: changable attributes required.\n");
		exit(-1);
	}

	if (parms_rta->rta_len > RTA_LENGTH(0)) {
		addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta),
			  RTA_PAYLOAD(parms_rta));
	}

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	return 0;
}
Beispiel #22
0
static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
			    struct nlmsghdr *n)
{
	int ret;
	__u8 encoding_sa = 0xff;
	__u32 window = -1;
	struct cipher_args cipher = {0};
	enum macsec_validation_type validate;
	bool es = false, scb = false, send_sci = false;
	int replay_protect = -1;
	struct sci sci = { 0 };

	ret = get_sci_portaddr(&sci, &argc, &argv, true, true);
	if (ret < 0) {
		fprintf(stderr, "expected sci\n");
		return -1;
	}

	if (ret > 0) {
		if (sci.sci)
			addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_SCI,
				  &sci.sci, sizeof(sci.sci));
		else
			addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_PORT,
				  &sci.port, sizeof(sci.port));
	}

	while (argc > 0) {
		if (strcmp(*argv, "cipher") == 0) {
			NEXT_ARG();
			if (cipher.id)
				duparg("cipher", *argv);
			if (strcmp(*argv, "default") == 0 ||
			    strcmp(*argv, "gcm-aes-128") == 0 ||
			    strcmp(*argv, "GCM-AES-128") == 0)
				cipher.id = MACSEC_DEFAULT_CIPHER_ID;
			else
				invarg("expected: default or gcm-aes-128",
				       *argv);
		} else if (strcmp(*argv, "icvlen") == 0) {
			NEXT_ARG();
			if (cipher.icv_len)
				duparg("icvlen", *argv);
			get_icvlen(&cipher.icv_len, *argv);
		} else if (strcmp(*argv, "encrypt") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("encrypt", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i);
		} else if (strcmp(*argv, "send_sci") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("send_sci", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			send_sci = i;
			addattr8(n, MACSEC_BUFLEN,
				 IFLA_MACSEC_INC_SCI, send_sci);
		} else if (strcmp(*argv, "end_station") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("end_station", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			es = i;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ES, es);
		} else if (strcmp(*argv, "scb") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("scb", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			scb = i;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb);
		} else if (strcmp(*argv, "protect") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("protect", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i);
		} else if (strcmp(*argv, "replay") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("replay", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			replay_protect = !!i;
		} else if (strcmp(*argv, "window") == 0) {
			NEXT_ARG();
			ret = get_u32(&window, *argv, 0);
			if (ret)
				invarg("expected replay window size", *argv);
		} else if (strcmp(*argv, "validate") == 0) {
			NEXT_ARG();
			ret = one_of("validate", *argv,
				     validate_str, ARRAY_SIZE(validate_str),
				     (int *)&validate);
			if (ret != 0)
				return ret;
			addattr8(n, MACSEC_BUFLEN,
				 IFLA_MACSEC_VALIDATION, validate);
		} else if (strcmp(*argv, "encodingsa") == 0) {
			if (encoding_sa != 0xff)
				duparg2("encodingsa", "encodingsa");
			NEXT_ARG();
			ret = get_an(&encoding_sa, *argv);
			if (ret)
				invarg("expected an { 0..3 }", *argv);
		} else {
			fprintf(stderr, "macsec: unknown command \"%s\"?\n",
				*argv);
			usage(stderr);
			return -1;
		}

		argv++; argc--;
	}

	if (!check_txsc_flags(es, scb, send_sci)) {
		fprintf(stderr,
			"invalid combination of send_sci/end_station/scb\n");
		return -1;
	}

	if (window != -1 && replay_protect == -1) {
		fprintf(stderr,
			"replay window set, but replay protection not enabled. did you mean 'replay on window %u'?\n",
			window);
		return -1;
	} else if (window == -1 && replay_protect == 1) {
		fprintf(stderr,
			"replay protection enabled, but no window set. did you mean 'replay on window VALUE'?\n");
		return -1;
	}

	if (cipher.id)
		addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE,
			  &cipher.id, sizeof(cipher.id));
	if (cipher.icv_len)
		addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN,
			  &cipher.icv_len, sizeof(cipher.icv_len));

	if (replay_protect != -1) {
		addattr32(n, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window);
		addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT,
			 replay_protect);
	}

	if (encoding_sa != 0xff) {
		addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA,
			  &encoding_sa, sizeof(encoding_sa));
	}

	return 0;
}
Beispiel #23
0
static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr			n;
		struct xfrm_userpolicy_info	xpinfo;
		char				buf[RTA_BUF_SIZE];
	} req;
	char *dirp = NULL;
	char *selp = NULL;
	char *ptypep = NULL;
	char *sctxp = NULL;
	struct xfrm_userpolicy_type upt;
	char tmpls_buf[XFRM_TMPLS_BUF_SIZE];
	int tmpls_len = 0;
	struct xfrm_mark mark = {0, 0};
	struct {
		struct xfrm_user_sec_ctx sctx;
		char	str[CTX_BUF_SIZE];
	} ctx;

	memset(&req, 0, sizeof(req));
	memset(&upt, 0, sizeof(upt));
	memset(&tmpls_buf, 0, sizeof(tmpls_buf));
	memset(&ctx, 0, sizeof(ctx));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.xpinfo.sel.family = preferred_family;

	req.xpinfo.lft.soft_byte_limit = XFRM_INF;
	req.xpinfo.lft.hard_byte_limit = XFRM_INF;
	req.xpinfo.lft.soft_packet_limit = XFRM_INF;
	req.xpinfo.lft.hard_packet_limit = XFRM_INF;

	while (argc > 0) {
		if (strcmp(*argv, "dir") == 0) {
			if (dirp)
				duparg("dir", *argv);
			dirp = *argv;

			NEXT_ARG();
			xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv);
		} else if (strcmp(*argv, "ctx") == 0) {
			char *context;

			if (sctxp)
				duparg("ctx", *argv);
			sctxp = *argv;
			NEXT_ARG();
			context = *argv;
			xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
		} else if (strcmp(*argv, "mark") == 0) {
			xfrm_parse_mark(&mark, &argc, &argv);
		} else if (strcmp(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&req.xpinfo.index, *argv, 0))
				invarg("INDEX value is invalid", *argv);
		} else if (strcmp(*argv, "ptype") == 0) {
			if (ptypep)
				duparg("ptype", *argv);
			ptypep = *argv;

			NEXT_ARG();
			xfrm_policy_ptype_parse(&upt.type, &argc, &argv);
		} else if (strcmp(*argv, "action") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "allow") == 0)
				req.xpinfo.action = XFRM_POLICY_ALLOW;
			else if (strcmp(*argv, "block") == 0)
				req.xpinfo.action = XFRM_POLICY_BLOCK;
			else
				invarg("ACTION value is invalid\n", *argv);
		} else if (strcmp(*argv, "priority") == 0) {
			NEXT_ARG();
			if (get_u32(&req.xpinfo.priority, *argv, 0))
				invarg("PRIORITY value is invalid", *argv);
		} else if (strcmp(*argv, "flag") == 0) {
			NEXT_ARG();
			xfrm_policy_flag_parse(&req.xpinfo.flags, &argc,
					       &argv);
		} else if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv);
		} else if (strcmp(*argv, "tmpl") == 0) {
			struct xfrm_user_tmpl *tmpl;

			if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) {
				fprintf(stderr, "Too many tmpls: buffer overflow\n");
				exit(1);
			}
			tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len);

			tmpl->family = preferred_family;
			tmpl->aalgos = (~(__u32)0);
			tmpl->ealgos = (~(__u32)0);
			tmpl->calgos = (~(__u32)0);

			NEXT_ARG();
			xfrm_tmpl_parse(tmpl, &argc, &argv);

			tmpls_len += sizeof(*tmpl);
		} else {
			if (selp)
				duparg("unknown", *argv);
			selp = *argv;

			xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv);
			if (preferred_family == AF_UNSPEC)
				preferred_family = req.xpinfo.sel.family;
		}

		argc--; argv++;
	}

	if (!dirp) {
		fprintf(stderr, "Not enough information: DIR is required.\n");
		exit(1);
	}

	if (ptypep) {
		addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE,
			  (void *)&upt, sizeof(upt));
	}

	if (tmpls_len > 0) {
		addattr_l(&req.n, sizeof(req), XFRMA_TMPL,
			  (void *)tmpls_buf, tmpls_len);
	}

	if (mark.m) {
		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
				  (void *)&mark, sizeof(mark));
		if (r < 0) {
			fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__);
			exit(1);
		}
	}

	if (sctxp) {
		addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX,
			  (void *)&ctx, ctx.sctx.len);
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xpinfo.sel.family == AF_UNSPEC)
		req.xpinfo.sel.family = AF_INET;

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Beispiel #24
0
static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct xfrm_usersa_info xsinfo;
		char   			buf[RTA_BUF_SIZE];
	} req;
	char *idp = NULL;
	char *ealgop = NULL;
	char *aalgop = NULL;
	char *calgop = NULL;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.xsinfo.family = preferred_family;

	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
	req.xsinfo.lft.hard_packet_limit = XFRM_INF;

	while (argc > 0) {
		if (strcmp(*argv, "mode") == 0) {
			NEXT_ARG();
			xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
		} else if (strcmp(*argv, "reqid") == 0) {
			NEXT_ARG();
			xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
		} else if (strcmp(*argv, "seq") == 0) {
			NEXT_ARG();
			xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
		} else if (strcmp(*argv, "replay-window") == 0) {
			NEXT_ARG();
			if (get_u8(&req.xsinfo.replay_window, *argv, 0))
				invarg("\"replay-window\" value is invalid", *argv);
		} else if (strcmp(*argv, "flag") == 0) {
			NEXT_ARG();
			xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
		} else if (strcmp(*argv, "sel") == 0) {
			NEXT_ARG();
			xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
		} else if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
		} else if (strcmp(*argv, "encap") == 0) {
			struct xfrm_encap_tmpl encap;
			inet_prefix oa;
		        NEXT_ARG();
			xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
			NEXT_ARG();
			if (get_u16(&encap.encap_sport, *argv, 0))
				invarg("\"encap\" sport value is invalid", *argv);
			encap.encap_sport = htons(encap.encap_sport);
			NEXT_ARG();
			if (get_u16(&encap.encap_dport, *argv, 0))
				invarg("\"encap\" dport value is invalid", *argv);
			encap.encap_dport = htons(encap.encap_dport);
			NEXT_ARG();
			get_addr(&oa, *argv, AF_UNSPEC);
			memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
			addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
				  (void *)&encap, sizeof(encap));
		} else {
			/* try to assume ALGO */
			int type = xfrm_algotype_getbyname(*argv);
			switch (type) {
			case XFRMA_ALG_CRYPT:
			case XFRMA_ALG_AUTH:
			case XFRMA_ALG_COMP:
			{
				/* ALGO */
				struct {
					struct xfrm_algo alg;
					char buf[XFRM_ALGO_KEY_BUF_SIZE];
				} alg;
				int len;
				char *name;
				char *key;

				switch (type) {
				case XFRMA_ALG_CRYPT:
					if (ealgop)
						duparg("ALGOTYPE", *argv);
					ealgop = *argv;
					break;
				case XFRMA_ALG_AUTH:
					if (aalgop)
						duparg("ALGOTYPE", *argv);
					aalgop = *argv;
					break;
				case XFRMA_ALG_COMP:
					if (calgop)
						duparg("ALGOTYPE", *argv);
					calgop = *argv;
					break;
				default:
					/* not reached */
					invarg("\"ALGOTYPE\" is invalid\n", *argv);
				}

				if (!NEXT_ARG_OK())
					missarg("ALGONAME");
				NEXT_ARG();
				name = *argv;

				if (!NEXT_ARG_OK())
					missarg("ALGOKEY");
				NEXT_ARG();
				key = *argv;

				memset(&alg, 0, sizeof(alg));

				xfrm_algo_parse((void *)&alg, type, name, key,
						sizeof(alg.buf));
				len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;

				addattr_l(&req.n, sizeof(req.buf), type,
					  (void *)&alg, len);
				break;
			}
			default:
				/* try to assume ID */
				if (idp)
					invarg("unknown", *argv);
				idp = *argv;

				/* ID */
				xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
					      &req.xsinfo.family, 0, &argc, &argv);
				if (preferred_family == AF_UNSPEC)
					preferred_family = req.xsinfo.family;
			}
		}
		argc--; argv++;
	}

	if (!idp) {
//		fprintf(stderr, "Not enough information: \"ID\" is required\n");
		exit(1);
	}

	if (ealgop || aalgop || calgop) {
		if (req.xsinfo.id.proto != IPPROTO_ESP &&
		    req.xsinfo.id.proto != IPPROTO_AH &&
		    req.xsinfo.id.proto != IPPROTO_COMP) {
//			fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
			exit(1);
		}
	} else {
		if (req.xsinfo.id.proto == IPPROTO_ESP ||
		    req.xsinfo.id.proto == IPPROTO_AH ||
		    req.xsinfo.id.proto == IPPROTO_COMP) {
//			fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
			exit (1);
		}
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xsinfo.family == AF_UNSPEC)
		req.xsinfo.family = AF_INET;

	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
		exit(2);

	rtnl_close(&rth);

	return 0;
}
Beispiel #25
0
static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
{
	struct qdisc_util *q = NULL;
	struct tc_estimator est;
	struct {
		struct tc_sizespec	szopts;
		__u16			*data;
	} stab;
	char  d[16];
	char  k[16];
	struct {
		struct nlmsghdr	n;
		struct tcmsg		t;
		char			buf[TCA_BUF_MAX];
	} req;

	memset(&req, 0, sizeof(req));
	memset(&stab, 0, sizeof(stab));
	memset(&est, 0, sizeof(est));
	memset(&d, 0, sizeof(d));
	memset(&k, 0, sizeof(k));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
	req.n.nlmsg_type = cmd;
	req.t.tcm_family = AF_UNSPEC;

	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			if (d[0])
				duparg("dev", *argv);
			strncpy(d, *argv, sizeof(d)-1);
		} else if (strcmp(*argv, "handle") == 0) {
			__u32 handle;

			if (req.t.tcm_handle)
				duparg("handle", *argv);
			NEXT_ARG();
			if (get_qdisc_handle(&handle, *argv))
				invarg("invalid qdisc ID", *argv);
			req.t.tcm_handle = handle;
		} else if (strcmp(*argv, "root") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"root\" is duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_ROOT;
		} else if (strcmp(*argv, "clsact") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"clsact\" is a duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_CLSACT;
			strncpy(k, "clsact", sizeof(k) - 1);
			q = get_qdisc_kind(k);
			req.t.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0);
			NEXT_ARG_FWD();
			break;
		} else if (strcmp(*argv, "ingress") == 0) {
			if (req.t.tcm_parent) {
				fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n");
				return -1;
			}
			req.t.tcm_parent = TC_H_INGRESS;
			strncpy(k, "ingress", sizeof(k) - 1);
			q = get_qdisc_kind(k);
			req.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
			NEXT_ARG_FWD();
			break;
		} else if (strcmp(*argv, "parent") == 0) {
			__u32 handle;

			NEXT_ARG();
			if (req.t.tcm_parent)
				duparg("parent", *argv);
			if (get_tc_classid(&handle, *argv))
				invarg("invalid parent ID", *argv);
			req.t.tcm_parent = handle;
		} else if (matches(*argv, "estimator") == 0) {
			if (parse_estimator(&argc, &argv, &est))
				return -1;
		} else if (matches(*argv, "stab") == 0) {
			if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
				return -1;
			continue;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else {
			strncpy(k, *argv, sizeof(k)-1);

			q = get_qdisc_kind(k);
			argc--; argv++;
			break;
		}
		argc--; argv++;
	}

	if (k[0])
		addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
	if (est.ewma_log)
		addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));

	if (q) {
		if (q->parse_qopt) {
			if (q->parse_qopt(q, argc, argv, &req.n))
				return 1;
		} else if (argc) {
			fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
			return -1;
		}
	} else {
		if (argc) {
			if (matches(*argv, "help") == 0)
				usage();

			fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv);
			return -1;
		}
	}

	if (check_size_table_opts(&stab.szopts)) {
		struct rtattr *tail;

		if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
			fprintf(stderr, "failed to calculate size table.\n");
			return -1;
		}

		tail = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
		addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
			  sizeof(stab.szopts));
		if (stab.data)
			addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
				  stab.szopts.tsize * sizeof(__u16));
		tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
		if (stab.data)
			free(stab.data);
	}

	if (d[0])  {
		int idx;

		ll_init_map(&rth);

		if ((idx = ll_name_to_index(d)) == 0) {
			fprintf(stderr, "Cannot find device \"%s\"\n", d);
			return 1;
		}
		req.t.tcm_ifindex = idx;
	}

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

	return 0;
}
Beispiel #26
0
int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
{
	struct qdisc_util *q = NULL;
	struct tc_estimator est;
	struct {
		struct tc_sizespec	szopts;
		__u16		*data;
	} stab;
	char  d[16];
	char  k[16];	
	struct {
		struct nlmsghdr 	n;
		struct tcmsg 		t;
		char  			buf[TCA_BUF_MAX];
	} * req;
	
	req = vmalloc(sizeof(*req));
	
	memset(req, 0, sizeof(*req));
	memset(&stab, 0, sizeof(stab));
	memset(&est, 0, sizeof(est));
	memset(&d, 0, sizeof(d));
	memset(&k, 0, sizeof(k));
		
	req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req->n.nlmsg_flags = NLM_F_REQUEST|flags;
	req->n.nlmsg_type = cmd;
	req->t.tcm_family = AF_UNSPEC;
	
	/*
	printk(KERN_DEBUG "NLM_F_CREATE:  %d\n", NLM_F_CREATE);
	printk(KERN_DEBUG "NLM_F_REPLACE: %d\n", NLM_F_REPLACE);
	printk(KERN_DEBUG "NLM_F_REQUEST: %d\n", NLM_F_REQUEST);
	printk(KERN_DEBUG "NLM_F_EXCL:    %d\n", NLM_F_EXCL);
	printk(KERN_DEBUG "RTM_NEWQDISC:  %d\n", RTM_NEWQDISC);
	printk(KERN_DEBUG "RTM_DELQDISC:  %d\n", RTM_DELQDISC);
	printk(KERN_DEBUG "cmd:           %d\n", cmd);
	printk(KERN_DEBUG "req:           %d\n", sizeof(*req));
	*/
	
	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG(); // Mangia un argomento
			if (d[0])
				duparg("dev", *argv);
			strncpy(d, *argv, sizeof(d)-1);
		} else if (strcmp(*argv, "handle") == 0) {
			__u32 handle; //unsigned long?
			if (req->t.tcm_handle)
				duparg("handle", *argv);
			NEXT_ARG(); // Mangia un argomento
			if (get_qdisc_handle(&handle, *argv))
				invarg("invalid qdisc ID", *argv);
			req->t.tcm_handle = handle;
		} else if (strcmp(*argv, "root") == 0) {
			if (req->t.tcm_parent) {
				printk(KERN_DEBUG "[MAT] Error: \"root\" is duplicate parent ID\n");
				return -1;
			}
			req->t.tcm_parent = TC_H_ROOT;
		} else if (strcmp(*argv, "parent") == 0) {
			__u32 handle;
			NEXT_ARG();
			if (req->t.tcm_parent)
				duparg("parent", *argv);
			if (get_tc_classid(&handle, *argv))
				invarg("invalid parent ID", *argv);
			req->t.tcm_parent = handle;
		} /* else if (matches(*argv, "estimator") == 0) {
			if (parse_estimator(&argc, &argv, &est))
				return -1;
		} */ else if (matches(*argv, "stab") == 0) {
			if (parse_size_table(&argc, &argv, &stab.szopts) < 0)
				return -1;
			continue;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else {
			strncpy(k, *argv, sizeof(k)-1);
			q = get_qdisc_kind(k);
			argc--; argv++;
			break;
		}
		argc--; argv++;
	}
	
	if (k[0])
		addattr_l(&req->n, sizeof(*req), TCA_KIND, k, strlen(k)+1);
	if (est.ewma_log) 
		addattr_l(&req->n, sizeof(*req), TCA_RATE, &est, sizeof(est));

	if (q) {
		if (!q->parse_qopt) {
			printk(KERN_DEBUG "[MAT] qdisc '%s' does not support option parsing\n", k);
			return -1;
		}
		if (q->parse_qopt(q, argc, argv, &req->n))
			return 1;
	} else {
		if (argc) {
			if (matches(*argv, "help") == 0)
				usage();
			printk(KERN_DEBUG "[MAT] Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv);
			return -1;
		}
	}
	
	if (check_size_table_opts(&stab.szopts)) {
		struct rtattr *tail;
		if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) {
			printk(KERN_DEBUG "[MAT] failed to calculate size table.\n");
			return -1;
		}
		tail = NLMSG_TAIL(&req->n);
		addattr_l(&req->n, sizeof(*req), TCA_STAB, NULL, 0);
		addattr_l(&req->n, sizeof(*req), TCA_STAB_BASE, &stab.szopts,
			  sizeof(stab.szopts));
		if (stab.data)
			addattr_l(&req->n, sizeof(*req), TCA_STAB_DATA, stab.data,
				  stab.szopts.tsize * sizeof(__u16));
		tail->rta_len = (void *)NLMSG_TAIL(&req->n) - (void *)tail;
		if (stab.data)
			vfree(stab.data);
	}
	
/*	
	if (d[0])  {
		int idx;

 		ll_init_map(&rth);

		if ((idx = ll_name_to_index(d)) == 0) {
			printk(KERN_DEBUG "[MAT] Cannot find device \"%s\"\n", d);
			return 1;
		}
		req->t.tcm_ifindex = idx;
      }
*/     
	if (rtnl_talk(&rth, &req->n, 0, 0, NULL) < 0)
		return 2;
	 
	return 0;
}
Beispiel #27
0
static int xfrm_state_allocspi(int argc, char **argv)
{
	struct rtnl_handle rth;
	struct {
		struct nlmsghdr 	n;
		struct xfrm_userspi_info xspi;
		char   			buf[RTA_BUF_SIZE];
	} req;
	char *idp = NULL;
	char *minp = NULL;
	char *maxp = NULL;
	struct xfrm_mark mark = {0, 0};
	char res_buf[NLMSG_BUF_SIZE];
	struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;

	memset(res_buf, 0, sizeof(res_buf));

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
	req.xspi.info.family = preferred_family;

#if 0
	req.xsinfo.lft.soft_byte_limit = XFRM_INF;
	req.xsinfo.lft.hard_byte_limit = XFRM_INF;
	req.xsinfo.lft.soft_packet_limit = XFRM_INF;
	req.xsinfo.lft.hard_packet_limit = XFRM_INF;
#endif

	while (argc > 0) {
		if (strcmp(*argv, "mode") == 0) {
			NEXT_ARG();
			xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
		} else if (strcmp(*argv, "mark") == 0) {
			xfrm_parse_mark(&mark, &argc, &argv);
		} else if (strcmp(*argv, "reqid") == 0) {
			NEXT_ARG();
			xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
		} else if (strcmp(*argv, "seq") == 0) {
			NEXT_ARG();
			xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
		} else if (strcmp(*argv, "min") == 0) {
			if (minp)
				duparg("min", *argv);
			minp = *argv;

			NEXT_ARG();

			if (get_u32(&req.xspi.min, *argv, 0))
				invarg("\"min\" value is invalid", *argv);
		} else if (strcmp(*argv, "max") == 0) {
			if (maxp)
				duparg("max", *argv);
			maxp = *argv;

			NEXT_ARG();

			if (get_u32(&req.xspi.max, *argv, 0))
				invarg("\"max\" value is invalid", *argv);
		} else {
			
			if (idp)
				invarg("unknown", *argv);
			idp = *argv;

			
			xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
				      &req.xspi.info.family, 0, &argc, &argv);
			if (req.xspi.info.id.spi) {
				fprintf(stderr, "\"SPI\" must be zero\n");
				exit(1);
			}
			if (preferred_family == AF_UNSPEC)
				preferred_family = req.xspi.info.family;
		}
		argc--; argv++;
	}

	if (!idp) {
		fprintf(stderr, "Not enough information: \"ID\" is required\n");
		exit(1);
	}

	if (minp) {
		if (!maxp) {
			fprintf(stderr, "\"max\" is missing\n");
			exit(1);
		}
		if (req.xspi.min > req.xspi.max) {
			fprintf(stderr, "\"min\" value is larger than \"max\" value\n");
			exit(1);
		}
	} else {
		if (maxp) {
			fprintf(stderr, "\"min\" is missing\n");
			exit(1);
		}

		req.xspi.min = 0x100;
		req.xspi.max = 0x0fffffff;

		if (req.xspi.info.id.proto == IPPROTO_COMP)
			req.xspi.max = 0xffff;
	}

	if (mark.m & mark.v) {
		int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
				  (void *)&mark, sizeof(mark));
		if (r < 0) {
			fprintf(stderr, "XFRMA_MARK failed\n");
			exit(1);
		}
	}

	if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
		exit(1);

	if (req.xspi.info.family == AF_UNSPEC)
		req.xspi.info.family = AF_INET;


	if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
		exit(2);

	if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
		fprintf(stderr, "An error :-)\n");
		exit(1);
	}

	rtnl_close(&rth);

	return 0;
}
Beispiel #28
0
/* Return value becomes exitcode. It's okay to not return at all */
static int do_set(char **argv)
{
	char *dev = NULL;
	uint32_t mask = 0;
	uint32_t flags = 0;
	int qlen = -1;
	int mtu = -1;
	char *newaddr = NULL;
	char *newbrd = NULL;
	struct ifreq ifr0, ifr1;
	char *newname = NULL;
	int htype, halen;
	static const char keywords[] ALIGN1 =
		"up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
		"arp\0""address\0""dev\0";
	enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
		ARG_arp, ARG_addr, ARG_dev };
	static const char str_on_off[] ALIGN1 = "on\0""off\0";
	enum { PARM_on = 0, PARM_off };
	smalluint key;

	while (*argv) {
		/* substring search ensures that e.g. "addr" and "address"
		 * are both accepted */
		key = index_in_substrings(keywords, *argv);
		if (key == ARG_up) {
			mask |= IFF_UP;
			flags |= IFF_UP;
		} else if (key == ARG_down) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		} else if (key == ARG_name) {
			NEXT_ARG();
			newname = *argv;
		} else if (key == ARG_mtu) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			mtu = get_unsigned(*argv, "mtu");
		} else if (key == ARG_qlen) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("qlen", *argv);
			qlen = get_unsigned(*argv, "qlen");
		} else if (key == ARG_addr) {
			NEXT_ARG();
			newaddr = *argv;
		} else if (key >= ARG_dev) {
			if (key == ARG_dev) {
				NEXT_ARG();
			}
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		} else {
			int param;
			NEXT_ARG();
			param = index_in_strings(str_on_off, *argv);
			if (key == ARG_multicast) {
				if (param < 0)
					die_must_be_on_off("multicast");
				mask |= IFF_MULTICAST;
				if (param == PARM_on)
					flags |= IFF_MULTICAST;
				else
					flags &= ~IFF_MULTICAST;
			} else if (key == ARG_arp) {
				if (param < 0)
					die_must_be_on_off("arp");
				mask |= IFF_NOARP;
				if (param == PARM_on)
					flags &= ~IFF_NOARP;
				else
					flags |= IFF_NOARP;
			}
		}
		argv++;
	}

	if (!dev) {
		bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
	}

	if (newaddr || newbrd) {
		halen = get_address(dev, &htype);
		if (newaddr) {
			parse_address(dev, htype, halen, newaddr, &ifr0);
			set_address(&ifr0, 0);
		}
		if (newbrd) {
			parse_address(dev, htype, halen, newbrd, &ifr1);
			set_address(&ifr1, 1);
		}
	}

	if (newname && strcmp(dev, newname)) {
		do_changename(dev, newname);
		dev = newname;
	}
	if (qlen != -1) {
		set_qlen(dev, qlen);
	}
	if (mtu != -1) {
		set_mtu(dev, mtu);
	}
	if (mask)
		do_chflags(dev, flags, mask);
	return 0;
}
Beispiel #29
0
static int do_set(int argc, char **argv)
{
	char *dev = NULL;
	__u32 mask = 0;
	__u32 flags = 0;
	int qlen = -1;
	int mtu = -1;
	char *newaddr = NULL;
	char *newbrd = NULL;
	struct ifreq ifr0, ifr1;
	char *newname = NULL;
	int htype, halen;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			mask |= IFF_UP;
			flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			mask |= IFF_UP;
			flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			newname = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			newaddr = *argv;
		} else if (matches(*argv, "broadcast") == 0 ||
			   strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			newbrd = *argv;
		} else if (matches(*argv, "txqueuelen") == 0 ||
			   strcmp(*argv, "qlen") == 0 ||
			   matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			mask |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast", *argv);
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			mask |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast", *argv);
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			mask |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc", *argv);
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			mask |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers", *argv);
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			mask |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				flags |= IFF_NOARP;
			} else
				return on_off("noarp", *argv);
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			mask |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic", *argv);
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (dev)
				duparg2("dev", *argv);
			dev = *argv;
		}
		argc--; argv++;
	}

	if (!dev) {
		fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
		exit(-1);
	}

	if (newaddr || newbrd) {
		halen = get_address(dev, &htype);
		if (halen < 0)
			return -1;
		if (newaddr) {
			if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
				return -1;
		}
		if (newbrd) {
			if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
				return -1;
		}
	}

	if (newname && strcmp(dev, newname)) {
		if (strlen(newname) == 0)
			invarg("\"\" is not a valid device identifier\n", "name");
		if (do_changename(dev, newname) < 0)
			return -1;
		dev = newname;
	}
	if (qlen != -1) {
		if (set_qlen(dev, qlen) < 0)
			return -1;
	}
	if (mtu != -1) {
		if (set_mtu(dev, mtu) < 0)
			return -1;
	}
	if (newaddr || newbrd) {
		if (newbrd) {
			if (set_address(&ifr1, 1) < 0)
				return -1;
		}
		if (newaddr) {
			if (set_address(&ifr0, 0) < 0)
				return -1;
		}
	}
	if (mask)
		return do_chflags(dev, flags, mask);
	return 0;
}
Beispiel #30
0
doentry(struct Entrypoint *ep)
#endif
{
	register int type;
	register Namep np;
	chainp p, p1;
	register Namep q;
	Addrp rs;
	int it, k;
	extern char dflttype[26];
	Extsym *entryname = ep->entryname;

	if (++nentry > 1)
		p1_label((long)(extsymtab - entryname - 1));

/* The main program isn't allowed to have parameters, so any given
   parameters are ignored */

	if(procclass == CLMAIN && !ep->arglist || procclass == CLBLOCK)
		return;

	/* Entry points in MAIN are an error, but we process them here */
	/* to prevent faults elsewhere. */

/* So now we're working with something other than CLMAIN or CLBLOCK.
   Determine the type of its return value. */

	impldcl( np = mkname(entryname->fextname) );
	type = np->vtype;
	proc_argchanges = prev_proc && type != entryname->extype;
	entryname->extseen = 1;
	if(proctype == TYUNKNOWN)
		if( (proctype = type) == TYCHAR)
			procleng = np->vleng ? np->vleng->constblock.Const.ci
					     : (ftnint) (-1);

	if(proctype == TYCHAR)
	{
		if(type != TYCHAR)
			err("noncharacter entry of character function");

/* Functions returning type   char   can only have multiple entries if all
   entries return the same length */

		else if( (np->vleng ? np->vleng->constblock.Const.ci :
		    (ftnint) (-1)) != procleng)
			err("mismatched character entry lengths");
	}
	else if(type == TYCHAR)
		err("character entry of noncharacter function");
	else if(type != proctype)
		multitype = YES;
	if(rtvlabel[type] == 0)
		rtvlabel[type] = (int)newlabel();
	ep->typelabel = rtvlabel[type];

	if(type == TYCHAR)
	{
		if(chslot < 0)
		{
			chslot = nextarg(TYADDR);
			chlgslot = nextarg(TYLENG);
		}
		np->vstg = STGARG;

/* Put a new argument in the function, one which will hold the result of
   a character function.  This will have to be named sometime, probably in
   mkarg(). */

		if(procleng < 0) {
			np->vleng = (expptr) mkarg(TYLENG, chlgslot);
			np->vleng->addrblock.uname_tag = UNAM_IDENT;
			strcpy (np -> vleng -> addrblock.user.ident,
				new_func_length());
			}
		if (!xretslot[TYCHAR]) {
			xretslot[TYCHAR] = rs =
				autovar(0, type, ISCONST(np->vleng)
					? np->vleng : ICON(0), "");
			strcpy(rs->user.ident, "ret_val");
			}
	}

/* Handle a   complex   return type -- declare a new parameter (pointer to
   a complex value) */

	else if( ISCOMPLEX(type) ) {
		if (!xretslot[type])
			xretslot[type] =
				autovar(0, type, EXNULL, " ret_val");
				/* the blank is for use in out_addr */
		np->vstg = STGARG;
		if(cxslot < 0)
			cxslot = nextarg(TYADDR);
		}
	else if (type != TYSUBR) {
		if (type == TYUNKNOWN) {
			dclerr("untyped function", np);
			proctype = type = np->vtype =
				dflttype[letter(np->fvarname[0])];
			}
		if (!xretslot[type])
			xretslot[type] = retslot =
				autovar(1, type, EXNULL, " ret_val");
				/* the blank is for use in out_addr */
		np->vstg = STGAUTO;
		}

	for(p = ep->arglist ; p ; p = p->nextp)
		if(! (( q = (Namep) (p->datap) )->vknownarg) ) {
			q->vknownarg = 1;
			q->vardesc.varno = nextarg(TYADDR);
			allargs = mkchain((char *)q, allargs);
			q->argno = nallargs++;
			}
		else if (nentry == 1)
			duparg(q);
		else for(p1 = ep->arglist ; p1 != p; p1 = p1->nextp)
			if ((Namep)p1->datap == q)
				duparg(q);

	k = 0;
	for(p = ep->arglist ; p ; p = p->nextp) {
		if(! (( q = (Namep) (p->datap) )->vdcldone) )
			{
			impldcl(q);
			q->vdcldone = YES;
			if(q->vtype == TYCHAR)
				{

/* If we don't know the length of a char*(*) (i.e. a string), we must add
   in this additional length argument. */

				++nallchargs;
				if (q->vclass == CLPROC)
					nallchargs--;
				else if (q->vleng == NULL) {
					/* character*(*) */
					q->vleng = (expptr)
					    mkarg(TYLENG, nextarg(TYLENG) );
					unamstring((Addrp)q->vleng,
						new_arg_length(q));
					}
				}
			}
		if (q->vdimfinish)
			dim_finish(q);
		if (q->vtype == TYCHAR && q->vclass != CLPROC)
			k++;
		}

	if (entryname->extype != type)
		changedtype(np);

	/* save information for checking consistency of arg lists */

	it = infertypes;
	if (entryname->exproto)
		infertypes = 1;
	save_argtypes(ep->arglist, &entryname->arginfo, &np->arginfo,
			0, np->fvarname, STGEXT, k, np->vtype, 2);
	infertypes = it;
}