Skip to content

Commit

Permalink
sys: net: add UHCP protocol code and gnrc client implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
kaspar030 committed Apr 11, 2016
1 parent 987f719 commit 4fb07a8
Show file tree
Hide file tree
Showing 9 changed files with 522 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ ifneq (,$(filter netdev2_ieee802154,$(USEMODULE)))
USEMODULE += ieee802154
endif

ifneq (,$(filter gnrc_uhcpc,$(USEMODULE)))
USEMODULE += uhcpc
USEMODULE += gnrc_conn_udp
USEMODULE += fmt
endif

ifneq (,$(filter gnrc_%,$(filter-out gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pktbuf,$(USEMODULE))))
USEMODULE += gnrc
endif
Expand Down
8 changes: 8 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ ifneq (,$(filter hamming256,$(USEMODULE)))
DIRS += ecc/hamming256
endif

ifneq (,$(filter uhcpc,$(USEMODULE)))
DIRS += net/application_layer/uhcp
endif

ifneq (,$(filter gnrc_uhcpc,$(USEMODULE)))
DIRS += net/gnrc/application_layer/uhcpc
endif

ifneq (,$(filter netopt,$(USEMODULE)))
DIRS += net/crosslayer/netopt
endif
Expand Down
5 changes: 5 additions & 0 deletions sys/auto_init/auto_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ void auto_init(void)
gnrc_ipv6_netif_init_by_dev();
#endif

#ifdef MODULE_GNRC_UHCPC
extern void auto_init_gnrc_uhcpc(void);
auto_init_gnrc_uhcpc();
#endif

/* initialize sensors and actuators */
#ifdef MODULE_AUTO_INIT_SAUL
DEBUG("auto_init SAUL\n");
Expand Down
179 changes: 179 additions & 0 deletions sys/include/net/uhcp.h
Original file line number Diff line number Diff line change
@@ -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 */
/** @} */
3 changes: 3 additions & 0 deletions sys/net/application_layer/uhcp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE=uhcpc
CFLAGS += -DUHCP_CLIENT
include $(RIOTBASE)/Makefile.base
111 changes: 111 additions & 0 deletions sys/net/application_layer/uhcp/uhcp.c
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 4fb07a8

Please sign in to comment.