pax_global_header00006660000000000000000000000064134064503250014514gustar00rootroot0000000000000052 comment=a316ca2caa746d60817400e5bf646c2820f09273 wpan-tools-0.9/000077500000000000000000000000001340645032500134675ustar00rootroot00000000000000wpan-tools-0.9/.gitignore000066400000000000000000000001531340645032500154560ustar00rootroot00000000000000*.o tags TAGS Makefile Makefile.in aclocal.m4 autom4te.cache build-aux config.* configure libtool stamp-h1 wpan-tools-0.9/.travis.yml000066400000000000000000000025611340645032500156040ustar00rootroot00000000000000env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - secure: "UvgSRxPnTZIC5ypFu8nzLPozWAarw3f9ZJEKaVBbQTa1dhHoEBwVutW5YJws9QzjBoKy0MRatRbMkZPJGkQGFSRgF4USnbs6SCbKOqhCVue3VjJ6T7V450AMJiD5IvvxSHStbJDDfmFYqZM/h2LKv5MOdtGqgXZLhkgL2sMUmZqi2Js0pSv9DwSFNMAvTYV6k2lnWIDVChO/cKDFM4CBKBj50nPS0UnlbuuWLExkBs31Z3zAut084kAjtGzaJJHLvU7g/DYqyPlJV8aYT43HqZeXMqeCtXkxSYTuN0sqQCvFNtB4J9E2aVR6UQyUV0t6VAqZYqO//XUnshtRvenNR3Fml9EkKlUVywHaTHRtm37l/IQteqiNa1ET9HQEnOdKGQxLck6New6sOPP33n7ZKaN+z+9s554aNAxowL7+TtVLXvTbuel2LwQUXlClW+v6/Z3KU9QESdWKAyfepgKidpyri5/SzqgLOHZVtKPnLnfkIJmEVRxL+KSyejWUTN2xi0Bh7wPeeZwK1Vh1WycIaalY6I/SAK0AEDb8IYwYhlJaoIbUSuHtGbKsXZogWK36lpYqe8wetBwIrTgqjYHWCRIRXKcybWzFDb7cvHivcUKmQ0fxLg1K/WSustb5t4CnmHbeFAriok5NW4DOW29okOfaR5KggacdctfbkuE0ZQ8=" notifications: irc: "chat.freenode.net#linux-wpan" language: c sudo: false compiler: - clang - gcc addons: apt: packages: - libnl-3-dev - libnl-genl-3-dev coverity_scan: project: name: "linux-wpan/wpan-tools" description: "Build submitted via Travis CI" notification_email: stefan@datenfreihafen.org build_command_prepend: "./autogen.sh && ./configure && make clean" build_command: "make -j 4" branch_pattern: coverity_scan script: ./autogen.sh && ./configure && make wpan-tools-0.9/COPYING000066400000000000000000000017101340645032500145210ustar00rootroot00000000000000Copyright (c) 2014 Alexander Aring Copyright (c) 2015 Stefan Schmidt Code is based on iw tool. Original Authors: Copyright (c) 2007, 2008 Johannes Berg Copyright (c) 2007 Andy Lutomirski Copyright (c) 2007 Mike Kershaw Copyright (c) 2008-2009 Luis R. Rodriguez Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. wpan-tools-0.9/Makefile.am000066400000000000000000000007141340645032500155250ustar00rootroot00000000000000EXTRA_DIST = CLEANFILES = ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} AM_MAKEFLAGS = --no-print-directory AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -I${top_srcdir}/src AM_CFLAGS = ${WPAN_TOOLS_CFLAGS} \ -fvisibility=hidden \ -ffunction-sections \ -fdata-sections AM_LDFLAGS = \ -Wl,--gc-sections \ -Wl,--as-needed SUBDIRS = \ src \ wpan-ping \ wpan-hwsim \ examples wpan-tools-0.9/autogen.sh000077500000000000000000000012741340645032500154740ustar00rootroot00000000000000#!/bin/sh -e if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ chmod +x .git/hooks/pre-commit && \ echo "Activated pre-commit hook." fi autoreconf --install --symlink libdir() { echo $(cd $1/$(gcc -print-multi-os-directory); pwd) } args="--prefix=/usr \ --sysconfdir=/etc \ --libdir=$(libdir /usr/lib)" echo echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo echo "./configure CFLAGS='-g -O0' $args" echo wpan-tools-0.9/configure.ac000066400000000000000000000025151340645032500157600ustar00rootroot00000000000000AC_PREREQ(2.60) AC_INIT([Userspace tools for Linux IEEE 802.15.4 stack], [0.9], [linux-wpan@vger.kernel.org], [wpan-tools], [https://github.com/linux-wpan/wpan-tools]) AC_CONFIG_SRCDIR([src/iwpan.c]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([ foreign 1.11 -Wall -Werror -Wno-portability silent-rules tar-pax dist-xz subdir-objects ]) AC_PROG_CC_STDC AC_USE_SYSTEM_EXTENSIONS AC_SYS_LARGEFILE AC_CONFIG_MACRO_DIR([m4]) AM_SILENT_RULES([yes]) LT_INIT([ disable-static pic-only ]) AC_PREFIX_DEFAULT([/usr]) AC_PROG_SED AC_PROG_MKDIR_P PKG_CHECK_MODULES(LIBNL3, [libnl-3.0 >= 3.1 libnl-genl-3.0 >= 3.1]) AC_CHECK_FUNCS([ \ __secure_getenv \ secure_getenv\ ]) WPAN_TOOLS_CFLAGS="\ -Wall \ -Wchar-subscripts \ -Wformat-security \ -Wmissing-declarations \ -Wmissing-prototypes \ -Wnested-externs \ -Wpointer-arith \ -Wshadow \ -Wsign-compare \ -Wstrict-prototypes \ -Wtype-limits \ " AC_SUBST([WPAN_TOOLS_CFLAGS]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES([ Makefile src/Makefile wpan-ping/Makefile wpan-hwsim/Makefile examples/Makefile ]) AC_OUTPUT AC_MSG_RESULT([ $PACKAGE $VERSION ===== prefix: ${prefix} sysconfdir: ${sysconfdir} compiler: ${CC} cflags: ${CFLAGS} ldflags: ${LDFLAGS} ]) wpan-tools-0.9/examples/000077500000000000000000000000001340645032500153055ustar00rootroot00000000000000wpan-tools-0.9/examples/.gitignore000066400000000000000000000001411340645032500172710ustar00rootroot00000000000000/.deps /af_ieee802154_rx /af_ieee802154_tx /af_packet_rx /af_packet_tx /af_inet6_rx /af_inet6_tx wpan-tools-0.9/examples/Makefile.am000066400000000000000000000003051340645032500173370ustar00rootroot00000000000000noinst_PROGRAMS = af_ieee802154_tx \ af_ieee802154_rx \ af_packet_tx \ af_packet_rx \ af_inet6_tx \ af_inet6_rx EXTRA_DIST = README.examples wpan-tools-0.9/examples/README.examples000066400000000000000000000030161340645032500200020ustar00rootroot00000000000000This folder contains various examples on how the Linux-wpan stack can be used from userspace, using the Linux socket interface. These examples do not cover all socket programming functionality nor do they give a real introduction to it. Their aim is to provide some quick examples for using the Linux-wpan stack for developers familiar with socket programming. Keep in mind that the socket interface is used for the data plane. For the configuration plane you would use netlink, which is heavily demonstrated in iwpan itself. Examples: --------- Address family AF_IEEE802154 with type SOCK_DGRAM: * Direct usage of IEEE 802.15.4 frames, no 6LoWPAN involved * Short and extended address usage is demonstrated * af_ieee802154_rx loops and prints each received IEEE 802.15.4 frame on stdout * af_ieee802154_tx sends a IEEE 802.15.4 frame Address family AF_INET6 with type SOCK_DGRAM: * 6LoWPAN examples, IPv6 over IEEE 802.15.4 * af_inet6_rx binds on any IPv6 address on UDP port * af_inet6_tx sends an UDP packet to the IPv6 all nodes address Address family AF_PACKET with type SOCK_RAW: * Raw access to IEEE 8021.5.4 frames for rx and tx * Useful for sniffer, packet generators, network stack in userspace, etc * af_packet_rx loops and prints each frame as hexdump * af_packet_tx constructs the raw packet payload manually and sends it Some of the example need special privileges to run. If you get a error like: socket: Operation not permitted Make sure your user that the needed privileges or run the example with sudo. wpan-tools-0.9/examples/af_ieee802154_rx.c000066400000000000000000000056611340645032500202330ustar00rootroot00000000000000/* * IEEE 802.15.4 socket example * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * * Author: Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* gcc af_ieee802154_rx.c -o af_ieee802154_rx */ #include #include #include #include #include #include #define IEEE802154_ADDR_LEN 8 #define MAX_PACKET_LEN 127 #define EXTENDED 1 enum { IEEE802154_ADDR_NONE = 0x0, IEEE802154_ADDR_SHORT = 0x2, IEEE802154_ADDR_LONG = 0x3, }; struct ieee802154_addr_sa { int addr_type; uint16_t pan_id; union { uint8_t hwaddr[IEEE802154_ADDR_LEN]; uint16_t short_addr; }; }; struct sockaddr_ieee802154 { sa_family_t family; struct ieee802154_addr_sa addr; }; int main(int argc, char *argv[]) { int ret, sd; struct sockaddr_ieee802154 src, dst; unsigned char buf[MAX_PACKET_LEN + 1]; socklen_t addrlen; /* IEEE 802.15.4 extended address to receive frames on, adapt to your setup */ uint8_t long_addr[IEEE802154_ADDR_LEN] = {0xd6, 0x55, 0x2c, 0xd6, 0xe4, 0x1c, 0xeb, 0x57}; /* Create IEEE 802.15.4 address family socket for the SOCK_DGRAM type */ sd = socket(PF_IEEE802154, SOCK_DGRAM, 0); if (sd < 0) { perror("socket"); return 1; } /* Prepare source socket address struct */ memset(&src, 0, sizeof(src)); src.family = AF_IEEE802154; /* Used PAN ID is 0x23 here, adapt to your setup */ src.addr.pan_id = 0x0023; #if EXTENDED /* IEEE 802.15.4 extended address usage */ src.addr.addr_type = IEEE802154_ADDR_LONG; memcpy(&src.addr.hwaddr, &long_addr, IEEE802154_ADDR_LEN); #else src.addr.addr_type = IEEE802154_ADDR_SHORT; src.addr.short_addr = 0x0002; #endif /* Bind socket on this side */ ret = bind(sd, (struct sockaddr *)&src, sizeof(src)); if (ret) { perror("bind"); close(sd); return 1; } addrlen = sizeof(dst); /* Infinite loop receiving 802.15.4 frames and print out */ while (1) { ret = recvfrom(sd, buf, MAX_PACKET_LEN, 0, (struct sockaddr *)&dst, &addrlen); if (ret < 0) { perror("recvfrom"); continue; } buf[ret] = '\0'; #if EXTENDED printf("Received (from %s): %s\n", dst.addr.hwaddr, buf); #else printf("Received (from %x): %s\n", dst.addr.short_addr, buf); #endif } shutdown(sd, SHUT_RDWR); close(sd); return 0; } wpan-tools-0.9/examples/af_ieee802154_tx.c000066400000000000000000000051701340645032500202300ustar00rootroot00000000000000/* * IEEE 802.15.4 socket example * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * * Author: Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* gcc af_ieee802154_tx.c -o af_ieee802154_tx */ #include #include #include #include #include #include #define IEEE802154_ADDR_LEN 8 #define MAX_PACKET_LEN 127 #define EXTENDED 1 enum { IEEE802154_ADDR_NONE = 0x0, IEEE802154_ADDR_SHORT = 0x2, IEEE802154_ADDR_LONG = 0x3, }; struct ieee802154_addr_sa { int addr_type; uint16_t pan_id; union { uint8_t hwaddr[IEEE802154_ADDR_LEN]; uint16_t short_addr; }; }; struct sockaddr_ieee802154 { sa_family_t family; struct ieee802154_addr_sa addr; }; int main(int argc, char *argv[]) { int sd; ssize_t len; struct sockaddr_ieee802154 dst; char buf[MAX_PACKET_LEN + 1]; /* IEEE 802.15.4 extended send address, adapt to your setup */ uint8_t long_addr[IEEE802154_ADDR_LEN] = {0xd6, 0x55, 0x2c, 0xd6, 0xe4, 0x1c, 0xeb, 0x57}; /* Create IEEE 802.15.4 address family socket for the SOCK_DGRAM type */ sd = socket(PF_IEEE802154, SOCK_DGRAM, 0); if (sd < 0) { perror("socket"); return 1; } /* Prepare destination socket address struct */ memset(&dst, 0, sizeof(dst)); dst.family = AF_IEEE802154; /* Used PAN ID is 0x23 here, adapt to your setup */ dst.addr.pan_id = 0x0023; #if EXTENDED /* IEEE 802.15.4 extended address usage */ dst.addr.addr_type = IEEE802154_ADDR_LONG; memcpy(&dst.addr.hwaddr, long_addr, IEEE802154_ADDR_LEN); #else dst.addr.addr_type = IEEE802154_ADDR_SHORT; dst.addr.short_addr = 0x0002; #endif sprintf(buf, "Hello world from IEEE 802.15.4 socket example!"); /* sendto() is used for implicity in this example, bin()/send() would * be an alternative */ len = sendto(sd, buf, strlen(buf), 0, (struct sockaddr *)&dst, sizeof(dst)); if (len < 0) { perror("sendto"); } shutdown(sd, SHUT_RDWR); close(sd); return 0; } wpan-tools-0.9/examples/af_inet6_rx.c000066400000000000000000000043511340645032500176600ustar00rootroot00000000000000/* * IEEE 802.15.4 socket example * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * * Author: Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* gcc af_inet6_rx.c -o af_inet6_rx */ #include #include #include #include #include #include #define MAX_PACKET_LEN 2048 int main(int argc, char *argv[]) { int ret, sd; ssize_t len; struct sockaddr_in6 src, dst; unsigned char buf[MAX_PACKET_LEN + 1]; socklen_t addrlen; char ipv6[INET6_ADDRSTRLEN]; /* Create IPv6 address family socket for the SOCK_DGRAM type */ sd = socket(PF_INET6, SOCK_DGRAM, 0); if (sd < 0) { perror("socket"); return 1; } /* Prepare source and destination socket address structs */ memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); src.sin6_family = AF_INET6; src.sin6_addr = in6addr_any; /* Port within the compressed port range for potential NHC UDP compression */ src.sin6_port = htons(61617); /* Bind socket on this side */ ret = bind(sd, (struct sockaddr *)&src, sizeof(src)); if (ret) { perror("bind"); close(sd); return 1; } addrlen = sizeof(dst); /* Infinite loop receiving IPv6 packets and print out */ while (1) { len = recvfrom(sd, buf, MAX_PACKET_LEN, 0, (struct sockaddr *)&dst, &addrlen); if (len < 0) { perror("recvfrom"); continue; } buf[len] = '\0'; inet_ntop(AF_INET6, &(dst.sin6_addr), ipv6, INET6_ADDRSTRLEN); printf("Received (from %s): %s\n", ipv6, buf); } shutdown(sd, SHUT_RDWR); close(sd); return 0; } wpan-tools-0.9/examples/af_inet6_tx.c000066400000000000000000000044321340645032500176620ustar00rootroot00000000000000/* * AF_INET6 over IEEE 802.15.4 socket example * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * * Author: Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* gcc af_inet6_tx.c -o af_inet6_tx */ #include #include #include #include #include #include #include #define IEEE802154_ADDR_LEN 8 #define MAX_PACKET_LEN 2048 int main(int argc, char *argv[]) { int ret, sd; struct sockaddr_in6 dst; struct ifreq ifr; char buf[MAX_PACKET_LEN + 1]; /* Create IPv6 address family socket for the SOCK_DGRAM type */ sd = socket(PF_INET6, SOCK_DGRAM, 0); if (sd < 0) { perror("socket"); return 1; } /* Bind the socket to lowpan0 to make sure we send over it, adapt to your setup */ memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "lowpan0"); ret = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)); if (ret < 0) { perror("setsockopt"); return 1; } /* Prepare destination socket address struct */ memset(&dst, 0, sizeof(dst)); dst.sin6_family = AF_INET6; /* Port within the compressed port range for potential NHC UDP compression */ dst.sin6_port = htons(61617); inet_pton(AF_INET6, "ff02::1", &(dst.sin6_addr)); sprintf(buf, "Hello world from AF_INET6 socket example!"); /* sendto() is used for implicity in this example, bin()/send() would * be an alternative */ ret = sendto(sd, buf, strlen(buf), 0, (struct sockaddr *)&dst, sizeof(dst)); if (ret < 0) { perror("sendto"); } shutdown(sd, SHUT_RDWR); close(sd); return 0; } wpan-tools-0.9/examples/af_packet_rx.c000066400000000000000000000045551340645032500201100ustar00rootroot00000000000000/* * IEEE 802.15.4 socket example * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * * Author: Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* gcc af_packet_rx.c -o af_packet_rx */ #include #include #include #include #include #include #include #include #include #define IEEE802154_ADDR_LEN 8 #define MAX_PACKET_LEN 127 #ifndef ETH_P_IEEE802154 #define ETH_P_IEEE802154 0x00F6 #endif int main(int argc, char *argv[]) { int ret, sd, i; ssize_t len; unsigned char buf[MAX_PACKET_LEN + 1]; struct sockaddr_ll sll; struct ifreq ifr; /* Create AF_PACKET address family socket for the SOCK_RAW type */ sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IEEE802154)); if (sd < 0) { perror("socket"); return 1; } /* Get interface index */ strncpy(ifr.ifr_name, "monitor0", IFNAMSIZ); ret = ioctl(sd, SIOCGIFINDEX, &ifr); if (ret < 0) { perror("ioctl"); close(sd); return 1; } /* Prepare source socket address struct */ memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons(ETH_P_IEEE802154); /* Bind socket on this side */ ret = bind(sd, (struct sockaddr *)&sll, sizeof(sll)); if (ret < 0) { perror("bind"); close(sd); return 1; } while (1) { /* Receive and print the whole packet payload, including FCS */ len = recv(sd, buf, MAX_PACKET_LEN, 0); if (len < 0) { perror("recv"); continue; } printf("Received:"); for (i = 0; i < len; i++) printf(" %x", buf[i]); printf("\n"); } shutdown(sd, SHUT_RDWR); close(sd); return 0; } wpan-tools-0.9/examples/af_packet_tx.c000066400000000000000000000060511340645032500201030ustar00rootroot00000000000000/* * IEEE 802.15.4 socket example * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * * Author: Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* gcc af_packet_tx.c -o af_packet_tx */ #include #include #include #include #include #include #include #include #include #ifndef ETH_P_IEEE802154 #define ETH_P_IEEE802154 0x00F6 #endif #define MAX_PACKET_LEN 127 int main(int argc, char *argv[]) { int ret, sd; ssize_t len; struct sockaddr_ll sll; struct ifreq ifr; unsigned char buf[MAX_PACKET_LEN + 1]; /* Create AF_PACKET address family socket for the SOCK_RAW type */ sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IEEE802154)); if (sd < 0) { perror("socket"); return 1; } /* Using a monitor interface here results in a bad FCS and two missing * bytes from payload, using the normal IEEE 802.15.4 interface here */ strncpy(ifr.ifr_name, "wpan0", IFNAMSIZ); ret = ioctl(sd, SIOCGIFINDEX, &ifr); if (ret < 0) { perror("ioctl"); close(sd); return 1; } /* Prepare destination socket address struct */ memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons(ETH_P_IEEE802154); /* Bind socket on this side */ ret = bind(sd, (struct sockaddr *)&sll, sizeof(sll)); if (ret < 0) { perror("bind"); close(sd); return 1; } /* Construct raw packet payload, length and FCS gets added in the kernel */ buf[0] = 0x21; /* Frame Control Field */ buf[1] = 0xc8; /* Frame Control Field */ buf[2] = 0x8b; /* Sequence number */ buf[3] = 0xff; /* Destination PAN ID 0xffff */ buf[4] = 0xff; /* Destination PAN ID */ buf[5] = 0x02; /* Destination short address 0x0002 */ buf[6] = 0x00; /* Destination short address */ buf[7] = 0x23; /* Source PAN ID 0x0023 */ buf[8] = 0x00; /* */ buf[9] = 0x60; /* Source extended address ae:c2:4a:1c:21:16:e2:60 */ buf[10] = 0xe2; /* */ buf[11] = 0x16; /* */ buf[12] = 0x21; /* */ buf[13] = 0x1c; /* */ buf[14] = 0x4a; /* */ buf[15] = 0xc2; /* */ buf[16] = 0xae; /* */ buf[17] = 0xAA; /* Payload */ buf[18] = 0xBB; /* */ buf[19] = 0xCC; /* */ /* Send constructed packet over binded interface */ len = send(sd, buf, 20, 0); if (len < 0) { perror("send"); } shutdown(sd, SHUT_RDWR); close(sd); return 0; } wpan-tools-0.9/m4/000077500000000000000000000000001340645032500140075ustar00rootroot00000000000000wpan-tools-0.9/m4/.gitignore000066400000000000000000000000771340645032500160030ustar00rootroot00000000000000libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4 wpan-tools-0.9/src/000077500000000000000000000000001340645032500142565ustar00rootroot00000000000000wpan-tools-0.9/src/.gitignore000066400000000000000000000000201340645032500162360ustar00rootroot00000000000000.deps iwpan *.o wpan-tools-0.9/src/Makefile.am000066400000000000000000000003401340645032500163070ustar00rootroot00000000000000bin_PROGRAMS = \ iwpan iwpan_SOURCES = \ iwpan.c \ iwpan.h \ sections.c \ info.c \ interface.c \ phy.c \ mac.c \ nl_extras.h \ nl802154.h iwpan_CFLAGS = $(AM_CFLAGS) $(LIBNL3_CFLAGS) iwpan_LDADD = $(LIBNL3_LIBS) wpan-tools-0.9/src/info.c000066400000000000000000000335541340645032500153670ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "nl802154.h" #include "nl_extras.h" #include "iwpan.h" static void print_minmax_handler(int min, int max) { int i; for (i = min; i <= max; i++) printf("%d,", i); /* TODO */ printf("\b \n"); } static void print_freq_handler(int channel_page, int channel) { float freq = 0; switch (channel_page) { case 0: if (channel == 0) { freq = 868.3; printf("%5.1f", freq); break; } else if (channel > 0 && channel < 11) { freq = 906 + 2 * (channel - 1); } else { freq = 2405 + 5 * (channel - 11); } printf("%5.0f", freq); break; case 1: if (channel == 0) { freq = 868.3; printf("%5.1f", freq); break; } else if (channel >= 1 && channel <= 10) { freq = 906 + 2 * (channel - 1); } printf("%5.0f", freq); break; case 2: if (channel == 0) { freq = 868.3; printf("%5.1f", freq); break; } else if (channel >= 1 && channel <= 10) { freq = 906 + 2 * (channel - 1); } printf("%5.0f", freq); break; case 3: if (channel >= 0 && channel <= 12) { freq = 2412 + 5 * channel; } else if (channel == 13) { freq = 2484; } printf("%4.0f", freq); break; case 4: switch (channel) { case 0: freq = 499.2; break; case 1: freq = 3494.4; break; case 2: freq = 3993.6; break; case 3: freq = 4492.8; break; case 4: freq = 3993.6; break; case 5: freq = 6489.6; break; case 6: freq = 6988.8; break; case 7: freq = 6489.6; break; case 8: freq = 7488.0; break; case 9: freq = 7987.2; break; case 10: freq = 8486.4; break; case 11: freq = 7987.2; break; case 12: freq = 8985.6; break; case 13: freq = 9484.8; break; case 14: freq = 9984.0; break; case 15: freq = 9484.8; break; } printf("%6.1f", freq); break; case 5: if (channel >= 0 && channel <= 3) { freq = 780 + 2 * channel; } else if (channel >= 4 && channel <= 7) { freq = 780 + 2 * (channel - 4); } printf("%3.0f", freq); break; case 6: if (channel >= 0 && channel <= 7) { freq = 951.2 + 0.6 * channel; } else if (channel >= 8 && channel <= 9) { freq = 954.4 + 0.2 * (channel - 8); } else if (channel >= 10 && channel <= 21) { freq = 951.1 + 0.4 * (channel - 10); } printf("%5.1f", freq); break; default: printf("Unknown"); break; } } static char cca_mode_buf[100]; static const char *print_cca_mode_handler(enum nl802154_cca_modes cca_mode, enum nl802154_cca_opts cca_opt) { switch (cca_mode) { case NL802154_CCA_ENERGY: sprintf(cca_mode_buf,"(%d) %s", cca_mode, "Energy above threshold"); break; case NL802154_CCA_CARRIER: sprintf(cca_mode_buf,"(%d) %s", cca_mode, "Carrier sense only"); break; case NL802154_CCA_ENERGY_CARRIER: switch (cca_opt) { case NL802154_CCA_OPT_ENERGY_CARRIER_AND: sprintf(cca_mode_buf, "(%d, cca_opt: %d) %s", cca_mode, cca_opt, "Carrier sense with energy above threshold (logical operator is 'and')"); break; case NL802154_CCA_OPT_ENERGY_CARRIER_OR: sprintf(cca_mode_buf, "(%d, cca_opt: %d) %s", cca_mode, cca_opt, "Carrier sense with energy above threshold (logical operator is 'or')"); break; default: sprintf(cca_mode_buf, "Unknown CCA option (%d) for CCA mode (%d)", cca_opt, cca_mode); break; } break; case NL802154_CCA_ALOHA: sprintf(cca_mode_buf,"(%d) %s", cca_mode, "ALOHA"); break; case NL802154_CCA_UWB_SHR: sprintf(cca_mode_buf,"(%d) %s", cca_mode, "UWB preamble sense based on the SHR of a frame"); break; case NL802154_CCA_UWB_MULTIPLEXED: sprintf(cca_mode_buf,"(%d) %s", cca_mode, "UWB preamble sense based on the packet with the multiplexed preamble"); break; default: sprintf(cca_mode_buf, "Unknown CCA mode (%d)", cca_mode); break; } return cca_mode_buf; } static const char *commands[NL802154_CMD_MAX + 1] = { [NL802154_CMD_UNSPEC] = "unspec", [NL802154_CMD_GET_WPAN_PHY] = "get_wpan_phy", [NL802154_CMD_SET_WPAN_PHY] = "set_wpan_phy", [NL802154_CMD_NEW_WPAN_PHY] = "new_wpan_phy", [NL802154_CMD_DEL_WPAN_PHY] = "del_wpan_phy", [NL802154_CMD_GET_INTERFACE] = "get_interface", [NL802154_CMD_SET_INTERFACE] = "set_interface", [NL802154_CMD_NEW_INTERFACE] = "new_interface", [NL802154_CMD_DEL_INTERFACE] = "del_interface", [NL802154_CMD_SET_CHANNEL] = "set_channel", [NL802154_CMD_SET_PAN_ID] = "set_pan_id", [NL802154_CMD_SET_SHORT_ADDR] = "set_short_addr", [NL802154_CMD_SET_TX_POWER] = "set_tx_power", [NL802154_CMD_SET_CCA_MODE] = "set_cca_mode", [NL802154_CMD_SET_CCA_ED_LEVEL] = "set_cca_ed_level", [NL802154_CMD_SET_MAX_FRAME_RETRIES] = "set_max_frame_retries", [NL802154_CMD_SET_BACKOFF_EXPONENT] = "set_backoff_exponent", [NL802154_CMD_SET_MAX_CSMA_BACKOFFS] = "set_max_csma_backoffs", [NL802154_CMD_SET_LBT_MODE] = "set_lbt_mode", [NL802154_CMD_SET_ACKREQ_DEFAULT] = "set_ackreq_default", }; static char cmdbuf[100]; static const char *command_name(enum nl802154_commands cmd) { if (cmd <= NL802154_CMD_MAX && commands[cmd]) return commands[cmd]; sprintf(cmdbuf, "Unknown command (%d)", cmd); return cmdbuf; } static int print_phy_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL802154_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); int rem_page, i, ret; int64_t phy_id = -1; bool print_name = true; struct nlattr *nl_page; enum nl802154_cca_modes cca_mode; nla_parse(tb_msg, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb_msg[NL802154_ATTR_WPAN_PHY]) { if (nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]) == phy_id) print_name = false; phy_id = nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]); } if (print_name && tb_msg[NL802154_ATTR_WPAN_PHY_NAME]) printf("wpan_phy %s\n", nla_get_string(tb_msg[NL802154_ATTR_WPAN_PHY_NAME])); /* TODO remove this handling it's deprecated */ if (tb_msg[NL802154_ATTR_CHANNELS_SUPPORTED]) { unsigned char page = 0; unsigned long channel; printf("supported channels:\n"); nla_for_each_nested(nl_page, tb_msg[NL802154_ATTR_CHANNELS_SUPPORTED], rem_page) { channel = nla_get_u32(nl_page); if (channel) { printf("\tpage %d: ", page); for (i = 0; i <= 31; i++) { if (channel & 0x1) printf("%d,", i); channel >>= 1; } /* TODO hack use sprintf here */ printf("\b \b\n"); } page++; } } if (tb_msg[NL802154_ATTR_PAGE]) printf("current_page: %d\n", nla_get_u8(tb_msg[NL802154_ATTR_PAGE])); if (tb_msg[NL802154_ATTR_CHANNEL] && tb_msg[NL802154_ATTR_PAGE]) { printf("current_channel: %d, ", nla_get_u8(tb_msg[NL802154_ATTR_CHANNEL])); print_freq_handler(nla_get_u8(tb_msg[NL802154_ATTR_PAGE]), nla_get_u8(tb_msg[NL802154_ATTR_CHANNEL])); printf(" MHz\n"); } if (tb_msg[NL802154_ATTR_CCA_MODE]) { enum nl802154_cca_opts cca_opt = NL802154_CCA_OPT_ATTR_MAX; if (tb_msg[NL802154_ATTR_CCA_OPT]) cca_opt = nla_get_u32(tb_msg[NL802154_ATTR_CCA_OPT]); cca_mode = nla_get_u32(tb_msg[NL802154_ATTR_CCA_MODE]); printf("cca_mode: %s", print_cca_mode_handler(cca_mode, cca_opt)); printf("\n"); } if (tb_msg[NL802154_ATTR_CCA_ED_LEVEL]) printf("cca_ed_level: %.3g\n", MBM_TO_DBM(nla_get_s32(tb_msg[NL802154_ATTR_CCA_ED_LEVEL]))); if (tb_msg[NL802154_ATTR_TX_POWER]) printf("tx_power: %.3g\n", MBM_TO_DBM(nla_get_s32(tb_msg[NL802154_ATTR_TX_POWER]))); if (tb_msg[NL802154_ATTR_WPAN_PHY_CAPS]) { struct nlattr *tb_caps[NL802154_CAP_ATTR_MAX + 1]; /* TODO fix netlink lib that we can use NLA_S32 here * see function validate_nla line if (pt->type > NLA_TYPE_MAX) */ static struct nla_policy caps_policy[NL802154_CAP_ATTR_MAX + 1] = { [NL802154_CAP_ATTR_CHANNELS] = { .type = NLA_NESTED }, [NL802154_CAP_ATTR_TX_POWERS] = { .type = NLA_NESTED }, [NL802154_CAP_ATTR_CCA_ED_LEVELS] = { .type = NLA_NESTED }, [NL802154_CAP_ATTR_CCA_MODES] = { .type = NLA_NESTED }, [NL802154_CAP_ATTR_CCA_OPTS] = { .type = NLA_NESTED }, [NL802154_CAP_ATTR_MIN_MINBE] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MAX_MINBE] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MIN_MAXBE] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MAX_MAXBE] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MIN_FRAME_RETRIES] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_U8 }, [NL802154_CAP_ATTR_IFTYPES] = { .type = NLA_NESTED }, [NL802154_CAP_ATTR_LBT] = { .type = NLA_U32 }, }; printf("capabilities:\n"); ret = nla_parse_nested(tb_caps, NL802154_CAP_ATTR_MAX, tb_msg[NL802154_ATTR_WPAN_PHY_CAPS], caps_policy); if (ret) { printf("failed to parse caps\n"); return -EIO; } if (tb_caps[NL802154_CAP_ATTR_IFTYPES]) { struct nlattr *nl_iftypes; int rem_iftypes; printf("\tiftypes: "); nla_for_each_nested(nl_iftypes, tb_caps[NL802154_CAP_ATTR_IFTYPES], rem_iftypes) printf("%s,", iftype_name(nla_type(nl_iftypes))); /* TODO */ printf("\b \n"); } if (tb_msg[NL802154_CAP_ATTR_CHANNELS]) { int counter = 0; int rem_pages; struct nlattr *nl_pages; printf("\tchannels:\n"); nla_for_each_nested(nl_pages, tb_caps[NL802154_CAP_ATTR_CHANNELS], rem_pages) { int rem_channels; struct nlattr *nl_channels; counter = 0; printf("\t\tpage %d: ", nla_type(nl_pages)); nla_for_each_nested(nl_channels, nl_pages, rem_channels) { if (counter % 3 == 0) { printf("\n\t\t\t[%2d] ", nla_type(nl_channels)); print_freq_handler(nla_type(nl_pages), nla_type(nl_channels)); printf(" MHz, "); } else { printf("[%2d] ", nla_type(nl_channels)); print_freq_handler(nla_type(nl_pages), nla_type(nl_channels)); printf(" MHz, "); } counter++; } /* TODO hack use sprintf here */ printf("\b\b \b\n"); } } if (tb_caps[NL802154_CAP_ATTR_TX_POWERS]) { int rem_pwrs; int counter = 0; struct nlattr *nl_pwrs; printf("\ttx_powers: "); nla_for_each_nested(nl_pwrs, tb_caps[NL802154_CAP_ATTR_TX_POWERS], rem_pwrs) { if (counter % 6 == 0) { printf("\n\t\t\t%.3g dBm, ", MBM_TO_DBM(nla_get_s32(nl_pwrs))); } else { printf("%.3g dBm, ", MBM_TO_DBM(nla_get_s32(nl_pwrs))); } counter++; } /* TODO */ printf("\b \n"); } if (tb_caps[NL802154_CAP_ATTR_CCA_ED_LEVELS]) { int rem_levels; int counter = 0; struct nlattr *nl_levels; printf("\tcca_ed_levels: "); nla_for_each_nested(nl_levels, tb_caps[NL802154_CAP_ATTR_CCA_ED_LEVELS], rem_levels) { if (counter % 6 == 0) { printf("\n\t\t\t%.3g dBm, ", MBM_TO_DBM(nla_get_s32(nl_levels))); } else { printf("%.3g dBm, ", MBM_TO_DBM(nla_get_s32(nl_levels))); } counter++; } /* TODO */ printf("\b \n"); } if (tb_caps[NL802154_CAP_ATTR_CCA_MODES]) { struct nlattr *nl_cca_modes; int rem_cca_modes; printf("\tcca_modes: "); nla_for_each_nested(nl_cca_modes, tb_caps[NL802154_CAP_ATTR_CCA_MODES], rem_cca_modes) { /* Loop through all CCA options only if it is a * CCA mode that takes CCA options into * consideration. */ if (tb_caps[NL802154_CAP_ATTR_CCA_OPTS] && nla_type(nl_cca_modes) == NL802154_CCA_ENERGY_CARRIER) { struct nlattr *nl_cca_opts; int rem_cca_opts; nla_for_each_nested(nl_cca_opts, tb_caps[NL802154_CAP_ATTR_CCA_OPTS], rem_cca_opts) { printf("\n\t\t%s", print_cca_mode_handler( nla_type(nl_cca_modes), nla_type(nl_cca_opts))); } } else { printf("\n\t\t%s", print_cca_mode_handler( nla_type(nl_cca_modes), NL802154_CCA_OPT_ATTR_MAX)); } } /* TODO */ printf("\n"); } if (tb_caps[NL802154_CAP_ATTR_MIN_MINBE] && tb_caps[NL802154_CAP_ATTR_MAX_MINBE] && tb_caps[NL802154_CAP_ATTR_MIN_MAXBE] && tb_caps[NL802154_CAP_ATTR_MAX_MAXBE]) { printf("\tmin_be: "); print_minmax_handler(nla_get_u8(tb_caps[NL802154_CAP_ATTR_MIN_MINBE]), nla_get_u8(tb_caps[NL802154_CAP_ATTR_MAX_MINBE])); printf("\tmax_be: "); print_minmax_handler(nla_get_u8(tb_caps[NL802154_CAP_ATTR_MIN_MAXBE]), nla_get_u8(tb_caps[NL802154_CAP_ATTR_MAX_MAXBE])); } if (tb_caps[NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS] && tb_caps[NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS]) { printf("\tcsma_backoffs: "); print_minmax_handler(nla_get_u8(tb_caps[NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS]), nla_get_u8(tb_caps[NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS])); } if (tb_caps[NL802154_CAP_ATTR_MIN_FRAME_RETRIES] && tb_caps[NL802154_CAP_ATTR_MAX_FRAME_RETRIES]) { printf("\tframe_retries: "); print_minmax_handler(nla_get_s8(tb_caps[NL802154_CAP_ATTR_MIN_FRAME_RETRIES]), nla_get_s8(tb_caps[NL802154_CAP_ATTR_MAX_FRAME_RETRIES])); } if (tb_caps[NL802154_CAP_ATTR_LBT]) { printf("\tlbt: "); switch (nla_get_u32(tb_caps[NL802154_CAP_ATTR_LBT])) { case NL802154_SUPPORTED_BOOL_FALSE: printf("false\n"); break; case NL802154_SUPPORTED_BOOL_TRUE: printf("true\n"); break; case NL802154_SUPPORTED_BOOL_BOTH: printf("false,true\n"); break; default: printf("unknown\n"); break; } } } return 0; } static int handle_info(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_phy_handler, NULL); return 0; } __COMMAND(NULL, info, "info", NULL, NL802154_CMD_GET_WPAN_PHY, 0, 0, CIB_PHY, handle_info, "Show capabilities for the specified wireless device.", NULL); TOPLEVEL(list, NULL, NL802154_CMD_GET_WPAN_PHY, NLM_F_DUMP, CIB_NONE, handle_info, "List all wireless devices and their capabilities."); TOPLEVEL(phy, NULL, NL802154_CMD_GET_WPAN_PHY, NLM_F_DUMP, CIB_NONE, handle_info, NULL); wpan-tools-0.9/src/interface.c000066400000000000000000000153731340645032500163730ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include "nl802154.h" #include "nl_extras.h" #include "iwpan.h" SECTION(interface); static char iftypebuf[100]; const char *iftype_name(enum nl802154_iftype iftype) { switch (iftype) { case NL802154_IFTYPE_MONITOR: return "monitor"; case NL802154_IFTYPE_NODE: return "node"; case NL802154_IFTYPE_COORD: return "coordinator"; default: sprintf(iftypebuf, "Invalid iftype (%d)", iftype); return iftypebuf; } } /* for help */ #define IFACE_TYPES "Valid interface types are: node, monitor, coordinator." /* return 0 if ok, internal error otherwise */ static int get_if_type(int *argc, char ***argv, enum nl802154_iftype *type, bool need_type) { char *tpstr; if (*argc < 1 + !!need_type) return 1; if (need_type && strcmp((*argv)[0], "type")) return 1; tpstr = (*argv)[!!need_type]; *argc -= 1 + !!need_type; *argv += 1 + !!need_type; if (strcmp(tpstr, "node") == 0) { *type = NL802154_IFTYPE_NODE; return 0; } else if (strcmp(tpstr, "monitor") == 0) { *type = NL802154_IFTYPE_MONITOR; return 0; } else if (strcmp(tpstr, "coordinator") == 0) { *type = NL802154_IFTYPE_COORD; return 0; } fprintf(stderr, "invalid interface type %s\n", tpstr); return 2; } #define EUI64_ALEN 8 static int extendedaddr_a2n(unsigned char *mac_addr, char *arg) { int i; for (i = 0; i < EUI64_ALEN ; i++) { int temp; char *cp = strchr(arg, ':'); if (cp) { *cp = 0; cp++; } if (sscanf(arg, "%x", &temp) != 1) return -1; if (temp < 0 || temp > 255) return -1; mac_addr[EUI64_ALEN - 1 - i] = temp; if (!cp) break; arg = cp; } if (i < EUI64_ALEN - 1) return -1; return 0; } /* return 0 if ok, internal error otherwise */ static int get_eui64(int *argc, char ***argv, void *eui64) { int ret; if (*argc < 1) return 0; ret = extendedaddr_a2n(eui64, (*argv)[0]); if (ret) { fprintf(stderr, "invalid extended address\n"); return 2; } *argc -= 1; *argv += 1; return 0; } static int handle_interface_add(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *name; enum nl802154_iftype type; uint64_t eui64 = 0; int tpset; if (argc < 1) return 1; name = argv[0]; argc--; argv++; tpset = get_if_type(&argc, &argv, &type, true); if (tpset) return tpset; tpset = get_eui64(&argc, &argv, &eui64); if (tpset) return tpset; if (argc) return 1; NLA_PUT_STRING(msg, NL802154_ATTR_IFNAME, name); NLA_PUT_U32(msg, NL802154_ATTR_IFTYPE, type); NLA_PUT_U64(msg, NL802154_ATTR_EXTENDED_ADDR, eui64); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(interface, add, " type [extended address ]", NL802154_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add, "Add a new virtual interface with the given configuration.\n" IFACE_TYPES "\n\n"); COMMAND(interface, add, " type [extended address ]", NL802154_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL); static int handle_interface_del(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { return 0; } TOPLEVEL(del, NULL, NL802154_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del, "Remove this virtual interface"); HIDDEN(interface, del, NULL, NL802154_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del); static int print_iface_handler(struct nl_msg *msg, void *arg) { struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb_msg[NL802154_ATTR_MAX + 1]; unsigned int *wpan_phy = arg; const char *indent = ""; nla_parse(tb_msg, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (wpan_phy && tb_msg[NL802154_ATTR_WPAN_PHY]) { unsigned int thiswpan_phy = nla_get_u32(tb_msg[NL802154_ATTR_WPAN_PHY]); indent = "\t"; if (*wpan_phy != thiswpan_phy) printf("phy#%d\n", thiswpan_phy); *wpan_phy = thiswpan_phy; } if (tb_msg[NL802154_ATTR_IFNAME]) printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL802154_ATTR_IFNAME])); else printf("%sUnnamed/non-netdev interface\n", indent); if (tb_msg[NL802154_ATTR_IFINDEX]) printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL802154_ATTR_IFINDEX])); if (tb_msg[NL802154_ATTR_WPAN_DEV]) printf("%s\twpan_dev 0x%llx\n", indent, (unsigned long long)nla_get_u64(tb_msg[NL802154_ATTR_WPAN_DEV])); if (tb_msg[NL802154_ATTR_EXTENDED_ADDR]) printf("%s\textended_addr 0x%016" PRIx64 "\n", indent, le64toh(nla_get_u64(tb_msg[NL802154_ATTR_EXTENDED_ADDR]))); if (tb_msg[NL802154_ATTR_SHORT_ADDR]) printf("%s\tshort_addr 0x%04x\n", indent, le16toh(nla_get_u16(tb_msg[NL802154_ATTR_SHORT_ADDR]))); if (tb_msg[NL802154_ATTR_PAN_ID]) printf("%s\tpan_id 0x%04x\n", indent, le16toh(nla_get_u16(tb_msg[NL802154_ATTR_PAN_ID]))); if (tb_msg[NL802154_ATTR_IFTYPE]) printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL802154_ATTR_IFTYPE]))); if (tb_msg[NL802154_ATTR_MAX_FRAME_RETRIES]) printf("%s\tmax_frame_retries %d\n", indent, nla_get_s8(tb_msg[NL802154_ATTR_MAX_FRAME_RETRIES])); if (tb_msg[NL802154_ATTR_MIN_BE]) printf("%s\tmin_be %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MIN_BE])); if (tb_msg[NL802154_ATTR_MAX_BE]) printf("%s\tmax_be %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MAX_BE])); if (tb_msg[NL802154_ATTR_MAX_CSMA_BACKOFFS]) printf("%s\tmax_csma_backoffs %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_MAX_CSMA_BACKOFFS])); if (tb_msg[NL802154_ATTR_LBT_MODE]) printf("%s\tlbt %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_LBT_MODE])); if (tb_msg[NL802154_ATTR_ACKREQ_DEFAULT]) printf("%s\tackreq_default %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_ACKREQ_DEFAULT])); return NL_SKIP; } static int handle_interface_info(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, NULL); return 0; } TOPLEVEL(info, NULL, NL802154_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info, "Show information for this interface."); static unsigned int dev_dump_wpan_phy; static int handle_dev_dump(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { dev_dump_wpan_phy = -1; nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, &dev_dump_wpan_phy); return 0; } TOPLEVEL(dev, NULL, NL802154_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump, "List all network interfaces for wireless hardware."); wpan-tools-0.9/src/iwpan.c000066400000000000000000000252151340645032500155450ustar00rootroot00000000000000 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nl802154.h" #include "iwpan.h" #include "config.h" /* TODO libnl 1.x compatibility code */ static int iwpan_debug = 0; static int nl802154_init(struct nl802154_state *state) { int err; state->nl_sock = nl_socket_alloc(); if (!state->nl_sock) { fprintf(stderr, "Failed to allocate netlink socket.\n"); return -ENOMEM; } nl_socket_set_buffer_size(state->nl_sock, 8192, 8192); if (genl_connect(state->nl_sock)) { fprintf(stderr, "Failed to connect to generic netlink.\n"); err = -ENOLINK; goto out_handle_destroy; } state->nl802154_id = genl_ctrl_resolve(state->nl_sock, "nl802154"); if (state->nl802154_id < 0) { fprintf(stderr, "nl802154 not found.\n"); err = -ENOENT; goto out_handle_destroy; } return 0; out_handle_destroy: nl_socket_free(state->nl_sock); return err; } static void nl802154_cleanup(struct nl802154_state *state) { nl_socket_free(state->nl_sock); } static int cmd_size; extern struct cmd __start___cmd; extern struct cmd __stop___cmd; static void __usage_cmd(const struct cmd *cmd, char *indent, bool full) { const char *start, *lend, *end; printf("%s", indent); switch (cmd->idby) { case CIB_NONE: break; case CIB_PHY: printf("phy "); break; case CIB_NETDEV: printf("dev "); break; case CIB_WPAN_DEV: printf("wdev "); break; } if (cmd->parent && cmd->parent->name) printf("%s ", cmd->parent->name); printf("%s", cmd->name); if (cmd->args) { /* print line by line */ start = cmd->args; end = strchr(start, '\0'); printf(" "); do { lend = strchr(start, '\n'); if (!lend) lend = end; if (start != cmd->args) { printf("\t"); switch (cmd->idby) { case CIB_NONE: break; case CIB_PHY: printf("phy "); break; case CIB_NETDEV: printf("dev "); break; case CIB_WPAN_DEV: printf("wdev "); break; } if (cmd->parent && cmd->parent->name) printf("%s ", cmd->parent->name); printf("%s ", cmd->name); } printf("%.*s\n", (int)(lend - start), start); start = lend + 1; } while (end != lend); } else { printf("\n"); } if (!full || !cmd->help) return; /* hack */ if (strlen(indent)) indent = "\t\t"; else printf("\n"); /* print line by line */ start = cmd->help; end = strchr(start, '\0'); do { lend = strchr(start, '\n'); if (!lend) lend = end; printf("%s", indent); printf("%.*s\n", (int)(lend - start), start); start = lend + 1; } while (end != lend); printf("\n"); } #define for_each_cmd(_cmd) \ for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \ _cmd = (const struct cmd *)((char *)_cmd + cmd_size)) static void usage_options(void) { printf("Options:\n"); printf("\t--debug\t\tenable netlink debugging\n"); } static const char *argv0; static void usage(int argc, char **argv) { const struct cmd *section, *cmd; bool full = argc >= 0; const char *sect_filt = NULL; const char *cmd_filt = NULL; if (argc > 0) sect_filt = argv[0]; if (argc > 1) cmd_filt = argv[1]; printf("Usage:\t%s [options] command\n", argv0); usage_options(); printf("\t--version\tshow version (" PACKAGE_VERSION ")\n"); printf("Commands:\n"); for_each_cmd(section) { if (section->parent) continue; if (sect_filt && strcmp(section->name, sect_filt)) continue; if (section->handler && !section->hidden) __usage_cmd(section, "\t", full); for_each_cmd(cmd) { if (section != cmd->parent) continue; if (!cmd->handler || cmd->hidden) continue; if (cmd_filt && strcmp(cmd->name, cmd_filt)) continue; __usage_cmd(cmd, "\t", full); } } printf("\nCommands that use the netdev ('dev') can also be given the\n" "'wdev' instead to identify the device.\n"); printf("\nYou can omit the 'phy' or 'dev' if " "the identification is unique,\n" "e.g. \"iwpan wpan0 info\" or \"iwpan phy0 info\". " "(Don't when scripting.)\n\n" "Do NOT screenscrape this tool, we don't " "consider its output stable.\n\n"); } static void usage_cmd(const struct cmd *cmd) { printf("Usage:\t%s [options] ", argv0); __usage_cmd(cmd, "", true); usage_options(); } static void version(void) { printf("iwpan version " PACKAGE_VERSION "\n"); } static int phy_lookup(char *name) { char buf[200]; int fd, pos; snprintf(buf, sizeof(buf), "/sys/class/ieee802154/%s/index", name); fd = open(buf, O_RDONLY); if (fd < 0) return -1; pos = read(fd, buf, sizeof(buf) - 1); if (pos < 0) { close(fd); return -1; } buf[pos] = '\0'; close(fd); return atoi(buf); } static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; return NL_STOP; } static int finish_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_SKIP; } static int ack_handler(struct nl_msg *msg, void *arg) { int *ret = arg; *ret = 0; return NL_STOP; } static int __handle_cmd(struct nl802154_state *state, enum id_input idby, int argc, char **argv, const struct cmd **cmdout) { const struct cmd *cmd, *match = NULL, *sectcmd; struct nl_cb *cb; struct nl_cb *s_cb; struct nl_msg *msg; signed long long devidx = 0; int err, o_argc; const char *command, *section; char *tmp, **o_argv; enum command_identify_by command_idby = CIB_NONE; if (argc <= 1 && idby != II_NONE) return 1; o_argc = argc; o_argv = argv; switch (idby) { case II_PHY_IDX: command_idby = CIB_PHY; devidx = strtoul(*argv + 4, &tmp, 0); if (*tmp != '\0') return 1; argc--; argv++; break; case II_PHY_NAME: command_idby = CIB_PHY; devidx = phy_lookup(*argv); argc--; argv++; break; case II_NETDEV: command_idby = CIB_NETDEV; devidx = if_nametoindex(*argv); if (devidx == 0) devidx = -1; argc--; argv++; break; case II_WPAN_DEV: command_idby = CIB_WPAN_DEV; devidx = strtoll(*argv, &tmp, 0); if (*tmp != '\0') return 1; argc--; argv++; default: break; } if (devidx < 0) return -errno; section = *argv; argc--; argv++; for_each_cmd(sectcmd) { if (sectcmd->parent) continue; /* ok ... bit of a hack for the dupe 'info' section */ if (match && sectcmd->idby != command_idby) continue; if (strcmp(sectcmd->name, section) == 0) match = sectcmd; } sectcmd = match; match = NULL; if (!sectcmd) return 1; if (argc > 0) { command = *argv; for_each_cmd(cmd) { if (!cmd->handler) continue; if (cmd->parent != sectcmd) continue; /* * ignore mismatch id by, but allow WPAN_DEV * in place of NETDEV */ if (cmd->idby != command_idby && !(cmd->idby == CIB_NETDEV && command_idby == CIB_WPAN_DEV)) continue; if (strcmp(cmd->name, command)) continue; if (argc > 1 && !cmd->args) continue; match = cmd; break; } if (match) { argc--; argv++; } } if (match) cmd = match; else { /* Use the section itself, if possible. */ cmd = sectcmd; if (argc && !cmd->args) return 1; if (cmd->idby != command_idby && !(cmd->idby == CIB_NETDEV && command_idby == CIB_WPAN_DEV)) return 1; if (!cmd->handler) return 1; } if (cmd->selector) { cmd = cmd->selector(argc, argv); if (!cmd) return 1; } if (cmdout) *cmdout = cmd; if (!cmd->cmd) { argc = o_argc; argv = o_argv; return cmd->handler(state, NULL, NULL, argc, argv, idby); } msg = nlmsg_alloc(); if (!msg) { fprintf(stderr, "failed to allocate netlink message\n"); return 2; } cb = nl_cb_alloc(iwpan_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); s_cb = nl_cb_alloc(iwpan_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); if (!cb || !s_cb) { fprintf(stderr, "failed to allocate netlink callbacks\n"); err = 2; goto out_free_msg; } genlmsg_put(msg, 0, 0, state->nl802154_id, 0, cmd->nl_msg_flags, cmd->cmd, 0); switch (command_idby) { case CIB_PHY: NLA_PUT_U32(msg, NL802154_ATTR_WPAN_PHY, devidx); break; case CIB_NETDEV: NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, devidx); break; case CIB_WPAN_DEV: NLA_PUT_U64(msg, NL802154_ATTR_WPAN_DEV, devidx); break; default: break; } err = cmd->handler(state, cb, msg, argc, argv, idby); if (err) goto out; nl_socket_set_cb(state->nl_sock, s_cb); err = nl_send_auto_complete(state->nl_sock, msg); if (err < 0) goto out; err = 1; nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); while (err > 0) nl_recvmsgs(state->nl_sock, cb); out: nl_cb_put(cb); out_free_msg: nlmsg_free(msg); return err; nla_put_failure: fprintf(stderr, "building message failed\n"); return 2; } int handle_cmd(struct nl802154_state *state, enum id_input idby, int argc, char **argv) { return __handle_cmd(state, idby, argc, argv, NULL); } int main(int argc, char **argv) { struct nl802154_state nlstate; const struct cmd *cmd = NULL; int err; /* calculate command size including padding */ cmd_size = labs((long)&__section_set - (long)&__section_get); /* strip off self */ argc--; argv0 = *argv++; if (argc > 0 && strcmp(*argv, "--debug") == 0) { iwpan_debug = 1; argc--; argv++; } if (argc > 0 && strcmp(*argv, "--version") == 0) { version(); return 0; } /* need to treat "help" command specially so it works w/o nl802154 */ if (argc == 0 || strcmp(*argv, "help") == 0) { usage(argc - 1, argv + 1); return 0; } err = nl802154_init(&nlstate); if (err) return 1; if (strcmp(*argv, "dev") == 0 && argc > 1) { argc--; argv++; err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd); } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) { if (strlen(*argv) == 3) { argc--; argv++; err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd); } else if (*(*argv + 3) == '#') err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd); else goto detect; } else if (strcmp(*argv, "wdev") == 0 && argc > 1) { argc--; argv++; err = __handle_cmd(&nlstate, II_WPAN_DEV, argc, argv, &cmd); } else { int idx; enum id_input idby = II_NONE; detect: if ((idx = if_nametoindex(argv[0])) != 0) idby = II_NETDEV; else if ((idx = phy_lookup(argv[0])) >= 0) idby = II_PHY_NAME; err = __handle_cmd(&nlstate, idby, argc, argv, &cmd); } if (err == 1) { if (cmd) usage_cmd(cmd); else usage(0, NULL); } else if (err < 0) fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err); nl802154_cleanup(&nlstate); return err; } wpan-tools-0.9/src/iwpan.h000066400000000000000000000072151340645032500155520ustar00rootroot00000000000000#ifndef __IWPAN_H #define __IWPAN_H #include #include #include #include #include #include #include "nl802154.h" /* TODO libnl1 compatibility */ //#define nl_sock nl_handle struct nl802154_state { struct nl_sock *nl_sock; int nl802154_id; }; enum command_identify_by { CIB_NONE, CIB_PHY, CIB_NETDEV, CIB_WPAN_DEV, }; enum id_input { II_NONE, II_NETDEV, II_PHY_NAME, II_PHY_IDX, II_WPAN_DEV, }; struct cmd { const char *name; const char *args; const char *help; const enum nl802154_commands cmd; int nl_msg_flags; int hidden; const enum command_identify_by idby; /* The handler should return a negative error code, * zero on success, 1 if the arguments were wrong * and the usage message should and 2 otherwise. */ int (*handler)(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id); const struct cmd *(*selector)(int argc, char **argv); const struct cmd *parent; }; #define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel)\ static struct cmd \ __cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\ __attribute__((used)) __attribute__((section("__cmd"))) = { \ .name = (_name), \ .args = (_args), \ .cmd = (_nlcmd), \ .nl_msg_flags = (_flags), \ .hidden = (_hidden), \ .idby = (_idby), \ .handler = (_handler), \ .help = (_help), \ .parent = _section, \ .selector = (_sel), \ } #define __ACMD(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel, _alias)\ __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel);\ static const struct cmd *_alias = &__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden #define COMMAND(section, name, args, cmd, flags, idby, handler, help) \ __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help, NULL) #define COMMAND_ALIAS(section, name, args, cmd, flags, idby, handler, help, selector, alias)\ __ACMD(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help, selector, alias) #define HIDDEN(section, name, args, cmd, flags, idby, handler) \ __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 1, idby, handler, NULL, NULL) #define TOPLEVEL(_name, _args, _nlcmd, _flags, _idby, _handler, _help) \ struct cmd \ __section ## _ ## _name \ __attribute__((used)) __attribute__((section("__cmd"))) = { \ .name = (#_name), \ .args = (_args), \ .cmd = (_nlcmd), \ .nl_msg_flags = (_flags), \ .idby = (_idby), \ .handler = (_handler), \ .help = (_help), \ } #define SECTION(_name) \ struct cmd __section ## _ ## _name \ __attribute__((used)) __attribute__((section("__cmd"))) = { \ .name = (#_name), \ .hidden = 1, \ } #define SECTION(_name) \ struct cmd __section ## _ ## _name \ __attribute__((used)) __attribute__((section("__cmd"))) = { \ .name = (#_name), \ .hidden = 1, \ } #define DECLARE_SECTION(_name) \ extern struct cmd __section ## _ ## _name; #define DBM_TO_MBM(gain) \ ((int)(((float)gain) * 100)) #define MBM_TO_DBM(gain) \ ((float)(gain) / 100) int handle_cmd(struct nl802154_state *state, enum id_input idby, int argc, char **argv); DECLARE_SECTION(set); DECLARE_SECTION(get); const char *iftype_name(enum nl802154_iftype iftype); #endif /* __IWPAN_H */ wpan-tools-0.9/src/mac.c000066400000000000000000000107171340645032500151700ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "nl_extras.h" #include "nl802154.h" #include "iwpan.h" static int handle_pan_id_set(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long pan_id; char *end; if (argc < 1) return 1; /* PAN ID */ pan_id = strtoul(argv[0], &end, 0); if (*end != '\0') return 1; if (pan_id > UINT16_MAX) return 1; NLA_PUT_U16(msg, NL802154_ATTR_PAN_ID, htole16(pan_id)); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, pan_id, "", NL802154_CMD_SET_PAN_ID, 0, CIB_NETDEV, handle_pan_id_set, NULL); static int handle_short_addr_set(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long short_addr; char *end; if (argc < 1) return 1; /* SHORT ADDR */ short_addr = strtoul(argv[0], &end, 0); if (*end != '\0') return 1; if (short_addr > UINT16_MAX) return 1; NLA_PUT_U16(msg, NL802154_ATTR_SHORT_ADDR, htole16(short_addr)); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, short_addr, "", NL802154_CMD_SET_SHORT_ADDR, 0, CIB_NETDEV, handle_short_addr_set, NULL); static int handle_max_frame_retries_set(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { long retries; char *end; if (argc < 1) return 1; /* RETRIES */ retries = strtol(argv[0], &end, 0); if (*end != '\0') return 1; if (retries > INT8_MAX) return 1; NLA_PUT_S8(msg, NL802154_ATTR_MAX_FRAME_RETRIES, retries); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, max_frame_retries, "", NL802154_CMD_SET_MAX_FRAME_RETRIES, 0, CIB_NETDEV, handle_max_frame_retries_set, NULL); static int handle_backoff_exponent(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long max_be; unsigned long min_be; char *end; if (argc < 2) return 1; /* MIN_BE */ min_be = strtoul(argv[0], &end, 0); if (*end != '\0') return 1; /* MAX_BE */ max_be = strtoul(argv[1], &end, 0); if (*end != '\0') return 1; if (min_be > UINT8_MAX || max_be > UINT8_MAX) return 1; NLA_PUT_U8(msg, NL802154_ATTR_MIN_BE, min_be); NLA_PUT_U8(msg, NL802154_ATTR_MAX_BE, max_be); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, backoff_exponents, " ", NL802154_CMD_SET_BACKOFF_EXPONENT, 0, CIB_NETDEV, handle_backoff_exponent, NULL); static int handle_max_csma_backoffs(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long backoffs; char *end; if (argc < 1) return 1; /* BACKOFFS */ backoffs = strtoul(argv[0], &end, 0); if (*end != '\0') return 1; if (backoffs > UINT8_MAX) return 1; NLA_PUT_U8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS, backoffs); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, max_csma_backoffs, "", NL802154_CMD_SET_MAX_CSMA_BACKOFFS, 0, CIB_NETDEV, handle_max_csma_backoffs, NULL); static int handle_lbt_mode(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long mode; char *end; if (argc < 1) return 1; /* LBT_MODE */ mode = strtoul(argv[0], &end, 0); if (*end != '\0') return 1; if (mode > UINT8_MAX) return 1; NLA_PUT_U8(msg, NL802154_ATTR_LBT_MODE, mode); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, lbt, "<1|0>", NL802154_CMD_SET_LBT_MODE, 0, CIB_NETDEV, handle_lbt_mode, NULL); static int handle_ackreq_default(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long ackreq; char *end; if (argc < 1) return 1; /* ACKREQ_DEFAULT */ ackreq = strtoul(argv[0], &end, 0); if (*end != '\0') return 1; if (ackreq > UINT8_MAX) return 1; NLA_PUT_U8(msg, NL802154_ATTR_ACKREQ_DEFAULT, ackreq); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, ackreq_default, "<1|0>", NL802154_CMD_SET_ACKREQ_DEFAULT, 0, CIB_NETDEV, handle_ackreq_default, NULL); wpan-tools-0.9/src/nl802154.h000066400000000000000000000301411340645032500155230ustar00rootroot00000000000000#ifndef __NL802154_H #define __NL802154_H /* * 802.15.4 netlink interface public header * * Copyright 2014 Alexander Aring * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #define NL802154_GENL_NAME "nl802154" enum nl802154_commands { /* don't change the order or add anything between, this is ABI! */ /* currently we don't shipping this file via uapi, ignore the above one */ NL802154_CMD_UNSPEC, NL802154_CMD_GET_WPAN_PHY, /* can dump */ NL802154_CMD_SET_WPAN_PHY, NL802154_CMD_NEW_WPAN_PHY, NL802154_CMD_DEL_WPAN_PHY, NL802154_CMD_GET_INTERFACE, /* can dump */ NL802154_CMD_SET_INTERFACE, NL802154_CMD_NEW_INTERFACE, NL802154_CMD_DEL_INTERFACE, NL802154_CMD_SET_CHANNEL, NL802154_CMD_SET_PAN_ID, NL802154_CMD_SET_SHORT_ADDR, NL802154_CMD_SET_TX_POWER, NL802154_CMD_SET_CCA_MODE, NL802154_CMD_SET_CCA_ED_LEVEL, NL802154_CMD_SET_MAX_FRAME_RETRIES, NL802154_CMD_SET_BACKOFF_EXPONENT, NL802154_CMD_SET_MAX_CSMA_BACKOFFS, NL802154_CMD_SET_LBT_MODE, NL802154_CMD_SET_ACKREQ_DEFAULT, NL802154_CMD_SET_WPAN_PHY_NETNS, /* add new commands above here */ #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL NL802154_CMD_SET_SEC_PARAMS, NL802154_CMD_GET_SEC_KEY, /* can dump */ NL802154_CMD_NEW_SEC_KEY, NL802154_CMD_DEL_SEC_KEY, NL802154_CMD_GET_SEC_DEV, /* can dump */ NL802154_CMD_NEW_SEC_DEV, NL802154_CMD_DEL_SEC_DEV, NL802154_CMD_GET_SEC_DEVKEY, /* can dump */ NL802154_CMD_NEW_SEC_DEVKEY, NL802154_CMD_DEL_SEC_DEVKEY, NL802154_CMD_GET_SEC_LEVEL, /* can dump */ NL802154_CMD_NEW_SEC_LEVEL, NL802154_CMD_DEL_SEC_LEVEL, #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ /* used to define NL802154_CMD_MAX below */ __NL802154_CMD_AFTER_LAST, NL802154_CMD_MAX = __NL802154_CMD_AFTER_LAST - 1 }; enum nl802154_attrs { /* don't change the order or add anything between, this is ABI! */ /* currently we don't shipping this file via uapi, ignore the above one */ NL802154_ATTR_UNSPEC, NL802154_ATTR_WPAN_PHY, NL802154_ATTR_WPAN_PHY_NAME, NL802154_ATTR_IFINDEX, NL802154_ATTR_IFNAME, NL802154_ATTR_IFTYPE, NL802154_ATTR_WPAN_DEV, NL802154_ATTR_PAGE, NL802154_ATTR_CHANNEL, NL802154_ATTR_PAN_ID, NL802154_ATTR_SHORT_ADDR, NL802154_ATTR_TX_POWER, NL802154_ATTR_CCA_MODE, NL802154_ATTR_CCA_OPT, NL802154_ATTR_CCA_ED_LEVEL, NL802154_ATTR_MAX_FRAME_RETRIES, NL802154_ATTR_MAX_BE, NL802154_ATTR_MIN_BE, NL802154_ATTR_MAX_CSMA_BACKOFFS, NL802154_ATTR_LBT_MODE, NL802154_ATTR_GENERATION, NL802154_ATTR_CHANNELS_SUPPORTED, NL802154_ATTR_SUPPORTED_CHANNEL, NL802154_ATTR_EXTENDED_ADDR, NL802154_ATTR_WPAN_PHY_CAPS, NL802154_ATTR_SUPPORTED_COMMANDS, NL802154_ATTR_ACKREQ_DEFAULT, NL802154_ATTR_PAD, NL802154_ATTR_PID, NL802154_ATTR_NETNS_FD, /* add attributes here, update the policy in nl802154.c */ #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL NL802154_ATTR_SEC_ENABLED, NL802154_ATTR_SEC_OUT_LEVEL, NL802154_ATTR_SEC_OUT_KEY_ID, NL802154_ATTR_SEC_FRAME_COUNTER, NL802154_ATTR_SEC_LEVEL, NL802154_ATTR_SEC_DEVICE, NL802154_ATTR_SEC_DEVKEY, NL802154_ATTR_SEC_KEY, #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ __NL802154_ATTR_AFTER_LAST, NL802154_ATTR_MAX = __NL802154_ATTR_AFTER_LAST - 1 }; enum nl802154_iftype { /* for backwards compatibility TODO */ NL802154_IFTYPE_UNSPEC = -1, NL802154_IFTYPE_NODE, NL802154_IFTYPE_MONITOR, NL802154_IFTYPE_COORD, /* keep last */ NUM_NL802154_IFTYPES, NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1 }; /** * enum nl802154_wpan_phy_capability_attr - wpan phy capability attributes * * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for * nl802154_wpan_phy_tx_power * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined * @__NL802154_CAP_ATTR_AFTER_LAST: internal use */ enum nl802154_wpan_phy_capability_attr { __NL802154_CAP_ATTR_INVALID, NL802154_CAP_ATTR_IFTYPES, NL802154_CAP_ATTR_CHANNELS, NL802154_CAP_ATTR_TX_POWERS, NL802154_CAP_ATTR_CCA_ED_LEVELS, NL802154_CAP_ATTR_CCA_MODES, NL802154_CAP_ATTR_CCA_OPTS, NL802154_CAP_ATTR_MIN_MINBE, NL802154_CAP_ATTR_MAX_MINBE, NL802154_CAP_ATTR_MIN_MAXBE, NL802154_CAP_ATTR_MAX_MAXBE, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, NL802154_CAP_ATTR_MIN_FRAME_RETRIES, NL802154_CAP_ATTR_MAX_FRAME_RETRIES, NL802154_CAP_ATTR_LBT, /* keep last */ __NL802154_CAP_ATTR_AFTER_LAST, NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1 }; /** * enum nl802154_cca_modes - cca modes * * @__NL802154_CCA_INVALID: cca mode number 0 is reserved * @NL802154_CCA_ENERGY: Energy above threshold * @NL802154_CCA_CARRIER: Carrier sense only * @NL802154_CCA_ENERGY_CARRIER: Carrier sense with energy above threshold * @NL802154_CCA_ALOHA: CCA shall always report an idle medium * @NL802154_CCA_UWB_SHR: UWB preamble sense based on the SHR of a frame * @NL802154_CCA_UWB_MULTIPLEXED: UWB preamble sense based on the packet with * the multiplexed preamble * @__NL802154_CCA_ATTR_AFTER_LAST: Internal * @NL802154_CCA_ATTR_MAX: Maximum CCA attribute number */ enum nl802154_cca_modes { __NL802154_CCA_INVALID, NL802154_CCA_ENERGY, NL802154_CCA_CARRIER, NL802154_CCA_ENERGY_CARRIER, NL802154_CCA_ALOHA, NL802154_CCA_UWB_SHR, NL802154_CCA_UWB_MULTIPLEXED, /* keep last */ __NL802154_CCA_ATTR_AFTER_LAST, NL802154_CCA_ATTR_MAX = __NL802154_CCA_ATTR_AFTER_LAST - 1 }; /** * enum nl802154_cca_opts - additional options for cca modes * * @NL802154_CCA_OPT_ENERGY_CARRIER_OR: NL802154_CCA_ENERGY_CARRIER with OR * @NL802154_CCA_OPT_ENERGY_CARRIER_AND: NL802154_CCA_ENERGY_CARRIER with AND */ enum nl802154_cca_opts { NL802154_CCA_OPT_ENERGY_CARRIER_AND, NL802154_CCA_OPT_ENERGY_CARRIER_OR, /* keep last */ __NL802154_CCA_OPT_ATTR_AFTER_LAST, NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1 }; /** * enum nl802154_supported_bool_states - bool states for bool capability entry * * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true * @__NL802154_SUPPORTED_BOOL_INVALD: reserved * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states */ enum nl802154_supported_bool_states { NL802154_SUPPORTED_BOOL_FALSE, NL802154_SUPPORTED_BOOL_TRUE, /* to handle them in a mask */ __NL802154_SUPPORTED_BOOL_INVALD, NL802154_SUPPORTED_BOOL_BOTH, /* keep last */ __NL802154_SUPPORTED_BOOL_AFTER_LAST, NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 }; #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL enum nl802154_dev_addr_modes { NL802154_DEV_ADDR_NONE, __NL802154_DEV_ADDR_INVALID, NL802154_DEV_ADDR_SHORT, NL802154_DEV_ADDR_EXTENDED, /* keep last */ __NL802154_DEV_ADDR_AFTER_LAST, NL802154_DEV_ADDR_MAX = __NL802154_DEV_ADDR_AFTER_LAST - 1 }; enum nl802154_dev_addr_attrs { NL802154_DEV_ADDR_ATTR_UNSPEC, NL802154_DEV_ADDR_ATTR_PAN_ID, NL802154_DEV_ADDR_ATTR_MODE, NL802154_DEV_ADDR_ATTR_SHORT, NL802154_DEV_ADDR_ATTR_EXTENDED, NL802154_DEV_ADDR_ATTR_PAD, /* keep last */ __NL802154_DEV_ADDR_ATTR_AFTER_LAST, NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 }; enum nl802154_key_id_modes { NL802154_KEY_ID_MODE_IMPLICIT, NL802154_KEY_ID_MODE_INDEX, NL802154_KEY_ID_MODE_INDEX_SHORT, NL802154_KEY_ID_MODE_INDEX_EXTENDED, /* keep last */ __NL802154_KEY_ID_MODE_AFTER_LAST, NL802154_KEY_ID_MODE_MAX = __NL802154_KEY_ID_MODE_AFTER_LAST - 1 }; enum nl802154_key_id_attrs { NL802154_KEY_ID_ATTR_UNSPEC, NL802154_KEY_ID_ATTR_MODE, NL802154_KEY_ID_ATTR_INDEX, NL802154_KEY_ID_ATTR_IMPLICIT, NL802154_KEY_ID_ATTR_SOURCE_SHORT, NL802154_KEY_ID_ATTR_SOURCE_EXTENDED, NL802154_KEY_ID_ATTR_PAD, /* keep last */ __NL802154_KEY_ID_ATTR_AFTER_LAST, NL802154_KEY_ID_ATTR_MAX = __NL802154_KEY_ID_ATTR_AFTER_LAST - 1 }; enum nl802154_seclevels { NL802154_SECLEVEL_NONE, NL802154_SECLEVEL_MIC32, NL802154_SECLEVEL_MIC64, NL802154_SECLEVEL_MIC128, NL802154_SECLEVEL_ENC, NL802154_SECLEVEL_ENC_MIC32, NL802154_SECLEVEL_ENC_MIC64, NL802154_SECLEVEL_ENC_MIC128, /* keep last */ __NL802154_SECLEVEL_AFTER_LAST, NL802154_SECLEVEL_MAX = __NL802154_SECLEVEL_AFTER_LAST - 1 }; enum nl802154_frames { NL802154_FRAME_BEACON, NL802154_FRAME_DATA, NL802154_FRAME_ACK, NL802154_FRAME_CMD, /* keep last */ __NL802154_FRAME_AFTER_LAST, NL802154_FRAME_MAX = __NL802154_FRAME_AFTER_LAST - 1 }; enum nl802154_cmd_frames { __NL802154_CMD_FRAME_INVALID, NL802154_CMD_FRAME_ASSOC_REQUEST, NL802154_CMD_FRAME_ASSOC_RESPONSE, NL802154_CMD_FRAME_DISASSOC_NOTIFY, NL802154_CMD_FRAME_DATA_REQUEST, NL802154_CMD_FRAME_PAN_ID_CONFLICT_NOTIFY, NL802154_CMD_FRAME_ORPHAN_NOTIFY, NL802154_CMD_FRAME_BEACON_REQUEST, NL802154_CMD_FRAME_COORD_REALIGNMENT, NL802154_CMD_FRAME_GTS_REQUEST, /* keep last */ __NL802154_CMD_FRAME_AFTER_LAST, NL802154_CMD_FRAME_MAX = __NL802154_CMD_FRAME_AFTER_LAST - 1 }; enum nl802154_seclevel_attrs { NL802154_SECLEVEL_ATTR_UNSPEC, NL802154_SECLEVEL_ATTR_LEVELS, NL802154_SECLEVEL_ATTR_FRAME, NL802154_SECLEVEL_ATTR_CMD_FRAME, NL802154_SECLEVEL_ATTR_DEV_OVERRIDE, /* keep last */ __NL802154_SECLEVEL_ATTR_AFTER_LAST, NL802154_SECLEVEL_ATTR_MAX = __NL802154_SECLEVEL_ATTR_AFTER_LAST - 1 }; /* TODO what is this? couldn't find in mib */ enum { NL802154_DEVKEY_IGNORE, NL802154_DEVKEY_RESTRICT, NL802154_DEVKEY_RECORD, /* keep last */ __NL802154_DEVKEY_AFTER_LAST, NL802154_DEVKEY_MAX = __NL802154_DEVKEY_AFTER_LAST - 1 }; enum nl802154_dev { NL802154_DEV_ATTR_UNSPEC, NL802154_DEV_ATTR_FRAME_COUNTER, NL802154_DEV_ATTR_PAN_ID, NL802154_DEV_ATTR_SHORT_ADDR, NL802154_DEV_ATTR_EXTENDED_ADDR, NL802154_DEV_ATTR_SECLEVEL_EXEMPT, NL802154_DEV_ATTR_KEY_MODE, NL802154_DEV_ATTR_PAD, /* keep last */ __NL802154_DEV_ATTR_AFTER_LAST, NL802154_DEV_ATTR_MAX = __NL802154_DEV_ATTR_AFTER_LAST - 1 }; enum nl802154_devkey { NL802154_DEVKEY_ATTR_UNSPEC, NL802154_DEVKEY_ATTR_FRAME_COUNTER, NL802154_DEVKEY_ATTR_EXTENDED_ADDR, NL802154_DEVKEY_ATTR_ID, NL802154_DEVKEY_ATTR_PAD, /* keep last */ __NL802154_DEVKEY_ATTR_AFTER_LAST, NL802154_DEVKEY_ATTR_MAX = __NL802154_DEVKEY_ATTR_AFTER_LAST - 1 }; enum nl802154_key { NL802154_KEY_ATTR_UNSPEC, NL802154_KEY_ATTR_ID, NL802154_KEY_ATTR_USAGE_FRAMES, NL802154_KEY_ATTR_USAGE_CMDS, NL802154_KEY_ATTR_BYTES, /* keep last */ __NL802154_KEY_ATTR_AFTER_LAST, NL802154_KEY_ATTR_MAX = __NL802154_KEY_ATTR_AFTER_LAST - 1 }; #define NL802154_KEY_SIZE 16 #define NL802154_CMD_FRAME_NR_IDS 256 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ #endif /* __NL802154_H */ wpan-tools-0.9/src/nl_extras.h000066400000000000000000000016421340645032500164310ustar00rootroot00000000000000#ifndef __NL_EXTRAS_H #define __NL_EXTRAS_H #if (LIBNL_VER_MIN < 2) || (LIBNL_VER_MIN == 2) && (LIBNL_VER_MIC <= 26) #ifndef NLA_S8 #define NLA_S8 13 #define NLA_PUT_S8(n, attrtype, value) \ NLA_PUT_TYPE(n, int8_t, attrtype, value) static inline int8_t nla_get_s8(struct nlattr *nla) { return *(int8_t *) nla_data(nla); } #endif /* NLA_S8 */ #ifndef NLA_S16 #define NLA_S16 14 #define NLA_PUT_S16(n, attrtype, value) \ NLA_PUT_TYPE(n, int16_t, attrtype, value) #endif /* NLA_S16 */ #ifndef NLA_S32 #define NLA_S32 15 #define NLA_PUT_S32(n, attrtype, value) \ NLA_PUT_TYPE(n, int32_t, attrtype, value) static inline int32_t nla_get_s32(struct nlattr *nla) { return *(int32_t *) nla_data(nla); } #endif /* NLA_S32 */ #ifndef NLA_S64 #define NLA_S64 16 #define NLA_PUT_S64(n, attrtype, value) \ NLA_PUT_TYPE(n, int64_t, attrtype, value) #endif /* NLA_S64 */ #endif /* LIBNL_VER_* */ #endif /* __NL_EXTRAS_H */ wpan-tools-0.9/src/phy.c000066400000000000000000000104611340645032500152240ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include "nl_extras.h" #include "nl802154.h" #include "iwpan.h" static int handle_channel_set(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { unsigned long channel; unsigned long page; char *end; if (argc < 2) return 1; /* PAGE */ page = strtoul(argv[0], &end, 10); if (*end != '\0') return 1; /* CHANNEL */ channel = strtoul(argv[1], &end, 10); if (*end != '\0') return 1; if (page > UINT8_MAX || channel > UINT8_MAX) return 1; NLA_PUT_U8(msg, NL802154_ATTR_PAGE, page); NLA_PUT_U8(msg, NL802154_ATTR_CHANNEL, channel); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, channel, " ", NL802154_CMD_SET_CHANNEL, 0, CIB_PHY, handle_channel_set, NULL); static int handle_tx_power_set(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { float dbm; char *end; if (argc < 1) return 1; /* TX_POWER */ dbm = strtof(argv[0], &end); if (*end != '\0') return 1; NLA_PUT_S32(msg, NL802154_ATTR_TX_POWER, DBM_TO_MBM(dbm)); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, tx_power, "", NL802154_CMD_SET_TX_POWER, 0, CIB_PHY, handle_tx_power_set, NULL); static int handle_cca_mode_set(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { enum nl802154_cca_modes cca_mode; char *end; if (argc < 1) return 1; /* CCA_MODE */ cca_mode = strtoul(argv[0], &end, 10); if (*end != '\0') return 1; if (cca_mode == NL802154_CCA_ENERGY_CARRIER) { enum nl802154_cca_opts cca_opt; if (argc < 2) return 1; /* CCA_OPT */ cca_opt = strtoul(argv[1], &end, 10); if (*end != '\0') return 1; NLA_PUT_U32(msg, NL802154_ATTR_CCA_OPT, cca_opt); } NLA_PUT_U32(msg, NL802154_ATTR_CCA_MODE, cca_mode); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, cca_mode, ">", NL802154_CMD_SET_CCA_MODE, 0, CIB_PHY, handle_cca_mode_set, NULL); static int handle_cca_ed_level(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { float level; char *end; if (argc < 1) return 1; /* CCA_ED_LEVEL */ level = strtof(argv[0], &end); if (*end != '\0') return 1; NLA_PUT_S32(msg, NL802154_ATTR_CCA_ED_LEVEL, DBM_TO_MBM(level)); return 0; nla_put_failure: return -ENOBUFS; } COMMAND(set, cca_ed_level, "", NL802154_CMD_SET_CCA_ED_LEVEL, 0, CIB_PHY, handle_cca_ed_level, NULL); #ifndef NETNS_RUN_DIR #define NETNS_RUN_DIR "/var/run/netns" #endif static int netns_get_fd(const char *name) { char pathbuf[MAXPATHLEN]; const char *path, *ptr; path = name; ptr = strchr(name, '/'); if (!ptr) { snprintf(pathbuf, sizeof(pathbuf), "%s/%s", NETNS_RUN_DIR, name ); path = pathbuf; } return open(path, O_RDONLY); } static int handle_netns(struct nl802154_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; int fd; if (argc < 1 || !*argv[0]) return 1; if (argc == 1) { NLA_PUT_U32(msg, NL802154_ATTR_PID, strtoul(argv[0], &end, 10)); if (*end != '\0') { printf("Invalid parameter: pid(%s)\n", argv[0]); return 1; } return 0; } if (argc != 2 || strcmp(argv[0], "name")) return 1; if ((fd = netns_get_fd(argv[1])) >= 0) { NLA_PUT_U32(msg, NL802154_ATTR_NETNS_FD, fd); return 0; } else { printf("Invalid parameter: nsname(%s)\n", argv[0]); } return 1; nla_put_failure: return -ENOBUFS; } COMMAND(set, netns, "{ | name }", NL802154_CMD_SET_WPAN_PHY_NETNS, 0, CIB_PHY, handle_netns, "Put this wpan device into a different network namespace:\n" " - change network namespace by process id\n" " - change network namespace by name from "NETNS_RUN_DIR"\n" " or by absolute path (man ip-netns)\n"); wpan-tools-0.9/src/sections.c000066400000000000000000000000601340645032500162450ustar00rootroot00000000000000#include "iwpan.h" SECTION(get); SECTION(set); wpan-tools-0.9/wpan-hwsim/000077500000000000000000000000001340645032500155615ustar00rootroot00000000000000wpan-tools-0.9/wpan-hwsim/Makefile.am000066400000000000000000000002551340645032500176170ustar00rootroot00000000000000bin_PROGRAMS = wpan-hwsim wpan_hwsim_SOURCES = wpan-hwsim.c \ mac802154_hwsim.h wpan_hwsim_CFLAGS = $(AM_CFLAGS) $(LIBNL3_CFLAGS) wpan_hwsim_LDADD = $(LIBNL3_LIBS) wpan-tools-0.9/wpan-hwsim/mac802154_hwsim.h000066400000000000000000000047311340645032500203720ustar00rootroot00000000000000#ifndef __MAC802154_HWSIM_H #define __MAC802154_HWSIM_H /* mac802154 hwsim netlink commands * * @MAC802154_HWSIM_CMD_UNSPEC: unspecified command to catch error * @MAC802154_HWSIM_CMD_GET_RADIO: fetch information about existing radios * @MAC802154_HWSIM_CMD_SET_RADIO: change radio parameters during runtime * @MAC802154_HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters * returns the radio ID (>= 0) or negative on errors, if successful * then multicast the result * @MAC802154_HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted * @MAC802154_HWSIM_CMD_GET_EDGE: fetch information about existing edges * @MAC802154_HWSIM_CMD_SET_EDGE: change edge parameters during runtime * @MAC802154_HWSIM_CMD_DEL_EDGE: delete edges between radios * @MAC802154_HWSIM_CMD_NEW_EDGE: create a new edge between two radios * @__MAC802154_HWSIM_CMD_MAX: enum limit */ enum { MAC802154_HWSIM_CMD_UNSPEC, MAC802154_HWSIM_CMD_GET_RADIO, MAC802154_HWSIM_CMD_SET_RADIO, MAC802154_HWSIM_CMD_NEW_RADIO, MAC802154_HWSIM_CMD_DEL_RADIO, MAC802154_HWSIM_CMD_GET_EDGE, MAC802154_HWSIM_CMD_SET_EDGE, MAC802154_HWSIM_CMD_DEL_EDGE, MAC802154_HWSIM_CMD_NEW_EDGE, __MAC802154_HWSIM_CMD_MAX, }; #define MAC802154_HWSIM_CMD_MAX (__MAC802154_HWSIM_MAX - 1) /* mac802154 hwsim netlink attributes * * @MAC802154_HWSIM_ATTR_UNSPEC: unspecified attribute to catch error * @MAC802154_HWSIM_ATTR_RADIO_ID: u32 attribute to identify the radio * @MAC802154_HWSIM_ATTR_EDGE: nested attribute of edges * @MAC802154_HWSIM_ATTR_EDGES: list if nested attributes which contains the * edge information according the radio id * @__MAC802154_HWSIM_ATTR_MAX: enum limit */ enum { MAC802154_HWSIM_ATTR_UNSPEC, MAC802154_HWSIM_ATTR_RADIO_ID, MAC802154_HWSIM_ATTR_RADIO_EDGE, MAC802154_HWSIM_ATTR_RADIO_EDGES, __MAC802154_HWSIM_ATTR_MAX, }; #define MAC802154_HWSIM_ATTR_MAX (__MAC802154_HWSIM_ATTR_MAX - 1) /* mac802154 hwsim edge netlink attributes * * @MAC802154_HWSIM_EDGE_ATTR_UNSPEC: unspecified attribute to catch error * @MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID: radio id where the edge points to * @MAC802154_HWSIM_EDGE_ATTR_LQI: LQI value which the endpoint radio will * receive for this edge * @__MAC802154_HWSIM_ATTR_MAX: enum limit */ enum { MAC802154_HWSIM_EDGE_ATTR_UNSPEC, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, MAC802154_HWSIM_EDGE_ATTR_LQI, __MAC802154_HWSIM_EDGE_ATTR_MAX, }; #define MAC802154_HWSIM_EDGE_ATTR_MAX (__MAC802154_HWSIM_EDGE_ATTR_MAX - 1) #endif /* __MAC802154_HWSIM_H */ wpan-tools-0.9/wpan-hwsim/wpan-hwsim.c000066400000000000000000000302001340645032500200120ustar00rootroot00000000000000/* * Linux IEEE 802.15.4 hwsim tool * * Copyright (C) 2018 Alexander Aring * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include "mac802154_hwsim.h" #include "config.h" static struct nl_sock *nl_sock; static int nlhwsim_id; static int nlhwsim_init(void) { int err; nl_sock = nl_socket_alloc(); if (!nl_sock) { fprintf(stderr, "Failed to allocate netlink socket.\n"); return -ENOMEM; } nl_socket_set_buffer_size(nl_sock, 8192, 8192); if (genl_connect(nl_sock)) { fprintf(stderr, "Failed to connect to generic netlink.\n"); err = -ENOLINK; goto out_handle_destroy; } nlhwsim_id = genl_ctrl_resolve(nl_sock, "MAC802154_HWSIM"); if (nlhwsim_id < 0) { fprintf(stderr, "MAC802154_HWSIM not found.\n"); err = -ENOENT; nl_close(nl_sock); goto out_handle_destroy; } return 0; out_handle_destroy: nl_socket_free(nl_sock); return err; } static void nlhwsim_cleanup(void) { nl_close(nl_sock); nl_socket_free(nl_sock); } static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { int *ret = arg; *ret = err->error; return NL_STOP; } static int hwsim_create(void) { struct nl_msg *msg; struct nl_cb *cb; int idx = 0, ret; cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) return -ENOMEM; msg = nlmsg_alloc(); if (!msg) { nl_cb_put(cb); return -ENOMEM; } genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, 0, MAC802154_HWSIM_CMD_NEW_RADIO, 0); ret = nl_send_auto(nl_sock, msg); if (ret < 0) { nl_cb_put(cb); return ret; } nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &idx); nl_recvmsgs(nl_sock, cb); printf("wpan_hwsim radio%d registered.\n", idx); nl_cb_put(cb); return 0; } static int nl_msg_dot_cb(struct nl_msg* msg, void* arg) { static struct nla_policy edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = { [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 }, [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 }, }; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(nlh); struct nlattr *attrs[MAC802154_HWSIM_ATTR_MAX + 1]; struct nlattr *edge[MAC802154_HWSIM_EDGE_ATTR_MAX + 1]; unsigned int *ignore_idx = arg; struct nlattr *nl_edge; uint32_t idx, idx2; uint8_t lqi = 0xff; int rem_edge; int rc; nla_parse(attrs, MAC802154_HWSIM_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!attrs[MAC802154_HWSIM_ATTR_RADIO_ID]) return NL_SKIP; idx = nla_get_u32(attrs[MAC802154_HWSIM_ATTR_RADIO_ID]); if (idx == *ignore_idx) return NL_SKIP; if (!attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES]) return NL_SKIP; nla_for_each_nested(nl_edge, attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES], rem_edge) { rc = nla_parse_nested(edge, MAC802154_HWSIM_EDGE_ATTR_MAX, nl_edge, edge_policy); if (rc) return NL_SKIP; idx2 = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]); if (idx2 == *ignore_idx) continue; lqi = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_LQI]); printf("\t%" PRIu32 " -> %" PRIu32 "[label=%" PRIu8 "];\n", idx, idx2, lqi); } return NL_SKIP; } static int nl_msg_cb(struct nl_msg* msg, void* arg) { static struct nla_policy edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = { [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 }, [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 }, }; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(nlh); struct nlattr *attrs[MAC802154_HWSIM_ATTR_MAX + 1]; struct nlattr *edge[MAC802154_HWSIM_EDGE_ATTR_MAX + 1]; unsigned int *ignore_idx = arg; struct nlattr *nl_edge; uint32_t idx; uint8_t lqi; int rem_edge; int rc; nla_parse(attrs, MAC802154_HWSIM_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!attrs[MAC802154_HWSIM_ATTR_RADIO_ID]) return NL_SKIP; idx = nla_get_u32(attrs[MAC802154_HWSIM_ATTR_RADIO_ID]); if (idx == *ignore_idx) return NL_SKIP; printf("wpan_hwsim radio%" PRIu32 ":\n", idx); if (!attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES]) return NL_SKIP; nla_for_each_nested(nl_edge, attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES], rem_edge) { rc = nla_parse_nested(edge, MAC802154_HWSIM_EDGE_ATTR_MAX, nl_edge, edge_policy); if (rc) return NL_SKIP; idx = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]); if (idx == *ignore_idx) continue; printf("\tedge:\n"); printf("\t\tradio%" PRIu32 "\n", idx); lqi = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_LQI]); printf("\t\tlqi: 0x%02x\n", lqi); } return NL_SKIP; } static int hwsim_dump(bool dot, int unsigned ignore_idx) { struct nl_msg *msg; int rc; nl_socket_modify_cb(nl_sock, NL_CB_VALID, NL_CB_CUSTOM, dot ? nl_msg_dot_cb : nl_msg_cb, &ignore_idx); msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, NLM_F_DUMP, MAC802154_HWSIM_CMD_GET_RADIO, 0); if (dot) printf("digraph {\n"); rc = nl_send_sync(nl_sock, msg); if (rc < 0) return rc; if (dot) printf("}\n"); return rc; } static int hwsim_del(uint32_t idx) { struct nl_msg *msg; struct nl_cb *cb; int err = 0; int rc; cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) return -ENOMEM; msg = nlmsg_alloc(); if (!msg) { nl_cb_put(cb); return -ENOMEM; } genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, 0, MAC802154_HWSIM_CMD_DEL_RADIO, 0); nla_put_u32(msg, MAC802154_HWSIM_ATTR_RADIO_ID, idx); nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); rc = nl_send_auto(nl_sock, msg); nl_recvmsgs(nl_sock, cb); if (err < 0) fprintf(stderr, "Failed to remove radio: %s\n", strerror(abs(err))); nl_cb_put(cb); return rc; } static int hwsim_cmd_edge(int cmd, uint32_t idx, uint32_t idx2, uint8_t lqi) { struct nlattr* edge; struct nl_msg *msg; struct nl_cb *cb; int err = 0; int rc; cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) return -ENOMEM; msg = nlmsg_alloc(); if (!msg) { nl_cb_put(cb); return -ENOMEM; } genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, 0, cmd, 0); nla_put_u32(msg, MAC802154_HWSIM_ATTR_RADIO_ID, idx); edge = nla_nest_start(msg, MAC802154_HWSIM_ATTR_RADIO_EDGE); if (!edge) { nl_cb_put(cb); return -ENOMEM; } nla_put_u32(msg, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, idx2); if (cmd == MAC802154_HWSIM_CMD_SET_EDGE) nla_put_u8(msg, MAC802154_HWSIM_EDGE_ATTR_LQI, lqi); nla_nest_end(msg, edge); nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); rc = nl_send_auto(nl_sock, msg); nl_recvmsgs(nl_sock, cb); if (err < 0) fprintf(stderr, "Failed to add or remove edge: %s\n", strerror(abs(err))); nl_cb_put(cb); return rc; } static int hwsim_do_cmd(uint32_t cmd, unsigned int idx, unsigned int idx2, uint8_t lqi, bool dot, unsigned int ignore_idx) { int rc; rc = nlhwsim_init(); if (rc) return 1; switch (cmd) { case MAC802154_HWSIM_CMD_GET_RADIO: rc = hwsim_dump(dot, ignore_idx); break; case MAC802154_HWSIM_CMD_DEL_RADIO: rc = hwsim_del(idx); break; case MAC802154_HWSIM_CMD_NEW_RADIO: rc = hwsim_create(); break; case MAC802154_HWSIM_CMD_NEW_EDGE: case MAC802154_HWSIM_CMD_DEL_EDGE: case MAC802154_HWSIM_CMD_SET_EDGE: rc = hwsim_cmd_edge(cmd, idx, idx2, lqi); break; default: rc = -EINVAL; break; } nlhwsim_cleanup(); return rc; } static void print_usage(void) { printf("wpan_hwsim [OPTION...] [CMD...]\n"); printf("\n"); printf(" possible options:\n"); printf(" -h, --help show this help\n"); printf(" -v, --version show version\n"); printf(" -d, --dot dump topology as dot format\n"); printf(" -i, --ignore filter one node from dump (useful for virtual monitors)\n"); printf("\n"); printf(" possible commands:\n"); printf(" add add new hwsim radio\n"); printf(" del IDX del hwsim radio according idx\n"); printf(" edge add IDX IDX add edge between radios\n"); printf(" edge del IDX IDX delete edge between radios\n"); printf(" edge lqi IDX IDX LQI set lqi value for a specific edge\n"); printf("\n"); printf(" To dump all node information just call this program without any command\n"); } static void print_version(void) { printf("wpan-hwsim " PACKAGE_VERSION "\n"); } int main(int argc, const char *argv[]) { unsigned long int idx, idx2, lqi = 0, ignore_idx = ULONG_MAX; bool dot = false; int cmd; int rc; int c; while (1) { int option_index = 0; static struct option long_options[] = { {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'v' }, {"dot", no_argument, 0, 'd' }, {"ignore", required_argument, 0, 'i' }, {0, 0, 0, 0 } }; c = getopt_long(argc, (char **)argv, "vhdi:", long_options, &option_index); if (c == -1) break; switch (c) { case 'v': print_version(); return EXIT_SUCCESS; case 'h': print_usage(); return EXIT_SUCCESS; case 'd': dot = true; break; case 'i': ignore_idx = strtoul(optarg, NULL, 0); if (ignore_idx == ULONG_MAX) { fprintf(stderr, "Invalid radio index for ignore argument\n"); return EXIT_FAILURE; } break; default: print_usage(); return EXIT_FAILURE; } } if (optind + 1 > argc) { rc = hwsim_do_cmd(MAC802154_HWSIM_CMD_GET_RADIO, 0, 0, 0, dot, ignore_idx); if (rc < 0) return EXIT_FAILURE; else goto out; } if (!strncmp(argv[optind], "add", 3)) { rc = hwsim_do_cmd(MAC802154_HWSIM_CMD_NEW_RADIO, 0, 0, 0, 0, 0); if (rc < 0) return EXIT_FAILURE; } else if (!strncmp(argv[optind], "del", 3)) { if (optind + 2 > argc) { fprintf(stderr, "Missing radio index for delete\n"); return EXIT_FAILURE; } else { idx = strtoul(argv[optind + 1], NULL, 0); if (idx == ULONG_MAX) { fprintf(stderr, "Invalid radio index for delete\n"); return EXIT_FAILURE; } rc = hwsim_do_cmd(MAC802154_HWSIM_CMD_DEL_RADIO, idx, 0, 0, 0, 0); if (rc < 0) return EXIT_FAILURE; } } else if (!strncmp(argv[optind], "edge", 4)) { if (optind + 4 > argc) { fprintf(stderr, "Missing edge radio index information\n"); return EXIT_FAILURE; } else { if (!strncmp(argv[optind + 1], "add", 3)) { cmd = MAC802154_HWSIM_CMD_NEW_EDGE; } else if (!strncmp(argv[optind + 1], "del", 3)) { cmd = MAC802154_HWSIM_CMD_DEL_EDGE; } else if (!strncmp(argv[optind + 1], "lqi", 3)) { cmd = MAC802154_HWSIM_CMD_SET_EDGE; } else { fprintf(stderr, "Invalid edge command\n"); return EXIT_FAILURE; } if (cmd == MAC802154_HWSIM_CMD_SET_EDGE) { if (optind + 5 > argc) { fprintf(stderr, "LQI information missing\n"); return EXIT_FAILURE; } lqi = strtoul(argv[optind + 4], NULL, 0); if (lqi == ULONG_MAX || lqi > 0xff) { fprintf(stderr, "Invalid lqi value\n"); return EXIT_FAILURE; } } idx = strtoul(argv[optind + 2], NULL, 0); if (idx == ULONG_MAX) { fprintf(stderr, "Invalid first radio index for edge command\n"); return EXIT_FAILURE; } idx2 = strtoul(argv[optind + 3], NULL, 0); if (idx2 == ULONG_MAX) { fprintf(stderr, "Invalid second radio index for edge command\n"); return EXIT_FAILURE; } rc = hwsim_do_cmd(cmd, idx, idx2, lqi, 0, 0); if (rc < 0) return EXIT_FAILURE; } } else { fprintf(stderr, "Unknown command\n"); print_usage(); return EXIT_FAILURE; } out: return EXIT_SUCCESS; } wpan-tools-0.9/wpan-ping/000077500000000000000000000000001340645032500153675ustar00rootroot00000000000000wpan-tools-0.9/wpan-ping/.gitignore000066400000000000000000000000211340645032500173500ustar00rootroot00000000000000.deps/ wpan-ping wpan-tools-0.9/wpan-ping/Makefile.am000066400000000000000000000002541340645032500174240ustar00rootroot00000000000000bin_PROGRAMS = wpan-ping wpan_ping_SOURCES = wpan-ping.c wpan_ping_CFLAGS = $(AM_CFLAGS) $(LIBNL3_CFLAGS) wpan_ping_LDADD = $(LIBNL3_LIBS) EXTRA_DIST = README.wpan-ping wpan-tools-0.9/wpan-ping/README.wpan-ping000066400000000000000000000016701340645032500201520ustar00rootroot00000000000000wpan-ping aims to offer ping/ping6 like functionality on a IEEE 802.15.4 level. No control message protocol is defined so we will simply use DGRAM's over a plain socket with a server component to emulate the behaviour. One can specify packet count (-c) as well as size (-s) and the interface to be used. Example usage server side: -------------------------- ./wpan-ping -d 0x0001 #0x0001 is the client short address Server mode. Waiting for packets... Example usage client side: -------------------------- ./wpan-ping -a 0x0003 -c 5 -s 114 #0x0003 is the server short address PING 0x0003 (PAN ID 0xbeef) 114 data bytes 114 bytes from 0x0003 seq=0 time=22.0 ms 114 bytes from 0x0003 seq=1 time=27.9 ms 114 bytes from 0x0003 seq=2 time=21.3 ms 114 bytes from 0x0003 seq=3 time=21.3 ms 114 bytes from 0x0003 seq=4 time=20.3 ms --- 0x0003 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss rtt min/avg/max = 20.261/22.539/27.895 ms wpan-tools-0.9/wpan-ping/wpan-ping.c000066400000000000000000000334411340645032500174400ustar00rootroot00000000000000/* * Linux IEEE 802.15.4 ping tool * * Copyright (C) 2015 Stefan Schmidt * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../src/nl802154.h" #define MIN_PAYLOAD_LEN 5 #define MAX_PAYLOAD_LEN 105 //116 with short address #define IEEE802154_ADDR_LEN 8 /* Set the dispatch header to not 6lowpan for compat */ #define NOT_A_6LOWPAN_FRAME 0x00 #define DEFAULT_INTERVAL 500 #define DEBUG 0 enum { IEEE802154_ADDR_NONE = 0x0, IEEE802154_ADDR_SHORT = 0x2, IEEE802154_ADDR_LONG = 0x3, }; struct ieee802154_addr_sa { int addr_type; uint16_t pan_id; union { uint8_t hwaddr[IEEE802154_ADDR_LEN]; uint16_t short_addr; }; }; struct sockaddr_ieee802154 { sa_family_t family; struct ieee802154_addr_sa addr; }; #ifdef _GNU_SOURCE static const struct option perf_long_opts[] = { { "daemon", no_argument, NULL, 'd' }, { "address", required_argument, NULL, 'a' }, { "extended", no_argument, NULL, 'e' }, { "count", required_argument, NULL, 'c' }, { "size", required_argument, NULL, 's' }, { "interface", required_argument, NULL, 'i' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 }, }; #endif struct config { char packet_len; unsigned short packets; bool extended; bool server; char *interface; struct nl_sock *nl_sock; int nl802154_id; struct sockaddr_ieee802154 src; struct sockaddr_ieee802154 dst; unsigned short interval; }; extern char *optarg; static void usage(const char *name) { printf("Usage: %s OPTIONS\n" "OPTIONS:\n" "--daemon |-d\n" "--address | -a server address (short e.g. 0x1234 or extended e.g. 00:11:22:33:44:55:66:77)\n" "--extended | -e use extended addressing scheme for -a / --address (default is the short)\n" "--count | -c number of packets\n" "--size | -s packet length\n" "--interface | -i listen on this interface (default wpan0)\n" "--interval | -I wait interval in milliseconds between sending packets (default 500ms)\n" "--version | -v print out version\n" "--help | -h this usage text\n", name); } static int nl802154_init(struct config *conf) { int err; conf->nl_sock = nl_socket_alloc(); if (!conf->nl_sock) { fprintf(stderr, "Failed to allocate netlink socket.\n"); return -ENOMEM; } nl_socket_set_buffer_size(conf->nl_sock, 8192, 8192); if (genl_connect(conf->nl_sock)) { fprintf(stderr, "Failed to connect to generic netlink.\n"); err = -ENOLINK; goto out_handle_destroy; } conf->nl802154_id = genl_ctrl_resolve(conf->nl_sock, "nl802154"); if (conf->nl802154_id < 0) { fprintf(stderr, "nl802154 not found.\n"); err = -ENOENT; goto out_handle_destroy; } return 0; out_handle_destroy: nl_socket_free(conf->nl_sock); return err; } static void nl802154_cleanup(struct config *conf) { nl_close(conf->nl_sock); nl_socket_free(conf->nl_sock); } static int nl_msg_cb(struct nl_msg* msg, void* arg) { struct config *conf = arg; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[NL802154_ATTR_MAX+1]; uint64_t temp; struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(nlh); nla_parse(attrs, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!attrs[NL802154_ATTR_SHORT_ADDR] || !attrs[NL802154_ATTR_PAN_ID] || !attrs[NL802154_ATTR_EXTENDED_ADDR]) return NL_SKIP; conf->src.family = AF_IEEE802154; conf->src.addr.pan_id = conf->dst.addr.pan_id = nla_get_u16(attrs[NL802154_ATTR_PAN_ID]); if (!conf->extended) { conf->src.addr.addr_type = IEEE802154_ADDR_SHORT; conf->src.addr.short_addr = nla_get_u16(attrs[NL802154_ATTR_SHORT_ADDR]); } else { conf->src.addr.addr_type = IEEE802154_ADDR_LONG; temp = htobe64(nla_get_u64(attrs[NL802154_ATTR_EXTENDED_ADDR])); memcpy(&conf->src.addr.hwaddr, &temp, IEEE802154_ADDR_LEN); } return NL_SKIP; } static int get_interface_info(struct config *conf) { struct nl_msg *msg; nl802154_init(conf); /* Build and send message */ nl_socket_modify_cb(conf->nl_sock, NL_CB_VALID, NL_CB_CUSTOM, nl_msg_cb, conf); msg = nlmsg_alloc(); genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, conf->nl802154_id, 0, NLM_F_DUMP, NL802154_CMD_GET_INTERFACE, 0); nla_put_string(msg, NL802154_ATTR_IFNAME, conf->interface); nl_send_sync(conf->nl_sock, msg); nl802154_cleanup(conf); return 0; } #if DEBUG static void dump_packet(unsigned char *buf, int len) { int i; fprintf(stdout, "Packet payload:"); for (i = 0; i < len; i++) { printf(" %x", buf[i]); } printf("\n"); } #endif static int generate_packet(unsigned char *buf, struct config *conf, unsigned int seq_num) { int i; buf[0] = NOT_A_6LOWPAN_FRAME; buf[1] = conf->packet_len; buf[2] = seq_num >> 8; /* Upper byte */ buf[3] = seq_num & 0xFF; /* Lower byte */ for (i = 4; i < conf->packet_len; i++) { buf[i] = 0xAB; } return 0; } static int print_address(char *addr, uint8_t dst_extended[IEEE802154_ADDR_LEN]) { snprintf(addr, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", dst_extended[0], dst_extended[1], dst_extended[2], dst_extended[3], dst_extended[4], dst_extended[5], dst_extended[6], dst_extended[7]); return 0; } static void sleeping(struct timeval ping_start_time, struct timeval timeout) { struct timeval curr_time; long sec, usec, interval_usec, timeout_usec; long sleep_usec = 0; gettimeofday(&curr_time, NULL); sec = curr_time.tv_sec - ping_start_time.tv_sec; usec = curr_time.tv_usec - ping_start_time.tv_usec; if (usec < 0) { usec += 1000000; sec--; } interval_usec = sec * 1000000 + usec; timeout_usec = timeout.tv_sec * 1000000 + timeout.tv_usec; if (interval_usec < timeout_usec) { sleep_usec = timeout_usec - interval_usec; usleep(sleep_usec); } } static int measure_roundtrip(struct config *conf, int sd) { unsigned char *buf; struct timeval ping_start_time, start_time, end_time, timeout; long sec = 0, usec = 0; long sec_max = 0, usec_max = 0; long sec_min = 2147483647, usec_min = 2147483647; long sum_sec = 0, sum_usec = 0; int i, ret, count; unsigned short seq_num; float rtt_min = 0.0, rtt_avg = 0.0, rtt_max = 0.0; float packet_loss = 100.0; char addr[24]; if (conf->extended) print_address(addr, conf->dst.addr.hwaddr); if (conf->extended) fprintf(stdout, "PING %s (PAN ID 0x%04x) %i data bytes\n", addr, conf->dst.addr.pan_id, conf->packet_len); else fprintf(stdout, "PING 0x%04x (PAN ID 0x%04x) %i data bytes\n", conf->dst.addr.short_addr, conf->dst.addr.pan_id, conf->packet_len); buf = (unsigned char *)malloc(MAX_PAYLOAD_LEN); /* default 500ms seconds packet receive timeout */ if (conf->interval >= 1000) { /* when interval is larger than 1s */ double d_interval = (conf->interval * 1.0) / 1000; timeout.tv_sec = (int)d_interval; timeout.tv_usec = (int)((d_interval - timeout.tv_sec) * 1000000); } else { timeout.tv_sec = 0; timeout.tv_usec = conf->interval * 1000; } ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&timeout,sizeof(struct timeval)); if (ret < 0) { perror("setsockopt receive timeout"); } count = 0; for (i = 0; i < conf->packets; i++) { gettimeofday(&ping_start_time, NULL); generate_packet(buf, conf, i); seq_num = (buf[2] << 8)| buf[3]; ret = sendto(sd, buf, conf->packet_len, 0, (struct sockaddr *)&conf->dst, sizeof(conf->dst)); if (ret < 0) { perror("sendto"); } gettimeofday(&start_time, NULL); ret = recv(sd, buf, conf->packet_len, 0); if (buf[0] != NOT_A_6LOWPAN_FRAME) { printf("Non-wpanping packet was received\n"); continue; } if (seq_num != ((buf[2] << 8)| buf[3])) { printf("Sequenze number did not match\n"); continue; } if (ret > 0) { gettimeofday(&end_time, NULL); count++; sec = end_time.tv_sec - start_time.tv_sec; sum_sec += sec; usec = end_time.tv_usec - start_time.tv_usec; if (usec < 0) { usec += 1000000; sec--; sum_sec--; } sum_usec += usec; if (sec > sec_max) sec_max = sec; else if (sec < sec_min) sec_min = sec; if (usec > usec_max) usec_max = usec; else if (usec < usec_min) usec_min = usec; if (sec > 0) fprintf(stdout, "Warning: packet return time over a second!\n"); if (conf->extended) fprintf(stdout, "%i bytes from %s seq=%i time=%.1f ms\n", ret, addr, (int)seq_num, (float)usec/1000); else fprintf(stdout, "%i bytes from 0x%04x seq=%i time=%.1f ms\n", ret, conf->dst.addr.short_addr, (int)seq_num, (float)usec/1000); } else fprintf(stderr, "Hit %i ms packet timeout\n", conf->interval); /* sleeping */ sleeping(ping_start_time, timeout); } if (count) packet_loss = 100 - ((100 * count)/conf->packets); if (usec_min) rtt_min = (float)usec_min/1000; if (sum_usec && count) rtt_avg = ((float)sum_usec/(float)count)/1000; if (usec_max) rtt_max = (float)usec_max/1000; if (conf->extended) fprintf(stdout, "\n--- %s ping statistics ---\n", addr); else fprintf(stdout, "\n--- 0x%04x ping statistics ---\n", conf->dst.addr.short_addr); fprintf(stdout, "%i packets transmitted, %i received, %.0f%% packet loss\n", conf->packets, count, packet_loss); fprintf(stdout, "rtt min/avg/max = %.3f/%.3f/%.3f ms\n", rtt_min, rtt_avg, rtt_max); free(buf); return 0; } static void init_server(int sd) { ssize_t len; unsigned char *buf; struct sockaddr_ieee802154 src; socklen_t addrlen; addrlen = sizeof(src); len = 0; fprintf(stdout, "Server mode. Waiting for packets...\n"); buf = (unsigned char *)malloc(MAX_PAYLOAD_LEN); while (1) { len = recvfrom(sd, buf, MAX_PAYLOAD_LEN, 0, (struct sockaddr *)&src, &addrlen); if (len < 0) { perror("recvfrom"); continue; } #if DEBUG dump_packet(buf, len); #endif if (buf[0] == NOT_A_6LOWPAN_FRAME) { /* Send same packet back */ len = sendto(sd, buf, len, 0, (struct sockaddr *)&src, addrlen); if (len < 0) { perror("sendto"); continue; } } } free(buf); } static int init_network(struct config *conf) { int sd; int ret; sd = socket(PF_IEEE802154, SOCK_DGRAM, 0); if (sd < 0) { perror("socket"); return 1; } /* Bind socket on this side */ ret = bind(sd, (struct sockaddr *)&conf->src, sizeof(conf->src)); if (ret) { perror("bind"); close(sd); return 1; } if (conf->server) init_server(sd); else measure_roundtrip(conf, sd); shutdown(sd, SHUT_RDWR); close(sd); return 0; } static int parse_dst_addr(struct config *conf, char *arg) { int i; if (!arg) return -1; /* PAN ID is filled from netlink in get_interface_info */ conf->dst.family = AF_IEEE802154; if (!conf->extended) { conf->dst.addr.addr_type = IEEE802154_ADDR_SHORT; conf->dst.addr.short_addr = strtol(arg, NULL, 16); return 0; } conf->dst.addr.addr_type = IEEE802154_ADDR_LONG; for (i = 0; i < IEEE802154_ADDR_LEN; i++) { int temp; char *cp = strchr(arg, ':'); if (cp) { *cp = 0; cp++; } if (sscanf(arg, "%x", &temp) != 1) return -1; if (temp < 0 || temp > 255) return -1; conf->dst.addr.hwaddr[i] = temp; if (!cp) break; arg = cp; } if (i < IEEE802154_ADDR_LEN - 1) return -1; return 0; } int main(int argc, char *argv[]) { int c, ret; struct config *conf; char *dst_addr = NULL; conf = calloc(1, sizeof(struct config)); /* Default to interface wpan0 if nothing else is given */ conf->interface = "wpan0"; /* Default to minimum packet size */ conf->packet_len = MIN_PAYLOAD_LEN; /* Default to short addressing */ conf->extended = false; /* Default to client mode */ conf->server = false; /* Default to 65535 packets being sent */ conf->packets = USHRT_MAX; /* Default to 500ms for interval value */ conf->interval = DEFAULT_INTERVAL; if (argc < 2) { usage(argv[0]); exit(1); } while (1) { #ifdef _GNU_SOURCE int opt_idx = -1; c = getopt_long(argc, argv, "a:ec:s:i:dvhI:", perf_long_opts, &opt_idx); #else c = getopt(argc, argv, "a:ec:s:i:dvhI:"); #endif if (c == -1) break; switch(c) { case 'a': dst_addr = optarg; break; case 'e': conf->extended = true; break; case 'd': conf->server = true; break; case 'c': conf->packets = atoi(optarg); break; case 's': conf->packet_len = atoi(optarg); if (conf->packet_len >= MAX_PAYLOAD_LEN || conf->packet_len < MIN_PAYLOAD_LEN) { printf("Packet size must be between %i and %i.\n", MIN_PAYLOAD_LEN, MAX_PAYLOAD_LEN - 1); free(conf); return 1; } break; case 'i': conf->interface = optarg; break; case 'I': conf->interval = atoi(optarg); break; case 'v': fprintf(stdout, "wpan-ping " PACKAGE_VERSION "\n"); free(conf); return 1; case 'h': usage(argv[0]); free(conf); return 1; default: usage(argv[0]); free(conf); return 1; } } get_interface_info(conf); if (!conf->server) { ret = parse_dst_addr(conf, dst_addr); if (ret< 0) { fprintf(stderr, "Address given in wrong format.\n"); return 1; } } init_network(conf); free(conf); return 0; }