commit
5fe57b4659
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
create_tap() {
|
||||
ip tuntap add ${TAP} mode tap user ${USER}
|
||||
sysctl -w net.ipv6.conf.${TAP}.forwarding=1
|
||||
sysctl -w net.ipv6.conf.${TAP}.accept_ra=0
|
||||
ip link set ${TAP} up
|
||||
ip a a fe80::1/64 dev ${TAP}
|
||||
ip a a fd00:dead:beef::1/128 dev lo
|
||||
ip route add ${PREFIX} via fe80::2 dev ${TAP}
|
||||
}
|
||||
|
||||
remove_tap() {
|
||||
ip tuntap del ${TAP} mode tap
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
echo "Cleaning up..."
|
||||
remove_tap
|
||||
ip a d fd00:dead:beef::1/128 dev lo
|
||||
kill $UHCPD_PID
|
||||
trap "" INT QUIT TERM EXIT
|
||||
}
|
||||
|
||||
start_uhcpd() {
|
||||
${UHCPD} ${TAP} ${PREFIX} > /dev/null &
|
||||
UHCPD_PID=$!
|
||||
}
|
||||
|
||||
PORT=$1
|
||||
TAP=$2
|
||||
PREFIX=$3
|
||||
UHCPD=../uhcpd/bin/uhcpd
|
||||
|
||||
[ -z "$PORT" -o -z "$TAP" -o -z "$PREFIX" ] && {
|
||||
echo "usage: $0 <serial-port> <tap-device> <prefix>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap "cleanup" INT QUIT TERM EXIT
|
||||
|
||||
create_tap && start_uhcpd && ./ethos $TAP $PORT
|
@ -0,0 +1 @@
|
||||
bin
|
@ -0,0 +1,17 @@
|
||||
CFLAGS?=-g -O3 -Wall
|
||||
CFLAGS_EXTRA=-DUHCP_SERVER
|
||||
all: bin bin/uhcpd
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
RIOTBASE:=../../..
|
||||
UHCP_DIR:=$(RIOTBASE)/sys/net/application_layer/uhcp
|
||||
RIOT_INCLUDE=$(RIOTBASE)/sys/include
|
||||
SRCS:=$(UHCP_DIR)/uhcp.c uhcpd.c
|
||||
HDRS:=$(RIOT_INCLUDE)/net/uhcp.h
|
||||
bin/uhcpd: $(SRCS) $(HDRS)
|
||||
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) -I$(RIOT_INCLUDE) $(SRCS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f bin/uhcpd
|
@ -0,0 +1,5 @@
|
||||
# pyjam build file. See https://github.com/kaspar030/pyjam for info.
|
||||
|
||||
default.CFLAGS = "-O3 -DUHCP_SYSTEM_LINUX -DUHCP_SERVER"
|
||||
|
||||
Main("uhcpd")
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License v2. See the file LICENSE for more details.
|
||||
*/
|
||||
|
||||
#define UHCP_MCAST_ADDR "ff15::ABCD"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "net/uhcp.h"
|
||||
|
||||
char _prefix[16];
|
||||
unsigned _prefix_len;
|
||||
|
||||
int ipv6_addr_split(char *addr_str, char seperator, int _default)
|
||||
{
|
||||
char *sep = addr_str;
|
||||
while(*++sep) {
|
||||
if (*sep == seperator) {
|
||||
*sep++ = '\0';
|
||||
if (*sep) {
|
||||
_default = atoi(sep);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _default;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static unsigned ifindex;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: uhcpd <interface> <prefix/prefix_length>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ifindex = if_nametoindex(argv[1]);
|
||||
if (!ifindex) {
|
||||
fprintf(stderr, "error: invalid interface \"%s\"\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_prefix_len = ipv6_addr_split(argv[2], '/', 64);
|
||||
if ((!inet_pton(AF_INET6, argv[2], _prefix)) || (_prefix_len > 128)) {
|
||||
fprintf(stderr, "error: cannot parse prefix\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *addr_str = UHCP_MCAST_ADDR;
|
||||
|
||||
struct addrinfo hint;
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
hint.ai_family = AF_INET6;
|
||||
hint.ai_socktype = SOCK_DGRAM;
|
||||
hint.ai_protocol = IPPROTO_UDP;
|
||||
hint.ai_flags |= AI_NUMERICHOST;
|
||||
|
||||
struct addrinfo *mcast_addr;
|
||||
int res = getaddrinfo(addr_str, UHCP_PORT_STR,
|
||||
&hint, &mcast_addr);
|
||||
if (res != 0) {
|
||||
perror("getaddrinfo()");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int sock = socket(mcast_addr->ai_family, mcast_addr->ai_socktype,
|
||||
mcast_addr->ai_protocol);
|
||||
if (sock < 0) {
|
||||
perror("socket() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bind(sock, mcast_addr->ai_addr, mcast_addr->ai_addrlen) < 0) {
|
||||
perror("bind() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* join multicast group */
|
||||
struct ipv6_mreq mreq;
|
||||
memcpy(&mreq.ipv6mr_multiaddr,
|
||||
&((struct sockaddr_in6 *)mcast_addr->ai_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
|
||||
mreq.ipv6mr_interface = ifindex;
|
||||
|
||||
puts("Joining IPv6 multicast group...");
|
||||
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
|
||||
&mreq, sizeof(mreq)) < 0) {
|
||||
perror("setsockopt(IPV6_JOIN_GROUP) failed");
|
||||
exit(1);
|
||||
}
|
||||
freeaddrinfo(mcast_addr);
|
||||
|
||||
char buf[2048];
|
||||
struct sockaddr_in6 src_addr;
|
||||
unsigned n = sizeof(src_addr);;
|
||||
|
||||
puts("entering loop...");
|
||||
while(1) {
|
||||
int nbytes = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&src_addr, &n);
|
||||
if (nbytes < 0) {
|
||||
perror("recvfrom() failed");
|
||||
continue;
|
||||
}
|
||||
uhcp_handle_udp((uint8_t *)buf, nbytes, (uint8_t *)&src_addr.sin6_addr, ntohs(src_addr.sin6_port), ifindex);
|
||||
}
|
||||
|
||||
close(sock);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int udp_sendto(uint8_t *buf, size_t len, uint8_t *dst, uint16_t dst_port, uhcp_iface_t iface)
|
||||
{
|
||||
struct sockaddr_in6 dst_addr;
|
||||
memset(&dst_addr, '\0', sizeof(dst_addr));
|
||||
dst_addr.sin6_family = AF_INET6;
|
||||
memcpy(&dst_addr.sin6_addr, dst, 16);
|
||||
dst_addr.sin6_port = htons(dst_port);
|
||||
dst_addr.sin6_scope_id = iface;
|
||||
|
||||
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
perror("creating send socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t res;
|
||||
if ((res = sendto(fd, buf, len, 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr))) == -1) {
|
||||
perror("udp_sendto(): sendto()");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return res;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief slip parameters example, used by auto_init_gnrc_netif
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef SLIP_PARAMS_H
|
||||
#define SLIP_PARAMS_H
|
||||
|
||||
#include "net/gnrc/slip.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static gnrc_slip_params_t gnrc_slip_params[] = {
|
||||
{
|
||||
.uart = SLIP_UART,
|
||||
.baudrate = SLIP_BAUDRATE,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* SLIP_PARAMS_H */
|
||||
/** @} */
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_uhcp UHCP
|
||||
* @ingroup net
|
||||
* @brief Provides UHCP (micro host configuration protocol)
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief UHCP header
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*/
|
||||
|
||||
#ifndef UHCP_H
|
||||
#define UHCP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief UHCP magic number */
|
||||
#define UHCP_MAGIC (0x55484350) /* "UHCP" in hex */
|
||||
|
||||
/** @brief UHCP version of this header */
|
||||
#define UHCP_VER (0)
|
||||
|
||||
/** @brief UHCP port number */
|
||||
#define UHCP_PORT (12345U)
|
||||
|
||||
/** @brief UHCP port number (as string for e.g., getaddrinfo() service arg */
|
||||
#define UHCP_PORT_STR "12345"
|
||||
|
||||
/** @brief Enum containing possible UHCP packet types */
|
||||
typedef enum {
|
||||
UHCP_REQ, /**< packet is a request packet */
|
||||
UHCP_PUSH /**< packet is a push / answer packet */
|
||||
} uhcp_type_t;
|
||||
|
||||
/**
|
||||
* @brief UHCP packet header struct
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t uhcp_magic; /**< always contains UHCP in hex */
|
||||
uint8_t ver_type; /**< four bits version number, four bits
|
||||
packet type (see uchp_type_t) */
|
||||
} uhcp_hdr_t;
|
||||
|
||||
/**
|
||||
* @brief struct for request packets
|
||||
*
|
||||
* @extends uhcp_hdr_t
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uhcp_hdr_t hdr; /**< member holding parent type */
|
||||
uint8_t prefix_len; /**< contains the requested prefix length */
|
||||
} uhcp_req_t;
|
||||
|
||||
/**
|
||||
* @brief struct for push packets
|
||||
*
|
||||
* @extends uhcp_hdr_t
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
uhcp_hdr_t hdr; /**< member holding parent type */
|
||||
uint8_t prefix_len; /**< contains the prefix length of assigned
|
||||
prefix */
|
||||
uint8_t prefix[]; /**< contains the assigned prefix */
|
||||
} uhcp_push_t;
|
||||
|
||||
/** @brief typedef for interface handle */
|
||||
typedef unsigned uhcp_iface_t;
|
||||
|
||||
/**
|
||||
* @brief handle incoming UDP packet
|
||||
*
|
||||
* This function should be called by UHCP server/client network code for every
|
||||
* incoming UDP packet destined to UCHP_PORT.
|
||||
*
|
||||
* @param[in] buf buffer containing UDP packet
|
||||
* @param[in] len length of @c buf
|
||||
* @param[in] src ptr to IPv6 source address
|
||||
* @param[in] port source port of packet
|
||||
* @param[in] iface interface number of incoming packet
|
||||
*/
|
||||
void uhcp_handle_udp(uint8_t *buf, size_t len, uint8_t *src, uint16_t port, uhcp_iface_t iface);
|
||||
|
||||
/**
|
||||
* @brief handle incoming UHCP request packet
|
||||
*
|
||||
* This function will be called by uhcp_handle_udp() for incoming request
|
||||
* packet.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[in] req ptr to UHCP request header
|
||||
* @param[in] src ptr to IPv6 source address
|
||||
* @param[in] port source port of packet
|
||||
* @param[in] iface number of interface the packet came in
|
||||
*/
|
||||
void uhcp_handle_req(uhcp_req_t *req, uint8_t *src, uint16_t port, uhcp_iface_t iface);
|
||||
|
||||
/**
|
||||
* @brief handle incoming UHCP push packet
|
||||
*
|
||||
* This function will be called by uhcp_handle_udp() for incoming push
|
||||
* packet.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[in] req ptr to UHCP push header
|
||||
* @param[in] src ptr to IPv6 source address
|
||||
* @param[in] port source port of packet
|
||||
* @param[in] iface number of interface the packet came in
|
||||
*/
|
||||
void uhcp_handle_push(uhcp_push_t *req, uint8_t *src, uint16_t port, uhcp_iface_t iface);
|
||||
|
||||
/**
|
||||
* @brief handle incoming prefix (as parsed from push packet)
|
||||
*
|
||||
* Supposed to be implemented by UHCP client implementations.
|
||||
*
|
||||
* The function might be called with an already configured prefix. In that
|
||||
* case, the lifetime *MUST* be updated.
|
||||
*
|
||||
* If the function is called with a different prefix than before, the old
|
||||
* prefix *MUST* be considered obsolete.
|
||||
*
|
||||
* @param[in] prefix ptr to assigned prefix
|
||||
* @param[in] prefix_len length of assigned prefix
|
||||
* @param[in] lifetime lifetime of prefix
|
||||
* @param[in] src ptr to IPv6 source address
|
||||
* @param[in] iface number of interface the packet came in
|
||||
*/
|
||||
void uhcp_handle_prefix(uint8_t *prefix, uint8_t prefix_len, uint16_t lifetime, uint8_t *src, uhcp_iface_t iface);
|
||||
|
||||
/**
|
||||
* @brief function to set constant values in UHCP header
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param[out] hdr hdr to set up
|
||||
* @param[in] type type of packet (request or push)
|
||||
*/
|
||||
static inline void uhcp_hdr_set(uhcp_hdr_t *hdr, uhcp_type_t type)
|
||||
{
|
||||
hdr->uhcp_magic = htonl(UHCP_MAGIC);
|
||||
hdr->ver_type = (UHCP_VER << 4) | (type & 0xF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UDP send function used by UHCP client / server
|
||||
*
|
||||
* Supposed to be implemented by UHCP clients.
|
||||
*
|
||||
* @param[in] buf buffer to send
|
||||
* @param[in] len length of buf
|
||||
* @param[in] dst ptr to IPv6 destination address
|
||||
* @param[in] dst_port destination port
|
||||
* @param[in] dst_iface interface number of destination interface
|
||||
*/
|
||||
int udp_sendto(uint8_t *buf, size_t len, uint8_t *dst, uint16_t dst_port, uhcp_iface_t dst_iface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* UHCP_H */
|
||||
/** @} */
|
@ -0,0 +1,3 @@
|
||||
MODULE=uhcpc
|
||||
CFLAGS += -DUHCP_CLIENT
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/uhcp.h"
|
||||
|
||||
void uhcp_handle_udp(uint8_t *buf, size_t len, uint8_t *src, uint16_t port, uhcp_iface_t iface)
|
||||
{
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, src, addr_str, INET6_ADDRSTRLEN);
|
||||
printf("got packet from %s port %u\n", addr_str, (unsigned)port);
|
||||
|
||||
if (len < sizeof(uhcp_req_t)) {
|
||||
puts("error: packet too small.");
|
||||
return;
|
||||
}
|
||||
|
||||
uhcp_hdr_t *hdr = (uhcp_hdr_t *)buf;
|
||||
|
||||
if (! (ntohl(hdr->uhcp_magic) == UHCP_MAGIC)) {
|
||||
puts("error: wrong magic number.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned ver, type;
|
||||
ver = hdr->ver_type >> 4;
|
||||
type = hdr->ver_type & 0xF;
|
||||
|
||||
if (ver != UHCP_VER) {
|
||||
puts("error: wrong protocol version.");
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
#ifdef UHCP_SERVER
|
||||
case UHCP_REQ:
|
||||
if (len < sizeof(uhcp_req_t)) {
|
||||
puts("error: request too small\n");
|
||||
}
|
||||
else {
|
||||
uhcp_handle_req((uhcp_req_t*)hdr, src, port, iface);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef UHCP_CLIENT
|
||||
case UHCP_PUSH:
|
||||
{
|
||||
uhcp_push_t *push = (uhcp_push_t*)hdr;
|
||||
if ((len < sizeof(uhcp_push_t))
|
||||
|| (len < (sizeof(uhcp_push_t) + (push->prefix_len >> 3)))
|
||||
) {
|
||||
puts("error: request too small\n");
|
||||
}
|
||||
else {
|
||||
uhcp_handle_push(push, src, port, iface);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
puts("error: unexpected type\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UHCP_SERVER
|
||||
extern char _prefix[16];
|
||||
extern unsigned _prefix_len;
|
||||
void uhcp_handle_req(uhcp_req_t *req, uint8_t *src, uint16_t port, uhcp_iface_t iface)
|
||||
{
|
||||
size_t prefix_bytes = (_prefix_len + 7)>>3;
|
||||
uint8_t packet[sizeof(uhcp_push_t) + prefix_bytes];
|
||||
|
||||
uhcp_push_t *reply = (uhcp_push_t *)packet;
|
||||
uhcp_hdr_set(&reply->hdr, UHCP_PUSH);
|
||||
|
||||
reply->prefix_len = _prefix_len;
|
||||
memcpy(reply->prefix, _prefix, prefix_bytes);
|
||||
|
||||
int res = udp_sendto(packet, sizeof(packet), src, port, iface);
|
||||
if (res == -1) {
|
||||
printf("uhcp_handle_req(): udp_sendto() res=%i\n", res);
|
||||
}
|
||||
}
|
||||
#endif /* UHCP_SERVER */
|
||||
|
||||
#ifdef UHCP_CLIENT
|
||||
void uhcp_handle_push(uhcp_push_t *req, uint8_t *src, uint16_t port, uhcp_iface_t iface)
|
||||
{
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
char prefix_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, src, addr_str, INET6_ADDRSTRLEN);
|
||||
uint8_t prefix[16];
|
||||
size_t prefix_bytes = (req->prefix_len + 7)>>3;
|
||||
memset(prefix + 16 - prefix_bytes, '\0', 16 - prefix_bytes);
|
||||
memcpy(prefix, req->prefix, prefix_bytes);
|
||||
|
||||
inet_ntop(AF_INET6, prefix, prefix_str, INET6_ADDRSTRLEN);
|
||||
|
||||
printf("uhcp: push from %s:%u prefix=%s/%u\n", addr_str, (unsigned)port, prefix_str, req->prefix_len);
|
||||
uhcp_handle_prefix(prefix, req->prefix_len, 0xFFFF, src, iface);
|
||||
}
|
||||
#endif
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#include "net/uhcp.h"
|
||||
|
||||
#include "net/af.h"
|
||||
#include "net/conn/udp.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
static void _timeout(void *arg) {
|
||||
kernel_pid_t pid = *(kernel_pid_t*)arg;
|
||||
msg_t msg;
|
||||
msg_send_int(&msg, pid);
|
||||
msg_send_int(&msg, pid);
|
||||
msg_send_int(&msg, pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request prefix from uhcp server
|
||||
*
|
||||
* Never returns.
|
||||
* Calls @c uhcp_handle_prefix() when a prefix or prefix change is received.
|
||||
*
|
||||
* @param[in] iface interface to request prefix on
|
||||
*/
|
||||
void uhcp_client(uhcp_iface_t iface)
|
||||
{
|
||||
ipv6_addr_t target;
|
||||
ipv6_addr_from_str(&target, "ff15::abcd");
|
||||
|
||||
/* prepare UHCP header */
|
||||
uhcp_req_t req;
|
||||
uhcp_hdr_set(&req.hdr, UHCP_REQ);
|
||||
req.prefix_len = 64;
|
||||
|
||||
/* create listening socket */
|
||||
ipv6_addr_t zero = {{0}};
|
||||
conn_udp_t conn;
|
||||
int res = conn_udp_create(&conn, &zero, 16, AF_INET6, UHCP_PORT);
|
||||
|
||||
uint8_t srv_addr[16];
|
||||
size_t srv_addr_len;
|
||||
uint16_t srv_port;
|
||||
uint8_t buf[sizeof(uhcp_push_t) + 16];
|
||||
|
||||
kernel_pid_t pid = thread_getpid();
|
||||
xtimer_t timeout;
|
||||
timeout.callback = _timeout;
|
||||
timeout.arg = &pid;
|
||||
|
||||
while(1) {
|
||||
xtimer_set(&timeout, 10U*SEC_IN_USEC);
|
||||
puts("uhcp_client(): sending REQ...");
|
||||
conn_udp_sendto(&req, sizeof(uhcp_req_t), NULL, 0, &target, 16, AF_INET6 , 12345, 12345);
|
||||
res = conn_udp_recvfrom(&conn, buf, sizeof(buf), srv_addr, &srv_addr_len, &srv_port);
|
||||
if (res > 0) {
|
||||
xtimer_remove(&timeout);
|
||||
uhcp_handle_udp(buf, res, srv_addr, srv_port, iface);
|
||||
xtimer_sleep(60);
|
||||
}
|
||||
else {
|
||||
msg_t msg;
|
||||
msg_try_receive(&msg);
|
||||
msg_try_receive(&msg);
|
||||
msg_try_receive(&msg);
|
||||
puts("uhcp_client(): timeout waiting for reply");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_uhcpc
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#include "net/fib.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/ipv6/nc.h"
|
||||
#include "net/gnrc/ipv6/netif.h"
|
||||
#include "net/gnrc/netapi.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/netdev2.h"
|
||||
#include "net/netopt.h"
|
||||
|
||||
#include "net/uhcp.h"
|
||||
#include "log.h"
|
||||
#include "fmt.h"
|
||||
|
||||
static kernel_pid_t gnrc_border_interface;
|
||||
static kernel_pid_t gnrc_wireless_interface;
|
||||
|
||||
static void set_interface_roles(void)
|
||||
{
|
||||
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
|
||||
size_t numof = gnrc_netif_get(ifs);
|
||||
|
||||
for (size_t i = 0; i < numof && i < GNRC_NETIF_NUMOF; i++) {
|
||||
kernel_pid_t dev = ifs[i];
|
||||
int is_wired = gnrc_netapi_get(dev, NETOPT_IS_WIRED, 0, NULL, 0);
|
||||
if ((!gnrc_border_interface) && (is_wired == 1)) {
|
||||
ipv6_addr_t addr, defroute;
|
||||
gnrc_border_interface = dev;
|
||||
|
||||
ipv6_addr_from_str(&addr, "fe80::2");
|
||||
gnrc_ipv6_netif_add_addr(dev, &addr, 64,
|
||||
GNRC_IPV6_NETIF_ADDR_FLAGS_UNICAST);
|
||||
|
||||
ipv6_addr_from_str(&defroute, "::");
|
||||
ipv6_addr_from_str(&addr, "fe80::1");
|
||||
fib_add_entry(&gnrc_ipv6_fib_table, dev, defroute.u8, 16,
|
||||
0x00, addr.u8, 16, 0,
|
||||
(uint32_t)FIB_LIFETIME_NO_EXPIRE);
|
||||
}
|
||||
else if ((!gnrc_wireless_interface) && (is_wired != 1)) {
|
||||
gnrc_wireless_interface = dev;
|
||||
}
|
||||
|
||||
if (gnrc_border_interface && gnrc_wireless_interface) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("gnrc_uhcpc: Using %u as border interface and %u as wireless interface.\n", gnrc_border_interface, gnrc_wireless_interface);
|
||||
}
|
||||
|
||||
static ipv6_addr_t _prefix;
|
||||
|
||||
void uhcp_handle_prefix(uint8_t *prefix, uint8_t prefix_len, uint16_t lifetime, uint8_t *src, uhcp_iface_t iface)
|
||||
{
|
||||
(void)prefix_len;
|
||||
(void)lifetime;
|
||||
(void)src;
|
||||
|
||||
eui64_t iid;
|
||||
if (!gnrc_wireless_interface) {
|
||||
LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): received prefix, but don't know any wireless interface\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((kernel_pid_t)iface != gnrc_border_interface) {
|
||||
LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): received prefix from unexpected interface\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gnrc_netapi_get(gnrc_wireless_interface, NETOPT_IPV6_IID, 0, &iid,
|
||||
sizeof(eui64_t)) >= 0) {
|
||||
ipv6_addr_set_aiid((ipv6_addr_t*)prefix, iid.uint8);
|
||||
}
|
||||
else {
|
||||
LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): cannot get IID of wireless interface\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ipv6_addr_equal(&_prefix, (ipv6_addr_t*)prefix)) {
|
||||
LOG_WARNING("gnrc_uhcpc: uhcp_handle_prefix(): got same prefix again\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gnrc_ipv6_netif_add_addr(gnrc_wireless_interface, (ipv6_addr_t*)prefix, 64,
|
||||
GNRC_IPV6_NETIF_ADDR_FLAGS_UNICAST |
|
||||
GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_AUTO);
|
||||
|
||||
gnrc_ipv6_netif_remove_addr(gnrc_wireless_interface, &_prefix);
|
||||
print_str("gnrc_uhcpc: uhcp_handle_prefix(): configured new prefix ");
|
||||
ipv6_addr_print((ipv6_addr_t*)prefix);
|
||||
puts("/64");
|
||||
|
||||
if (!ipv6_addr_is_unspecified(&_prefix)) {
|
||||
gnrc_ipv6_netif_remove_addr(gnrc_wireless_interface, &_prefix);
|
||||
print_str("gnrc_uhcpc: uhcp_handle_prefix(): removed old prefix ");
|
||||
ipv6_addr_print(&_prefix);
|
||||
puts("/64");
|
||||
}
|
||||
|
||||
memcpy(&_prefix, prefix, 16);
|
||||
}
|
||||
|
||||
extern void uhcp_client(uhcp_iface_t iface);
|
||||
|
||||
static char _uhcp_client_stack[THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||
static msg_t _uhcp_msg_queue[4];
|
||||
|
||||
static void* uhcp_client_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
msg_init_queue(_uhcp_msg_queue, sizeof(_uhcp_msg_queue)/sizeof(msg_t));
|
||||
uhcp_client(gnrc_border_interface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void auto_init_gnrc_uhcpc(void)
|
||||
{
|
||||
set_interface_roles();
|
||||
|
||||
/* only start client if more than one interface is given */
|
||||
if (! (gnrc_border_interface && gnrc_wireless_interface)) {
|
||||
LOG_WARNING("gnrc_uhcpc: only one interface found, skipping setup.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* initiate uhcp client */
|
||||
thread_create(_uhcp_client_stack, sizeof(_uhcp_client_stack),
|
||||
THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST,
|
||||
uhcp_client_thread, NULL, "uhcp");
|
||||
}
|
Loading…
Reference in New Issue