diff --git a/sys/dev/wtap/if_wtap_module.c b/sys/dev/wtap/if_wtap_module.c --- a/sys/dev/wtap/if_wtap_module.c +++ b/sys/dev/wtap/if_wtap_module.c @@ -3,6 +3,10 @@ * * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -109,18 +113,23 @@ int fflag, struct thread *td) { int error = 0; + int id; CURVNET_SET(CRED_TO_VNET(curthread->td_ucred)); switch(cmd) { case WTAPIOCTLCRT: - if(new_wtap(hal, *(int *)data)) + if((id = new_wtap(hal, *(int *)data)) < 0) error = EINVAL; + memcpy(data, &id, sizeof(int)); break; case WTAPIOCTLDEL: if(free_wtap(hal, *(int *)data)) error = EINVAL; break; + case WTAPIOCTLLIST: + memcpy(data, &hal->hal_devs_set, sizeof(uint64_t)); + break; default: DWTAP_PRINTF("Unknown WTAP IOCTL\n"); error = EINVAL; diff --git a/sys/dev/wtap/if_wtapioctl.h b/sys/dev/wtap/if_wtapioctl.h --- a/sys/dev/wtap/if_wtapioctl.h +++ b/sys/dev/wtap/if_wtapioctl.h @@ -7,6 +7,11 @@ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -48,8 +53,9 @@ #define SIOCGATHSTATS _IOWR('i', 137, struct ifreq) #define SIOCZATHSTATS _IOWR('i', 139, struct ifreq) -#define WTAPIOCTLCRT _IOW('W', 1, int) +#define WTAPIOCTLCRT _IOWR('W', 1, int) #define WTAPIOCTLDEL _IOW('W', 2, int) +#define WTAPIOCTLLIST _IOR('W', 3, uint64_t) struct wtap_stats { u_int32_t ast_watchdog; /* device reset by watchdog */ diff --git a/sys/dev/wtap/if_wtapvar.h b/sys/dev/wtap/if_wtapvar.h --- a/sys/dev/wtap/if_wtapvar.h +++ b/sys/dev/wtap/if_wtapvar.h @@ -4,6 +4,11 @@ * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -84,7 +89,14 @@ #include "if_wtapioctl.h" -#define MAX_NBR_WTAP (64) +#ifndef MAX_NBR_WTAP +#define MAX_NBR_WTAP (64) // We support a maximum of 64 nodes for now +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE (MAX_NBR_WTAP / (int)(sizeof(uint32_t) * NBBY)) +#endif + #define BEACON_INTRERVAL (1000) MALLOC_DECLARE(M_WTAP); diff --git a/sys/dev/wtap/plugins/visibility.h b/sys/dev/wtap/plugins/visibility.h --- a/sys/dev/wtap/plugins/visibility.h +++ b/sys/dev/wtap/plugins/visibility.h @@ -4,6 +4,11 @@ * Copyright (c) 2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,8 +43,6 @@ #define CDEV_GET_SOFTC(x) (x)->si_drv1 -#define ARRAY_SIZE (32) //We support a maximum of 1024 nodes for now - struct vis_map { uint32_t map[ARRAY_SIZE]; }; diff --git a/sys/dev/wtap/plugins/visibility.c b/sys/dev/wtap/plugins/visibility.c --- a/sys/dev/wtap/plugins/visibility.c +++ b/sys/dev/wtap/plugins/visibility.c @@ -4,6 +4,11 @@ * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -199,6 +204,20 @@ #endif } +static int +get_link(struct visibility_plugin *vis_plugin, struct vis_map_req *req) +{ + struct wtap_hal *hal = vis_plugin->base.wp_hal; + + if (req->id < 0 || req->id >= MAX_NBR_WTAP || + !isset(hal->hal_devs_set, req->id)) + return -1; + + memcpy(&req->map, &vis_plugin->pl_node[req->id], sizeof(struct vis_map)); + + return 0; +} + int vis_ioctl(struct cdev *sdev, u_long cmd, caddr_t data, int fflag, struct thread *td) @@ -207,19 +226,20 @@ (struct visibility_plugin *) sdev->si_drv1; struct wtap_hal *hal = vis_plugin->base.wp_hal; struct link l; + struct vis_map_req *req; int op; int error = 0; CURVNET_SET(CRED_TO_VNET(curthread->td_ucred)); switch(cmd) { - case VISIOCTLOPEN: + case VISIOCTLSETOPEN: op = *(int *)data; if(op == 0) medium_close(hal->hal_md); else medium_open(hal->hal_md); break; - case VISIOCTLLINK: + case VISIOCTLSETLINK: l = *(struct link *)data; if(l.op == 0) del_link(vis_plugin, &l); @@ -228,6 +248,16 @@ #if 0 printf("op=%d, id1=%d, id2=%d\n", l.op, l.id1, l.id2); #endif + break; + case VISIOCTLGETOPEN: + memcpy(data, &hal->hal_md->open, sizeof(int)); + break; + case VISIOCTLGETMAP: + req = (struct vis_map_req *)data; + + if (get_link(vis_plugin, req) < 0) + error = EINVAL; + break; default: DWTAP_PRINTF("Unknown WTAP IOCTL\n"); diff --git a/sys/dev/wtap/plugins/visibility_ioctl.h b/sys/dev/wtap/plugins/visibility_ioctl.h --- a/sys/dev/wtap/plugins/visibility_ioctl.h +++ b/sys/dev/wtap/plugins/visibility_ioctl.h @@ -4,6 +4,11 @@ * Copyright (c) 2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -40,13 +45,28 @@ #include +#ifndef MAX_NBR_WTAP +#define MAX_NBR_WTAP (64) // We support a maximum of 64 nodes for now +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE (MAX_NBR_WTAP / (int)(sizeof(uint32_t) * NBBY)) +#endif + +struct vis_map_req { + int id; + uint32_t map[ARRAY_SIZE]; +}; + struct link { int op; //0 remove, 1 link int id1; int id2; }; -#define VISIOCTLOPEN _IOW('W', 3, int) // 0 close, 1 open -#define VISIOCTLLINK _IOW('W', 4, struct link) // +#define VISIOCTLSETOPEN _IOW('W', 4, int) // 0 close, 1 open +#define VISIOCTLSETLINK _IOW('W', 5, struct link) // +#define VISIOCTLGETOPEN _IOR('R', 6, int) +#define VISIOCTLGETMAP _IOWR('R', 7, struct vis_map_req) #endif diff --git a/sys/dev/wtap/wtap_hal/hal.h b/sys/dev/wtap/wtap_hal/hal.h --- a/sys/dev/wtap/wtap_hal/hal.h +++ b/sys/dev/wtap/wtap_hal/hal.h @@ -4,6 +4,11 @@ * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -45,6 +50,7 @@ struct mtx hal_mtx; struct wtap_plugin *plugin; struct wtap_softc *hal_devs[MAX_NBR_WTAP]; + uint32_t hal_devs_set[ARRAY_SIZE]; // We support a maximum of 64 nodes for now /* hardware information */ struct hw { struct callout timer_intr; diff --git a/sys/dev/wtap/wtap_hal/hal.c b/sys/dev/wtap/wtap_hal/hal.c --- a/sys/dev/wtap/wtap_hal/hal.c +++ b/sys/dev/wtap/wtap_hal/hal.c @@ -4,6 +4,11 @@ * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB * All rights reserved. * + * Copyright (c) 2023 The FreeBSD Foundation + * + * Portions of this software were developed by En-Wei Wu + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -65,6 +70,7 @@ { DWTAP_PRINTF("%s\n", __func__); + memset(hal->hal_devs_set, 0, sizeof(uint32_t) * ARRAY_SIZE); mtx_init(&hal->hal_mtx, "wtap_hal mtx", NULL, MTX_DEF | MTX_RECURSE); hal->hal_md = (struct wtap_medium *)malloc(sizeof(struct wtap_medium), @@ -107,7 +113,7 @@ int32_t new_wtap(struct wtap_hal *hal, int32_t id) { - static const uint8_t mac_pool[64][IEEE80211_ADDR_LEN] = { + static const uint8_t mac_pool[MAX_NBR_WTAP][IEEE80211_ADDR_LEN] = { {0,152,154,152,150,151}, {0,152,154,152,150,152}, {0,152,154,152,150,153}, @@ -175,12 +181,37 @@ }; DWTAP_PRINTF("%s\n", __func__); + + /* When id < 0, automate the assignmanet of wtap device by + * finding the least significant clear bit in hal->hal_devs_set + */ + if (id < 0) { + int i; + for (i = 0; i < MAX_NBR_WTAP; i++) { + if (!isset(hal->hal_devs_set, i)) { + id = i; + break; + } + } + + if (i == MAX_NBR_WTAP) { + DWTAP_PRINTF("%s: wtap device is full\n", __func__); + return -1; + } + } + uint8_t const *macaddr = mac_pool[id]; - if(hal->hal_devs[id] != NULL){ + if (isset(hal->hal_devs_set, id)) { printf("error, wtap_id=%d already created\n", id); return -1; } + if (id >= MAX_NBR_WTAP) { + DWTAP_PRINTF("error, wtap_id=%d must be between 0 and 63\n", id); + return -1; + } + + setbit(hal->hal_devs_set, id); hal->hal_devs[id] = (struct wtap_softc *)malloc( sizeof(struct wtap_softc), M_WTAP, M_NOWAIT | M_ZERO); hal->hal_devs[id]->sc_md = hal->hal_md; @@ -196,7 +227,7 @@ return -1; } - return 0; + return id; } int32_t @@ -204,13 +235,21 @@ { DWTAP_PRINTF("%s\n", __func__); - if(hal->hal_devs[id] == NULL){ + + if (id < 0 || id >= MAX_NBR_WTAP) { + DWTAP_PRINTF("error, wtap_id=%d must be between 0 and 63\n", id); + return -1; + } + + if(!isset(hal->hal_devs_set, id)){ printf("error, wtap_id=%d never created\n", id); return -1; } if(wtap_detach(hal->hal_devs[id])) printf("%s, cant alloc new wtap\n", __func__); + + clrbit(hal->hal_devs_set, id); mtx_destroy(&hal->hal_devs[id]->sc_mtx); free(hal->hal_devs[id], M_WTAP); hal->hal_devs[id] = NULL; diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -102,6 +102,7 @@ wake \ watch \ watchdogd \ + wtapctl \ zic \ zonectl diff --git a/usr.sbin/wtapctl/Makefile b/usr.sbin/wtapctl/Makefile new file mode 100644 --- /dev/null +++ b/usr.sbin/wtapctl/Makefile @@ -0,0 +1,8 @@ +PACKAGE=runtime +PROG= wtapctl +SRCS= wtapctl.c +MAN= wtapctl.8 + +CFLAGS+= -I${SRCTOP}/sys/dev/wtap + +.include diff --git a/usr.sbin/wtapctl/wtapctl.h b/usr.sbin/wtapctl/wtapctl.h new file mode 100644 --- /dev/null +++ b/usr.sbin/wtapctl/wtapctl.h @@ -0,0 +1,81 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by En-Wei Wu under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE + */ + +#ifndef _WTAPCTL_H_ +#define _WTAPCTL_H_ + +struct cmd { + const char *c_name; + const int c_arg_flag; +#define ARG_NOARG 0xfffffffb +#define ARG_NEXTARGOPT 0xfffffffc +#define ARG_NEXTARG 0xfffffffd +#define ARG_NEXTARG2 0xfffffffe +#define ARG_NULL 0xffffffff + union { + void (*c_func_noarg)(const struct cmd *); + void (*c_func_arg)(const struct cmd *, int); + void (*c_func_arg2)(const struct cmd *, int, int); + } c_u; +#define c_func_noarg c_u.c_func_noarg +#define c_func_arg c_u.c_func_arg +#define c_func_arg2 c_u.c_func_arg2 +}; + +#define CMD_SENTINEL { NULL, ARG_NULL, { NULL } } + +#define DEF_CMD_NOARG(name, func) { \ + .c_name = (name), \ + .c_arg_flag = ARG_NOARG, \ + .c_func_noarg = (func) \ +} + +#define DEF_CMD_ARGOPT(name, func) { \ + .c_name = (name), \ + .c_arg_flag = ARG_NEXTARGOPT, \ + .c_func_arg = (func) \ +} + +#define DEF_CMD_ARG(name, func) { \ + .c_name = (name), \ + .c_arg_flag = ARG_NEXTARG, \ + .c_func_arg = (func) \ +} + +#define DEF_CMD_ARG2(name, func) { \ + .c_name = (name), \ + .c_arg_flag = ARG_NEXTARG2, \ + .c_func_arg2 = (func) \ +} + +#define WTAP_DEV_NODE "/dev/wtapctl" +#define VIS_DEV_NODE "/dev/visctl" + +#endif /* _WTAPCTL_H_ */ diff --git a/usr.sbin/wtapctl/wtapctl.8 b/usr.sbin/wtapctl/wtapctl.8 new file mode 100644 --- /dev/null +++ b/usr.sbin/wtapctl/wtapctl.8 @@ -0,0 +1,97 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2023 The FreeBSD Foundation +.\" +.\" This software was developed by En-Wei Wu under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE +.\" +.Dd January 6, 2023 +.Dt WTAPCTL 8 +.Os +.Sh NAME +.Nm wtapctl +.Nd "configure wtap device parameters" +.Sh SYNOPSIS +.Nm +.Cm device Cm create Op Ar id +.Pp +.Nm +.Cm device Cm delete Ar id +.Pp +.Nm +.Cm device Cm delete Cm list +.Pp +.Nm +.Cm vis Op Cm open | Cm close +.Pp +.Nm +.Cm vis Op Cm add | delete +.Ar id_from Ar id_to +.Pp +.Nm +.Cm vis Cm show Ar id +.Sh DESCRIPTION +The +.Nm +utility controls two aspects of the wtap system: +device manipulation and visibility control. +.Pp +The device manipulation function allows users to +create and delete wtap devices, and once a device is created, +users can use +.Xr ifconfig 8 +to create network interfaces on top of the wtap device. +.Pp +The visibility control function manages the +visibility of the wtap devices. +.Sh EXAMPLES +For example, create two wtap devices, and allow them to transmit +packets to each other : +.Pp +.Dl # wtapctl device create 0 +.Pp +.Dl # wtapctl device create 1 +.Pp +.Dl # wtapctl vis add 0 1 +.Pp +.Dl # wtapctl vis add 1 0 +.Pp +Show the list of wtap devices: +.Pp +.Dl # wtapctl device list +.Pp +Check the devices wtap0 can reach: +.Pp +.Dl # wtapctl vis show 0 +.El +.Sh SEE ALSO +.Xr ifconfig 8 , +.Xr net80211 4 , +.Xr ieee80211 9 , +.Xr wlan 4 +.Sh HISTORY +The +.Nm +utility first appeared in FreeBSD 14.0. diff --git a/usr.sbin/wtapctl/wtapctl.c b/usr.sbin/wtapctl/wtapctl.c new file mode 100644 --- /dev/null +++ b/usr.sbin/wtapctl/wtapctl.c @@ -0,0 +1,269 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by En-Wei Wu under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE + */ + +#include +#include +#include +#include +#include +#include + +#include "wtapctl.h" + +#include "if_wtapioctl.h" +#include "plugins/visibility_ioctl.h" + +static int dev_fd = -1; +static int vis_fd = -1; +static struct cmd *cmds = NULL; + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", + "wtapctl device create [id]", + "wtapctl device delete ", + "wtapctl device list", + "wtapctl vis [open | close]", + "wtapctl vis [add | delete] ", + "wtapctl vis show "); + exit(1); +} + +static void +device_create(const struct cmd *cmd __unused, int id) +{ + int old_id = id; + + if (ioctl(dev_fd, WTAPIOCTLCRT, &id) < 0) + errx(1, "error creating wtap with id=%d", id); + + if (old_id != id) + printf("wtap%d\n", id); +} + +static void +device_delete(const struct cmd *cmd __unused, int id) +{ + if (ioctl(dev_fd, WTAPIOCTLDEL, &id) < 0) + errx(1, "error deleting wtap with id=%d", id); +} + +static void +device_list(const struct cmd *cmd __unused) +{ + uint64_t devs_set; + int id; + + if (ioctl(dev_fd, WTAPIOCTLLIST, &devs_set) < 0) + errx(1, "error getting wtap device list"); + + for (id = 0; id < MAX_NBR_WTAP; id++) + if (isset(&devs_set, id)) + printf("wtap%d ", id); + + printf("\n"); +} + +static void +vis_toggle_medium(const struct cmd *cmd) +{ + int op; + + if (strcmp(cmd->c_name, "open") == 0) + op = 1; + else + op = 0; + + if (ioctl(vis_fd, VISIOCTLSETOPEN, &op) < 0) + errx(1, "error %s medium\n", (op == 1 ? "opening": "closing")); +} + + +static void +vis_link_op(const struct cmd *cmd, int id1, int id2) +{ + struct link l; + + if (strcmp(cmd->c_name, "add") == 0) + l.op = 1; + else + l.op = 0; + + l.id1 = id1; + l.id2 = id2; + + if (ioctl(vis_fd, VISIOCTLSETLINK, &l) < 0) + errx(1, "error making a link operation"); +} + +static void +vis_link_show(const struct cmd *cmd __unused, int id) +{ + int is_open, i, j; + struct vis_map_req req; + + if (id < 0 || id >= MAX_NBR_WTAP) + errx(1, "device id must be between 0 and 63"); + + req.id = id; + + if (ioctl(vis_fd, VISIOCTLGETOPEN, &is_open) < 0) + errx(1, "error getting medium state"); + + if (ioctl(vis_fd, VISIOCTLGETMAP, &req) < 0) + errx(1, "error getting link information of id=%d", id); + + printf("medium: %s\n", is_open ? "open": "close"); + + printf("wtap%d -> ", id); + + for (i = 0; i < ARRAY_SIZE; i++) { + uint32_t vis = req.map[i]; + + for (j = 0; j < 32; j++) { + if (vis & 0x1) + printf("wtap%d ", i * ARRAY_SIZE + j); + + vis >>= 1; + } + } + + printf("\n"); +} + +static struct cmd * +find_command(const char *cmdstr) +{ + int i; + struct cmd *cmd; + + for (i = 0; ; i++) { + cmd = &cmds[i]; + + /* Sentinel */ + if (cmd->c_name == NULL) + return NULL; + + if (strcmp(cmd->c_name, cmdstr) == 0) + return cmd; + } + + return NULL; +} + +static void +run_command(const struct cmd *cmd, int argc, const char *argv[]) +{ + int arg; + + switch (cmd->c_arg_flag) { + case ARG_NOARG: + if (argc != 0) + usage(); + + cmd->c_func_noarg(cmd); + break; + case ARG_NEXTARGOPT: + if (argc > 1) + usage(); + + arg = argc ? atoi(argv[0]) : -1; + cmd->c_func_arg(cmd, arg); + break; + case ARG_NEXTARG: + if (argc != 1) + usage(); + + cmd->c_func_arg(cmd, atoi(argv[0])); + break; + case ARG_NEXTARG2: + if (argc != 2) + usage(); + + cmd->c_func_arg2(cmd, atoi(argv[0]), atoi(argv[1])); + break; + default: + errx(1, "internal fault"); + } +} + +static struct cmd dev_cmds[] = { + DEF_CMD_ARGOPT("create", device_create), + DEF_CMD_ARG("delete", device_delete), + DEF_CMD_NOARG("list", device_list), + CMD_SENTINEL +}; + +static struct cmd vis_cmds[] = { + DEF_CMD_NOARG("open", vis_toggle_medium), + DEF_CMD_NOARG("close", vis_toggle_medium), + DEF_CMD_ARG2("add", vis_link_op), + DEF_CMD_ARG2("delete", vis_link_op), + DEF_CMD_ARG("show", vis_link_show), + CMD_SENTINEL +}; + +int +main(int argc, const char *argv[]) +{ + if (argc < 3) + usage(); + + struct cmd *cmd; + + if (strcmp(argv[1], "device") == 0) { + cmds = dev_cmds; + } else if (strcmp(argv[1], "vis") == 0) { + cmds = vis_cmds; + } else { + usage(); + } + + cmd = find_command(argv[2]); + if (!cmd) + usage(); + + argc -= 3; + argv += 3; + + /* We defer opening file descriptor until now */ + dev_fd = open(WTAP_DEV_NODE, O_RDONLY); + if (dev_fd < 0) + errx(1, "error opening %s", WTAP_DEV_NODE); + + vis_fd = open(VIS_DEV_NODE, O_RDONLY); + if (vis_fd < 0) + errx(1, "error opening %s", VIS_DEV_NODE); + + run_command(cmd, argc, argv); + + return 0; +}