blob: b57932b2206f939d1bbb9ea5770c290f6456c64a [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "netz.h"
#include <net/net_core.h>
#include <net/net_socket.h>
#include <string.h>
#include <errno.h>
void netz_host(struct netz_ctx_t *ctx, struct net_addr *host)
{
return netz_host_ipv4(ctx, host->in_addr.in4_u.u4_addr8[0],
host->in_addr.in4_u.u4_addr8[1],
host->in_addr.in4_u.u4_addr8[2],
host->in_addr.in4_u.u4_addr8[3]);
}
void netz_host_ipv4(struct netz_ctx_t *ctx, uint8_t a1, uint8_t a2,
uint8_t a3, uint8_t a4)
{
uip_ipaddr_t host_addr;
uip_ipaddr(&host_addr, a1, a2, a3, a4);
uip_sethostaddr(&host_addr);
ctx->host.in_addr.in4_u.u4_addr8[0] = a1;
ctx->host.in_addr.in4_u.u4_addr8[1] = a2;
ctx->host.in_addr.in4_u.u4_addr8[2] = a3;
ctx->host.in_addr.in4_u.u4_addr8[3] = a4;
ctx->host.family = AF_INET;
}
void netz_netmask(struct netz_ctx_t *ctx, struct net_addr *netmask)
{
return netz_netmask_ipv4(ctx, netmask->in_addr.in4_u.u4_addr8[0],
netmask->in_addr.in4_u.u4_addr8[1],
netmask->in_addr.in4_u.u4_addr8[2],
netmask->in_addr.in4_u.u4_addr8[3]);
}
void netz_netmask_ipv4(struct netz_ctx_t *ctx, uint8_t n1, uint8_t n2,
uint8_t n3, uint8_t n4)
{
ARG_UNUSED(ctx);
uip_ipaddr_t netmask;
uip_ipaddr(&netmask, n1, n2, n3, n4);
uip_setnetmask(&netmask);
}
void netz_remote(struct netz_ctx_t *ctx, struct net_addr *remote, int port)
{
return netz_remote_ipv4(ctx, remote->in_addr.in4_u.u4_addr8[0],
remote->in_addr.in4_u.u4_addr8[1],
remote->in_addr.in4_u.u4_addr8[2],
remote->in_addr.in4_u.u4_addr8[3], port);
}
void netz_remote_ipv4(struct netz_ctx_t *ctx, uint8_t a1, uint8_t a2,
uint8_t a3, uint8_t a4, int port)
{
ctx->remote.in_addr.in4_u.u4_addr8[0] = a1;
ctx->remote.in_addr.in4_u.u4_addr8[1] = a2;
ctx->remote.in_addr.in4_u.u4_addr8[2] = a3;
ctx->remote.in_addr.in4_u.u4_addr8[3] = a4;
ctx->remote.family = AF_INET;
ctx->remote_port = port;
}
static int netz_prepare(struct netz_ctx_t *ctx, enum ip_protocol proto)
{
#ifdef CONFIG_NETWORKING_WITH_TCP
struct app_buf_t buf = APP_BUF_INIT(NULL, 0, 0);
int rc;
#endif
ctx->connected = 0;
ctx->proto = proto;
ctx->net_ctx = net_context_get(ctx->proto,
&ctx->remote, ctx->remote_port,
&ctx->host, 0);
if (ctx->net_ctx == NULL) {
return -EINVAL;
}
#ifdef CONFIG_NETWORKING_WITH_TCP
/* workaround to activate the IP stack */
rc = netz_tx(ctx, &buf);
if (rc != 0) {
return rc;
}
#endif
ctx->connected = 1;
return 0;
}
int netz_tcp(struct netz_ctx_t *ctx)
{
return netz_prepare(ctx, IPPROTO_TCP);
}
int netz_udp(struct netz_ctx_t *ctx)
{
return netz_prepare(ctx, IPPROTO_UDP);
}
static void netz_sleep(int sleep_ticks)
{
struct nano_timer timer;
nano_timer_init(&timer, NULL);
nano_fiber_timer_start(&timer, sleep_ticks);
nano_fiber_timer_test(&timer, TICKS_UNLIMITED);
}
static int tcp_tx(struct net_context *ctx, uint8_t *buf, size_t size,
int tx_retry_timeout)
{
struct net_buf *nbuf;
uint8_t *ptr;
int rc;
nbuf = ip_buf_get_tx(ctx);
if (nbuf == NULL) {
return -EINVAL;
}
ptr = net_buf_add(nbuf, size);
memcpy(ptr, buf, size);
ip_buf_appdatalen(nbuf) = size;
do {
rc = net_send(nbuf);
if (rc >= 0) {
ip_buf_unref(nbuf);
return 0;
}
switch (rc) {
case -EINPROGRESS:
netz_sleep(tx_retry_timeout);
break;
case -EAGAIN:
case -ECONNRESET:
netz_sleep(tx_retry_timeout);
break;
default:
ip_buf_unref(nbuf);
return -EIO;
}
} while (1);
return 0;
}
static int tcp_rx(struct net_context *ctx, uint8_t *buf, size_t *read_bytes,
size_t size, int rx_timeout)
{
struct net_buf *nbuf;
int rc;
nbuf = net_receive(ctx, rx_timeout);
if (nbuf == NULL) {
return -EIO;
}
*read_bytes = ip_buf_appdatalen(nbuf);
if (*read_bytes > size) {
*read_bytes = size;
rc = -ENOMEM;
} else {
rc = 0;
}
memcpy(buf, ip_buf_appdata(nbuf), *read_bytes);
ip_buf_unref(nbuf);
return rc;
}
int netz_tx(struct netz_ctx_t *ctx, struct app_buf_t *buf)
{
int rc;
/* We don't evaluate if we are connected. */
rc = tcp_tx(ctx->net_ctx, buf->buf, buf->length,
ctx->tx_retry_timeout);
return rc;
}
int netz_rx(struct netz_ctx_t *ctx, struct app_buf_t *buf)
{
int rc;
if (ctx->connected != 1) {
return -ENOTCONN;
}
rc = tcp_rx(ctx->net_ctx, buf->buf, &buf->length, buf->size,
ctx->rx_timeout);
return rc;
}