| /* |
| * 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 <string.h> |
| #include <errno.h> |
| #include <misc/printk.h> |
| |
| #include "tcp_cfg.h" |
| #include "tcp.h" |
| |
| #include <net/ip_buf.h> |
| #include <net/net_core.h> |
| #include <net/net_socket.h> |
| |
| #if !defined(CONFIG_MBEDTLS_CFG_FILE) |
| #include "mbedtls/config.h" |
| #else |
| #include CONFIG_MBEDTLS_CFG_FILE |
| #endif |
| |
| #include "mbedtls/ssl.h" |
| |
| uip_ipaddr_t uip_hostaddr = { {CLIENT_IPADDR0, CLIENT_IPADDR1, |
| CLIENT_IPADDR2, CLIENT_IPADDR3} |
| }; |
| |
| uip_ipaddr_t uip_netmask = { {NETMASK0, NETMASK1, NETMASK2, NETMASK3} |
| }; |
| |
| #define CLIENT_IP_ADDR { { { CLIENT_IPADDR0, CLIENT_IPADDR1, \ |
| CLIENT_IPADDR2, CLIENT_IPADDR3 } } } |
| |
| #define SERVER_IP_ADDR { { { SERVER_IPADDR0, SERVER_IPADDR1, \ |
| SERVER_IPADDR2, SERVER_IPADDR3 } } } |
| |
| #define INET_FAMILY AF_INET |
| |
| int tcp_tx(void *context, const unsigned char *buf, size_t size) |
| { |
| struct tcp_context *ctx = context; |
| struct net_buf *nbuf; |
| uint8_t *ptr; |
| int rc = 0; |
| nbuf = ip_buf_get_tx(ctx->net_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); |
| fiber_sleep(TCP_RETRY_TIMEOUT); |
| if (rc >= 0) { |
| ip_buf_unref(nbuf); |
| return size; |
| } |
| switch (rc) { |
| case -EINPROGRESS: |
| break; |
| case -EAGAIN: |
| case -ECONNRESET: |
| break; |
| default: |
| ip_buf_unref(nbuf); |
| return -EIO; |
| } |
| } while (1); |
| |
| return -EIO; |
| } |
| |
| int tcp_rx(void *context, unsigned char *buf, size_t size) |
| { |
| struct tcp_context *ctx = context; |
| struct net_buf *nbuf; |
| int8_t *ptr; |
| int rc, read_bytes; |
| |
| if (ctx->rx_nbuf == NULL) { |
| nbuf = net_receive(ctx->net_ctx, TCP_RX_TIMEOUT); |
| rc = -EIO; |
| if (nbuf != NULL) { |
| read_bytes = ip_buf_appdatalen(nbuf); |
| if (read_bytes > size) { |
| memcpy(buf, ip_buf_appdata(nbuf), size); |
| ctx->rx_nbuf = nbuf; |
| ctx->remaining = read_bytes - size; |
| return size; |
| } else { |
| memcpy(buf, ip_buf_appdata(nbuf), read_bytes); |
| rc = read_bytes; |
| } |
| ip_buf_unref(nbuf); |
| } |
| } else { |
| ptr = ip_buf_appdata(ctx->rx_nbuf); |
| read_bytes = ip_buf_appdatalen(ctx->rx_nbuf) - ctx->remaining; |
| ptr += read_bytes; |
| if (ctx->remaining > size) { |
| memcpy(buf, ptr, size); |
| ctx->remaining -= size; |
| rc = size; |
| } else { |
| read_bytes = size < ctx->remaining ? size : ctx->remaining; |
| memcpy(buf, ptr, read_bytes); |
| ip_buf_unref(ctx->rx_nbuf); |
| ctx->remaining = 0; |
| ctx->rx_nbuf = NULL; |
| rc = read_bytes; |
| } |
| } |
| |
| return rc; |
| } |
| |
| int tcp_init(struct tcp_context *ctx) |
| { |
| static struct in_addr server_addr = SERVER_IP_ADDR; |
| static struct in_addr client_addr = CLIENT_IP_ADDR; |
| static struct net_addr server; |
| static struct net_addr client; |
| char woke = 0; |
| |
| server.in_addr = server_addr; |
| server.family = AF_INET; |
| |
| client.in_addr = client_addr; |
| client.family = AF_INET; |
| |
| ctx->rx_nbuf = NULL; |
| ctx->remaining = 0; |
| |
| ctx->net_ctx = net_context_get(IPPROTO_TCP, |
| &server, SERVER_PORT, |
| &client, CLIENT_PORT); |
| if (ctx->net_ctx == NULL) { |
| return -EINVAL; |
| } |
| |
| /* In order to stablish connection, at least one packet has to be sent, |
| * sending a 0 size packet is no longer possible, as noted in |
| * https://jira.zephyrproject.org/browse/ZEP-612 so at least one byte |
| * has to be sent. |
| */ |
| tcp_tx(ctx, &woke, 1); |
| |
| return 0; |
| } |