mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-27 07:21:18 +01:00
gnrc_tcp: handle link local IPv6 addresses correctly
This commit is contained in:
parent
6e484f7aed
commit
686aabaa0a
@ -52,36 +52,37 @@ int gnrc_tcp_init(void);
|
||||
*/
|
||||
void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb);
|
||||
|
||||
/**
|
||||
* @brief Opens a connection actively.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre @p tcb must not be NULL
|
||||
* @pre @p target_addr must not be NULL.
|
||||
* @pre @p target_port must not be 0.
|
||||
*
|
||||
* @note Blocks until a connection has been established or an error occured.
|
||||
*
|
||||
* @param[in,out] tcb TCB holding the connection information.
|
||||
* @param[in] address_family Address family of @p target_addr.
|
||||
* @param[in] target_addr Pointer to target address.
|
||||
* @param[in] target_port Target port number.
|
||||
* @param[in] local_port If zero or PORT_UNSPEC, the connections
|
||||
* source port is randomly chosen. If local_port is non-zero
|
||||
* the local_port is used as source port.
|
||||
*
|
||||
* @returns Zero on success.
|
||||
* -EAFNOSUPPORT if @p address_family is not supported.
|
||||
* -EINVAL if @p address_family is not the same the address_family use by the TCB.
|
||||
* -EISCONN if TCB is already in use.
|
||||
* -ENOMEM if the receive buffer for the TCB could not be allocated.
|
||||
* -EADDRINUSE if @p local_port is already used by another connection.
|
||||
* -ETIMEDOUT if the connection could not be opened.
|
||||
* -ECONNREFUSED if the connection was resetted by the peer.
|
||||
*/
|
||||
int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *target_addr, const uint16_t target_port,
|
||||
const uint16_t local_port);
|
||||
/**
|
||||
* @brief Opens a connection actively.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre @p tcb must not be NULL
|
||||
* @pre @p target_addr must not be NULL.
|
||||
* @pre @p target_port must not be 0.
|
||||
*
|
||||
* @note Blocks until a connection has been established or an error occured.
|
||||
*
|
||||
* @param[in,out] tcb TCB holding the connection information.
|
||||
* @param[in] address_family Address family of @p target_addr.
|
||||
* @param[in] target_addr Pointer to target address.
|
||||
* @param[in] target_port Target port number.
|
||||
* @param[in] local_port If zero or PORT_UNSPEC, the connections
|
||||
* source port is randomly chosen. If local_port is non-zero
|
||||
* the local_port is used as source port.
|
||||
*
|
||||
* @returns Zero on success.
|
||||
* -EAFNOSUPPORT if @p address_family is not supported.
|
||||
* -EINVAL if @p address_family is not the same the address_family use by the TCB.
|
||||
* or @p target_addr is invalid.
|
||||
* -EISCONN if TCB is already in use.
|
||||
* -ENOMEM if the receive buffer for the TCB could not be allocated.
|
||||
* -EADDRINUSE if @p local_port is already used by another connection.
|
||||
* -ETIMEDOUT if the connection could not be opened.
|
||||
* -ECONNREFUSED if the connection was resetted by the peer.
|
||||
*/
|
||||
int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, uint8_t address_family,
|
||||
char *target_addr, uint16_t target_port,
|
||||
uint16_t local_port);
|
||||
|
||||
/**
|
||||
* @brief Opens a connection passively, by waiting for an incomming request.
|
||||
@ -105,12 +106,13 @@ int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
* @returns Zero on success.
|
||||
* -EAFNOSUPPORT if local_addr != NULL and @p address_family is not supported.
|
||||
* -EINVAL if @p address_family is not the same the address_family used in TCB.
|
||||
* or @p target_addr is invalid.
|
||||
* -EISCONN if TCB is already in use.
|
||||
* -ENOMEM if the receive buffer for the TCB could not be allocated.
|
||||
* Hint: Increase "GNRC_TCP_RCV_BUFFERS".
|
||||
*/
|
||||
int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *local_addr, const uint16_t local_port);
|
||||
int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, uint8_t address_family,
|
||||
const char *local_addr, uint16_t local_port);
|
||||
|
||||
/**
|
||||
* @brief Transmit data to connected peer.
|
||||
|
||||
@ -53,6 +53,7 @@ typedef struct _transmission_control_block {
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
uint8_t local_addr[sizeof(ipv6_addr_t)]; /**< Local IP address */
|
||||
uint8_t peer_addr[sizeof(ipv6_addr_t)]; /**< Peer IP address */
|
||||
int8_t ll_iface; /**< Link layer interface id to use. */
|
||||
#endif
|
||||
uint16_t local_port; /**< Local connections port number */
|
||||
uint16_t peer_port; /**< Peer connections port number */
|
||||
|
||||
@ -112,8 +112,8 @@ static void _setup_timeout(xtimer_t *timer, const uint32_t duration, const xtime
|
||||
* -ETIMEDOUT if the connection opening timed out.
|
||||
* -ECONNREFUSED if the connection was resetted by the peer.
|
||||
*/
|
||||
static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const uint8_t *target_addr, uint16_t target_port,
|
||||
const uint8_t *local_addr, uint16_t local_port, uint8_t passive)
|
||||
static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, char *target_addr, uint16_t target_port,
|
||||
const char *local_addr, uint16_t local_port, uint8_t passive)
|
||||
{
|
||||
msg_t msg;
|
||||
xtimer_t connection_timeout;
|
||||
@ -146,7 +146,10 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const uint8_t *target_addr, uint1
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
/* If local address is specified: Copy it into TCB */
|
||||
else if (tcb->address_family == AF_INET6) {
|
||||
memcpy(tcb->local_addr, local_addr, sizeof(ipv6_addr_t));
|
||||
if (ipv6_addr_from_str((ipv6_addr_t *) tcb->local_addr, local_addr) == NULL) {
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : Invalid peer addr\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Set port number to listen on */
|
||||
@ -154,10 +157,21 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const uint8_t *target_addr, uint1
|
||||
}
|
||||
/* Setup active connection */
|
||||
else {
|
||||
/* Copy target address and port number into TCB */
|
||||
/* Parse target address and port number into TCB */
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
if ((target_addr != NULL) && (tcb->address_family == AF_INET6)) {
|
||||
memcpy(tcb->peer_addr, target_addr, sizeof(ipv6_addr_t));
|
||||
|
||||
/* Extract interface (optional) specifier from target address */
|
||||
int ll_iface = ipv6_addr_split_iface(target_addr);
|
||||
if (ipv6_addr_from_str((ipv6_addr_t *) tcb->peer_addr, target_addr) == NULL) {
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : Invalid peer addr\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* In case the given address is link-local: Memorize the interface Id if existing. */
|
||||
if ((ll_iface > 0) && ipv6_addr_is_link_local((ipv6_addr_t *) tcb->peer_addr)) {
|
||||
tcb->ll_iface = ll_iface;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Assign port numbers, verfication happens in fsm */
|
||||
@ -172,10 +186,10 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const uint8_t *target_addr, uint1
|
||||
/* Call FSM with event: CALL_OPEN */
|
||||
ret = _fsm(tcb, FSM_EVENT_CALL_OPEN, NULL, NULL, 0);
|
||||
if (ret == -ENOMEM) {
|
||||
DEBUG("gnrc_tcp.c : gnrc_tcp_connect() : Out of receive buffers.\n");
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : Out of receive buffers.\n");
|
||||
}
|
||||
else if(ret == -EADDRINUSE) {
|
||||
DEBUG("gnrc_tcp.c : gnrc_tcp_connect() : local_port is already in use.\n");
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : local_port is already in use.\n");
|
||||
}
|
||||
|
||||
/* Wait until a connection was established or closed */
|
||||
@ -245,9 +259,9 @@ void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb)
|
||||
mutex_init(&(tcb->function_lock));
|
||||
}
|
||||
|
||||
int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *target_addr, const uint16_t target_port,
|
||||
const uint16_t local_port)
|
||||
int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, uint8_t address_family,
|
||||
char *target_addr, uint16_t target_port,
|
||||
uint16_t local_port)
|
||||
{
|
||||
assert(tcb != NULL);
|
||||
assert(target_addr != NULL);
|
||||
@ -270,8 +284,8 @@ int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
return _gnrc_tcp_open(tcb, target_addr, target_port, NULL, local_port, 0);
|
||||
}
|
||||
|
||||
int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *local_addr, const uint16_t local_port)
|
||||
int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, uint8_t address_family,
|
||||
const char *local_addr, uint16_t local_port)
|
||||
{
|
||||
assert(tcb != NULL);
|
||||
assert(local_port != PORT_UNSPEC);
|
||||
|
||||
@ -46,19 +46,35 @@ static msg_t _eventloop_msg_queue[TCP_EVENTLOOP_MSG_QUEUE_SIZE];
|
||||
*/
|
||||
static int _send(gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
assert(pkt != NULL);
|
||||
|
||||
/* NOTE: In sending direction: pkt = nw, nw->next = tcp, tcp->next = payload */
|
||||
gnrc_pktsnip_t *tcp;
|
||||
gnrc_pktsnip_t *tcp = NULL;
|
||||
gnrc_pktsnip_t *nw = NULL;
|
||||
|
||||
/* Search for TCP header */
|
||||
LL_SEARCH_SCALAR(pkt, tcp, type, GNRC_NETTYPE_TCP);
|
||||
/* cppcheck-suppress knownConditionTrueFalse */
|
||||
if (tcp == NULL) {
|
||||
DEBUG("gnrc_tcp_eventloop : _send() : tcp header missing.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* Search for network layer */
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
/* Get IPv6 header, discard packet if doesn't contain an ipv6 header */
|
||||
LL_SEARCH_SCALAR(pkt, nw, type, GNRC_NETTYPE_IPV6);
|
||||
if (nw == NULL) {
|
||||
DEBUG("gnrc_tcp_eventloop.c : _send() : pkt contains no ipv6 layer header\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -EBADMSG;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Dispatch packet to network layer */
|
||||
if (!gnrc_netapi_dispatch_send(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
|
||||
assert(nw != NULL);
|
||||
if (!gnrc_netapi_dispatch_send(nw->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
|
||||
DEBUG("gnrc_tcp_eventloop : _send() : network layer not found\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
|
||||
@ -474,6 +474,19 @@ static int _fsm_rcvd_pkt(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *in_pkt)
|
||||
if (snp->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) {
|
||||
memcpy(tcb->local_addr, &((ipv6_hdr_t *)ip)->dst, sizeof(ipv6_addr_t));
|
||||
memcpy(tcb->peer_addr, &((ipv6_hdr_t *)ip)->src, sizeof(ipv6_addr_t));
|
||||
|
||||
/* In case peer_addr is link local: Store interface Id in tcb */
|
||||
if (ipv6_addr_is_link_local((ipv6_addr_t *) tcb->peer_addr)) {
|
||||
gnrc_pktsnip_t *tmp = NULL;
|
||||
LL_SEARCH_SCALAR(in_pkt, tmp, type, GNRC_NETTYPE_NETIF);
|
||||
/* cppcheck-suppress knownConditionTrueFalse */
|
||||
if (tmp == NULL) {
|
||||
DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() :\
|
||||
incomming packet had no netif header\n");
|
||||
return 0;
|
||||
}
|
||||
tcb->ll_iface = ((gnrc_netif_hdr_t *)tmp->data)->if_pid;
|
||||
}
|
||||
}
|
||||
#else
|
||||
DEBUG("gnrc_tcp_fsm.c : _fsm_rcvd_pkt() : Received address was not stored\n");
|
||||
|
||||
@ -109,6 +109,30 @@ int _pkt_build_reset_from_pkt(gnrc_pktsnip_t **out_pkt, gnrc_pktsnip_t *in_pkt)
|
||||
return -ENOMEM;
|
||||
}
|
||||
*out_pkt = ip6_snp;
|
||||
|
||||
/* Add netif header in case the receiver addr sent from a link local address */
|
||||
if (ipv6_addr_is_link_local(&ip6_hdr->src)) {
|
||||
|
||||
/* Search for netif header in received packet */
|
||||
gnrc_pktsnip_t *net_snp;
|
||||
LL_SEARCH_SCALAR(in_pkt, net_snp, type, GNRC_NETTYPE_NETIF);
|
||||
gnrc_netif_hdr_t *net_hdr = (gnrc_netif_hdr_t *)net_snp->data;
|
||||
|
||||
/* Allocate new header and set interface id */
|
||||
net_snp = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
if (net_snp == NULL) {
|
||||
DEBUG("gnrc_tcp_pkt.c : _pkt_build_reset_from_pkt() :\
|
||||
Can't alloc buffer for netif Header.\n");
|
||||
gnrc_pktbuf_release(ip6_snp);
|
||||
*(out_pkt) = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
else {
|
||||
((gnrc_netif_hdr_t *)net_snp->data)->if_pid = net_hdr->if_pid;
|
||||
LL_PREPEND(ip6_snp, net_snp);
|
||||
*(out_pkt) = net_snp;
|
||||
}
|
||||
}
|
||||
#else
|
||||
DEBUG("gnrc_tcp_pkt.c : _pkt_build_reset_from_pkt() : Network Layer Module Missing\n");
|
||||
#endif
|
||||
@ -191,6 +215,22 @@ int _pkt_build(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t **out_pkt, uint16_t *seq_con,
|
||||
else {
|
||||
*(out_pkt) = ip6_snp;
|
||||
}
|
||||
|
||||
/* Prepend network interface header if an interface id was specified */
|
||||
if (tcb->ll_iface > 0) {
|
||||
gnrc_pktsnip_t *net_snp = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
if (net_snp == NULL) {
|
||||
DEBUG("gnrc_tcp_pkt.c : _pkt_build() : Can't allocate buffer for netif header.\n");
|
||||
gnrc_pktbuf_release(ip6_snp);
|
||||
*(out_pkt) = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
else {
|
||||
((gnrc_netif_hdr_t *)net_snp->data)->if_pid = (kernel_pid_t)tcb->ll_iface;
|
||||
LL_PREPEND(ip6_snp, net_snp);
|
||||
*(out_pkt) = net_snp;
|
||||
}
|
||||
}
|
||||
#else
|
||||
DEBUG("gnrc_tcp_pkt.c : _pkt_build_reset_from_pkt() : Network Layer Module Missing\n");
|
||||
#endif
|
||||
@ -441,6 +481,8 @@ uint16_t _pkt_calc_csum(const gnrc_pktsnip_t *hdr, const gnrc_pktsnip_t *pseudo_
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Suppress compiler warnings */
|
||||
(void) len;
|
||||
return 0;
|
||||
}
|
||||
return ~csum;
|
||||
|
||||
@ -4,7 +4,7 @@ include ../Makefile.tests_common
|
||||
BOARD ?= native
|
||||
PORT ?= tap1
|
||||
|
||||
TCP_TARGET_ADDR ?= fe80::affe
|
||||
TCP_TARGET_ADDR ?= fe80::affe%5
|
||||
TCP_TARGET_PORT ?= 80
|
||||
TCP_TEST_CYCLES ?= 3
|
||||
|
||||
@ -21,6 +21,7 @@ BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-duemilanove arduino-mega2560 \
|
||||
CFLAGS += -DTARGET_ADDR=\"$(TCP_TARGET_ADDR)\"
|
||||
CFLAGS += -DTARGET_PORT=$(TCP_TARGET_PORT)
|
||||
CFLAGS += -DCYCLES=$(TCP_TEST_CYCLES)
|
||||
CFLAGS += -DGNRC_NETIF_IPV6_GROUPS_NUMOF=3
|
||||
|
||||
# Modules to include
|
||||
USEMODULE += gnrc_netdev_default
|
||||
|
||||
@ -65,21 +65,19 @@ void *cli_thread(void *arg)
|
||||
/* Transmission control block */
|
||||
gnrc_tcp_tcb_t tcb;
|
||||
|
||||
/* Target peer address information */
|
||||
ipv6_addr_t target_addr;
|
||||
uint16_t target_port;
|
||||
|
||||
/* Initialize target information */
|
||||
ipv6_addr_from_str(&target_addr, TARGET_ADDR);
|
||||
target_port = TARGET_PORT;
|
||||
|
||||
printf("Client running: TID=%d\n", tid);
|
||||
while (cycles < CYCLES) {
|
||||
|
||||
/* Copy peer address information. NOTE: This test uses link-local addresses
|
||||
* -> The Device identifier is removed from target_addr in each iteration! */
|
||||
char target_addr[] = TARGET_ADDR;
|
||||
uint16_t target_port = TARGET_PORT;
|
||||
|
||||
/* Initialize TCB */
|
||||
gnrc_tcp_tcb_init(&tcb);
|
||||
|
||||
/* Connect to peer */
|
||||
int ret = gnrc_tcp_open_active(&tcb, AF_INET6, (uint8_t *) &target_addr, target_port, 0);
|
||||
int ret = gnrc_tcp_open_active(&tcb, AF_INET6, target_addr, target_port, 0);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
DEBUG("TID=%d : gnrc_tcp_open_active() : 0 : ok\n", tid);
|
||||
|
||||
@ -24,6 +24,7 @@ RIOTBASE ?= $(CURDIR)/../..
|
||||
CFLAGS += -DLOCAL_ADDR=\"$(TCP_LOCAL_ADDR)\"
|
||||
CFLAGS += -DLOCAL_PORT=$(TCP_LOCAL_PORT)
|
||||
CFLAGS += -DCYCLES=$(TCP_TEST_CYCLES)
|
||||
CFLAGS += -DGNRC_NETIF_IPV6_GROUPS_NUMOF=3
|
||||
|
||||
# Modules to include
|
||||
USEMODULE += gnrc_netdev_default
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user