154359Sroberto/*
256746Sroberto * Copyright (c) 1999
354359Sroberto *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
456746Sroberto *
554359Sroberto * Redistribution and use in source and binary forms, with or without
654359Sroberto * modification, are permitted provided that the following conditions
754359Sroberto * are met:
854359Sroberto * 1. Redistributions of source code must retain the above copyright
954359Sroberto *    notice, this list of conditions and the following disclaimer.
1054359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1154359Sroberto *    notice, this list of conditions and the following disclaimer in the
1254359Sroberto *    documentation and/or other materials provided with the distribution.
1354359Sroberto * 3. All advertising materials mentioning features or use of this software
1454359Sroberto *    must display the following acknowledgement:
1554359Sroberto *	This product includes software developed by Bill Paul.
1654359Sroberto * 4. Neither the name of the author nor the names of any co-contributors
1754359Sroberto *    may be used to endorse or promote products derived from this software
1854359Sroberto *    without specific prior written permission.
1954359Sroberto *
2054359Sroberto * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2154359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2254359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2354359Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2454359Sroberto * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2554359Sroberto * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2654359Sroberto * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2754359Sroberto * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2854359Sroberto * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2954359Sroberto * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3054359Sroberto * THE POSSIBILITY OF SUCH DAMAGE.
3154359Sroberto */
3254359Sroberto
3354359Sroberto#include <sys/param.h>
3454359Sroberto#include <sys/ioctl.h>
3554359Sroberto#include <sys/socket.h>
3654359Sroberto#include <sys/sockio.h>
3754359Sroberto
3854359Sroberto#include <stdlib.h>
3954359Sroberto#include <unistd.h>
4054359Sroberto
4154359Sroberto#include <net/ethernet.h>
4254359Sroberto#include <net/if.h>
4354359Sroberto#include <net/if_var.h>
4454359Sroberto#include <net/if_vlan_var.h>
4554359Sroberto#include <net/route.h>
4654359Sroberto
4754359Sroberto#include <ctype.h>
4854359Sroberto#include <stdio.h>
4954359Sroberto#include <string.h>
5054359Sroberto#include <stdlib.h>
5154359Sroberto#include <unistd.h>
5254359Sroberto#include <err.h>
5354359Sroberto#include <errno.h>
5454359Sroberto
5554359Sroberto#include "ifconfig.h"
5654359Sroberto
5754359Sroberto#ifndef lint
5854359Srobertostatic const char rcsid[] =
5954359Sroberto  "$FreeBSD: releng/10.3/sbin/ifconfig/ifvlan.c 289986 2015-10-26 03:43:28Z ngie $";
6054359Sroberto#endif
6154359Sroberto
6254359Sroberto#define	NOTAG	((u_short) -1)
6354359Sroberto
6454359Srobertostatic 	struct vlanreq params = {
6554359Sroberto	.vlr_tag	= NOTAG,
6654359Sroberto};
6754359Sroberto
6854359Srobertostatic int
6954359Srobertogetvlan(int s, struct ifreq *ifr, struct vlanreq *vreq)
7054359Sroberto{
7154359Sroberto	bzero((char *)vreq, sizeof(*vreq));
7254359Sroberto	ifr->ifr_data = (caddr_t)vreq;
7354359Sroberto
7454359Sroberto	return ioctl(s, SIOCGETVLAN, (caddr_t)ifr);
7554359Sroberto}
7654359Sroberto
7754359Srobertostatic void
7854359Srobertovlan_status(int s)
7954359Sroberto{
8054359Sroberto	struct vlanreq		vreq;
8154359Sroberto
8254359Sroberto	if (getvlan(s, &ifr, &vreq) != -1)
8354359Sroberto		printf("\tvlan: %d parent interface: %s\n",
8454359Sroberto		    vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
8554359Sroberto		    "<none>" : vreq.vlr_parent);
8654359Sroberto}
8754359Sroberto
8854359Srobertostatic void
8954359Srobertovlan_create(int s, struct ifreq *ifr)
9054359Sroberto{
9154359Sroberto	if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
9254359Sroberto		/*
9354359Sroberto		 * One or both parameters were specified, make sure both.
9454359Sroberto		 */
9554359Sroberto		if (params.vlr_tag == NOTAG)
9654359Sroberto			errx(1, "must specify a tag for vlan create");
9754359Sroberto		if (params.vlr_parent[0] == '\0')
9854359Sroberto			errx(1, "must specify a parent device for vlan create");
9954359Sroberto		ifr->ifr_data = (caddr_t) &params;
10054359Sroberto	}
10154359Sroberto	if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
10254359Sroberto		err(1, "SIOCIFCREATE2");
10354359Sroberto}
10454359Sroberto
10554359Srobertostatic void
10654359Srobertovlan_cb(int s, void *arg)
10754359Sroberto{
10854359Sroberto	if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0'))
10954359Sroberto		errx(1, "both vlan and vlandev must be specified");
11054359Sroberto}
11154359Sroberto
11254359Srobertostatic void
11354359Srobertovlan_set(int s, struct ifreq *ifr)
11454359Sroberto{
11554359Sroberto	if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') {
11654359Sroberto		ifr->ifr_data = (caddr_t) &params;
11754359Sroberto		if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1)
11854359Sroberto			err(1, "SIOCSETVLAN");
11954359Sroberto	}
12054359Sroberto}
12154359Sroberto
12254359Srobertostatic
12354359SrobertoDECL_CMD_FUNC(setvlantag, val, d)
12454359Sroberto{
12554359Sroberto	struct vlanreq vreq;
12654359Sroberto	u_long ul;
12754359Sroberto	char *endp;
12854359Sroberto
12954359Sroberto	ul = strtoul(val, &endp, 0);
13054359Sroberto	if (*endp != '\0')
13154359Sroberto		errx(1, "invalid value for vlan");
13254359Sroberto	params.vlr_tag = ul;
13354359Sroberto	/* check if the value can be represented in vlr_tag */
13454359Sroberto	if (params.vlr_tag != ul)
13554359Sroberto		errx(1, "value for vlan out of range");
13654359Sroberto
13754359Sroberto	if (getvlan(s, &ifr, &vreq) != -1)
13854359Sroberto		vlan_set(s, &ifr);
13954359Sroberto}
14054359Sroberto
14154359Srobertostatic
14254359SrobertoDECL_CMD_FUNC(setvlandev, val, d)
14354359Sroberto{
14454359Sroberto	struct vlanreq vreq;
14554359Sroberto
14654359Sroberto	strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent));
14754359Sroberto
14854359Sroberto	if (getvlan(s, &ifr, &vreq) != -1)
14954359Sroberto		vlan_set(s, &ifr);
15054359Sroberto}
15154359Sroberto
15254359Srobertostatic
15354359SrobertoDECL_CMD_FUNC(unsetvlandev, val, d)
15454359Sroberto{
15554359Sroberto	struct vlanreq		vreq;
15654359Sroberto
15754359Sroberto	bzero((char *)&vreq, sizeof(struct vlanreq));
15854359Sroberto	ifr.ifr_data = (caddr_t)&vreq;
15954359Sroberto
16054359Sroberto	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
16154359Sroberto		err(1, "SIOCGETVLAN");
16254359Sroberto
16354359Sroberto	bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
16454359Sroberto	vreq.vlr_tag = 0;
16554359Sroberto
16654359Sroberto	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
16754359Sroberto		err(1, "SIOCSETVLAN");
16854359Sroberto}
16954359Sroberto
17054359Srobertostatic struct cmd vlan_cmds[] = {
17154359Sroberto	DEF_CLONE_CMD_ARG("vlan",			setvlantag),
17254359Sroberto	DEF_CLONE_CMD_ARG("vlandev",			setvlandev),
17354359Sroberto	/* NB: non-clone cmds */
17454359Sroberto	DEF_CMD_ARG("vlan",				setvlantag),
17554359Sroberto	DEF_CMD_ARG("vlandev",				setvlandev),
17654359Sroberto	/* XXX For compatibility.  Should become DEF_CMD() some day. */
17754359Sroberto	DEF_CMD_OPTARG("-vlandev",			unsetvlandev),
17854359Sroberto	DEF_CMD("vlanmtu",	IFCAP_VLAN_MTU,		setifcap),
17954359Sroberto	DEF_CMD("-vlanmtu",	-IFCAP_VLAN_MTU,	setifcap),
18054359Sroberto	DEF_CMD("vlanhwtag",	IFCAP_VLAN_HWTAGGING,	setifcap),
18154359Sroberto	DEF_CMD("-vlanhwtag",	-IFCAP_VLAN_HWTAGGING,	setifcap),
18254359Sroberto	DEF_CMD("vlanhwfilter",	IFCAP_VLAN_HWFILTER,	setifcap),
18354359Sroberto	DEF_CMD("-vlanhwfilter", -IFCAP_VLAN_HWFILTER,	setifcap),
18454359Sroberto	DEF_CMD("-vlanhwtso",	-IFCAP_VLAN_HWTSO,	setifcap),
18554359Sroberto	DEF_CMD("vlanhwtso",	IFCAP_VLAN_HWTSO,	setifcap),
18654359Sroberto	DEF_CMD("vlanhwcsum",	IFCAP_VLAN_HWCSUM,	setifcap),
18754359Sroberto	DEF_CMD("-vlanhwcsum",	-IFCAP_VLAN_HWCSUM,	setifcap),
18854359Sroberto};
18954359Srobertostatic struct afswtch af_vlan = {
19054359Sroberto	.af_name	= "af_vlan",
19154359Sroberto	.af_af		= AF_UNSPEC,
19254359Sroberto	.af_other_status = vlan_status,
19354359Sroberto};
19454359Sroberto
19554359Srobertostatic __constructor void
19654359Srobertovlan_ctor(void)
19754359Sroberto{
19854359Sroberto	size_t i;
19954359Sroberto
20054359Sroberto	for (i = 0; i < nitems(vlan_cmds);  i++)
20154359Sroberto		cmd_register(&vlan_cmds[i]);
20254359Sroberto	af_register(&af_vlan);
20354359Sroberto	callback_register(vlan_cb, NULL);
20454359Sroberto	clone_setdefcallback("vlan", vlan_create);
20554359Sroberto}
20654359Sroberto