Commit b218c2b6 authored by danielinux's avatar danielinux

Merge branch 'raw_socket' into gl

parents 1ef8bac3 e79565ef
......@@ -15,6 +15,7 @@
#include "pico_device.h"
#include "pico_stack.h"
#include "pico_tree.h"
#include "pico_socket.h"
/* Queues */
static struct pico_queue icmp_in = {
......@@ -44,12 +45,125 @@ static int pico_icmp4_checksum(struct pico_frame *f)
static void ping_recv_reply(struct pico_frame *f);
#endif
/******************************/
/* ICMP socket implementation */
/******************************/
static uint16_t I4Socket_id = 0;
struct pico_socket_icmp4
{
struct pico_socket sock;
uint16_t id;
};
static int icmp4_socket_cmp(void *ka, void *kb)
{
struct pico_socket_icmp4 *a = ka, *b = kb;
if (a->id < b->id)
return -1;
if (a->id > b->id)
return 1;
return (0);
}
static PICO_TREE_DECLARE(I4Sockets, icmp4_socket_cmp);
struct pico_socket *pico_socket_icmp4_open(void)
{
struct pico_socket_icmp4 *s;
s = PICO_ZALLOC(sizeof(struct pico_socket_icmp4));
if (!s) {
pico_err = PICO_ERR_ENOMEM;
return NULL;
}
s->sock.proto = &pico_proto_icmp4;
s->id = I4Socket_id++;
pico_tree_insert(&I4Sockets, s);
return (struct pico_socket *)s;
}
int pico_socket_icmp4_bind(struct pico_socket *s, void *addr, uint16_t port)
{
struct pico_socket_icmp4 test;
test.id = port;
if (pico_tree_findKey(&I4Sockets, &test)) {
pico_err = PICO_ERR_EADDRINUSE;
return -1;
}
pico_tree_delete(&I4Sockets, s);
s->id = port;
pico_tree_insert(&I4Sockets, s);
return 0;
}
int pico_socket_icmp4_recvfrom(struct pico_socket *s, void *buf, int len, void *orig,
uint16_t *remote_port)
{
struct pico_frame *f;
f = pico_dequeue(&s->q_in);
if (!f)
return 0;
if (f->transport_len < len) {
len = f->transport_len;
}
memcpy(buf, f->transport_hdr, (size_t)len);
if (orig) {
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
memcpy(orig, &hdr->src, sizeof(struct pico_ip4));
}
*remote_port = 0;
pico_frame_discard(f);
return len;
}
int pico_socket_icmp4_sendto_check(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port)
{
struct pico_icmp4_hdr *hdr;
struct pico_frame *echo;
struct pico_socket_icmp4 *i4 = (struct pico_socket_icmp4 *)s;
(void)remote_port;
if (len < 8) {
pico_err = PICO_ERR_EINVAL;
return -1;
}
/* Check header sent */
hdr = (struct pico_icmp4_hdr *) buf;
if (hdr->type != PICO_ICMP_ECHO) {
pico_err = PICO_ERR_EINVAL;
return -1;
}
if(hdr->code != 0) {
pico_err = PICO_ERR_EINVAL;
return -1;
}
hdr->hun.ih_idseq.idseq_id = i4->id;
return len;
}
int pico_socket_icmp4_close(struct pico_socket *arg)
{
struct pico_socket_icmp4 *s = (struct pico_socket_icmp4 *)arg;
if (s) {
pico_tree_delete(&I4Sockets, s);
return 0;
}
pico_err = PICO_ERR_ENOENT;
return -1;
}
static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f)
{
struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
static int firstpkt = 1;
static uint16_t last_id = 0;
static uint16_t last_seq = 0;
struct pico_socket_icmp4 *s = NULL;
struct pico_socket_icmp4 test;
IGNORE_PARAMETER(self);
if (hdr->type == PICO_ICMP_ECHO) {
......@@ -76,6 +190,18 @@ static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *
#ifdef PICO_SUPPORT_PING
ping_recv_reply(f);
#endif
test.id = hdr->hun.ih_idseq.idseq_id;
s = pico_tree_findKey(&I4Sockets, &test);
if (s) {
struct pico_frame *cp;
cp = pico_frame_copy(f);
if (cp) {
pico_enqueue(&s->sock.q_in, cp);
if (s->sock.wakeup) {
s->sock.wakeup(PICO_SOCK_EV_RD, &s->sock);
}
}
}
pico_frame_discard(f);
} else {
pico_frame_discard(f);
......@@ -87,9 +213,17 @@ static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *
static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
{
IGNORE_PARAMETER(self);
IGNORE_PARAMETER(f);
dbg("Called %s\n", __FUNCTION__);
return 0;
pico_icmp4_checksum(f);
return (int)pico_network_send(f);
}
static int pico_icmp4_push(struct pico_protocol *self, struct pico_frame *f)
{
if (pico_enqueue(self->q_out, f) > 0) {
return f->payload_len;
} else {
return 0;
}
}
/* Interface: protocol definition */
......@@ -97,6 +231,7 @@ struct pico_protocol pico_proto_icmp4 = {
.name = "icmp4",
.proto_number = PICO_PROTO_ICMP4,
.layer = PICO_LAYER_TRANSPORT,
.push = pico_icmp4_push,
.process_in = pico_icmp4_process_in,
.process_out = pico_icmp4_process_out,
.q_in = &icmp_in,
......@@ -188,6 +323,8 @@ int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code)
return pico_icmp4_notify(f, PICO_ICMP_PARAMPROB, code);
}
/***********************/
/* Ping implementation */
/***********************/
......
......@@ -145,6 +145,13 @@ int pico_icmp4_frag_expired(struct pico_frame *f);
int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *));
int pico_icmp4_ping_abort(int id);
struct pico_socket *pico_icmp4_socket_open(void);
void pico_icmp4_socket_close(struct pico_socket *s);
int pico_socket_icmp4_sendto_check(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port);
int pico_socket_icmp4_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port);
int pico_socket_icmp4_bind(struct pico_socket *s, void *addr, uint16_t port);
#ifdef PICO_SUPPORT_ICMP4
int pico_icmp4_packet_filtered(struct pico_frame *f);
int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code);
......
......@@ -381,7 +381,120 @@ static void pico_ipv4_process_finally_try_forward(struct pico_frame *f)
}
}
/* Raw sockets support */
struct pico_socket_ipv4
{
struct pico_socket sock;
uint16_t id;
uint8_t proto;
};
static uint16_t IP4Socket_id = 0;
static int ipv4_socket_cmp(void *ka, void *kb)
{
struct pico_socket_ipv4 *a = ka, *b = kb;
if (a->id < b->id)
return -1;
if (a->id > b->id)
return 1;
return (0);
}
static PICO_TREE_DECLARE(IP4Sockets, ipv4_socket_cmp);
struct pico_socket *pico_socket_ipv4_open(uint8_t proto)
{
struct pico_socket_ipv4 *s;
if (proto == 0 || proto == PICO_PROTO_TCP || proto == PICO_PROTO_UDP) {
pico_err = PICO_ERR_EINVAL;
return NULL;
}
s = PICO_ZALLOC(sizeof(struct pico_socket_ipv4));
if (!s) {
pico_err = PICO_ERR_ENOMEM;
return NULL;
}
s->id = IP4Socket_id++;
s->proto = proto;
pico_tree_insert(&IP4Sockets, s);
return (struct pico_socket *)s;
}
int pico_socket_ipv4_recvfrom(struct pico_socket *s, void *buf, int len, void *orig,
uint16_t *remote_port)
{
struct pico_frame *f;
f = pico_dequeue(&s->q_in);
if (!f)
return 0;
if (f->transport_len < len) {
len = f->transport_len;
}
memcpy(buf, f->transport_hdr, (size_t)len);
if (orig) {
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
memcpy(orig, &hdr->src, sizeof(struct pico_ip4));
}
*remote_port = 0;
pico_frame_discard(f);
return len;
}
int pico_socket_ipv4_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port)
{
struct pico_socket_ipv4 *i4 = (struct pico_socket_ipv4 *)s;
struct pico_ipv4_hdr *hdr;
struct pico_frame *f;
(void)remote_port;
if (len < 8) {
pico_err = PICO_ERR_EINVAL;
return -1;
}
/* Allocate packet and send */
f = pico_proto_ipv4.alloc(&pico_proto_ipv4, NULL, (uint16_t)(len));
if (!f) {
return -1;
}
f->transport_len = (uint16_t)(len);
pico_ipv4_frame_push(f, dst, s->proto);
return len;
}
int pico_socket_ipv4_close(struct pico_socket *arg)
{
struct pico_socket_ipv4 *s = (struct pico_socket_ipv4 *)arg;
if (s) {
pico_tree_delete(&IP4Sockets, s);
return 0;
}
pico_err = PICO_ERR_ENOENT;
return -1;
}
static void pico_ipv4_process_raw_socket(struct pico_frame *f)
{
struct pico_tree_node *node;
struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
pico_tree_foreach(node, &IP4Sockets) {
struct pico_socket_ipv4 *s;
struct pico_frame *cp;
s = (struct pico_socket_ipv4 *) node->keyValue;
if (s->proto == hdr->proto) {
cp = pico_frame_copy(f);
if (cp) {
pico_enqueue(&s->sock.q_in, cp);
if (s->sock.wakeup) {
s->sock.wakeup(PICO_SOCK_EV_RD, &s->sock);
}
}
}
}
}
static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f)
{
......@@ -460,6 +573,8 @@ static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f
}
#endif
pico_ipv4_process_raw_socket(f);
if (pico_ipv4_process_bcast_in(f) > 0)
return 0;
......
......@@ -112,4 +112,12 @@ int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_gr
struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void);
int pico_ipv4_cleanup_links(struct pico_device *dev);
/* Raw socket support */
struct pico_socket_ipv4;
struct pico_socket *pico_socket_ipv4_open(uint8_t proto);
int pico_socket_ipv4_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port);
int pico_socket_ipv4_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port);
#endif /* _INCLUDE_PICO_IPV4 */
......@@ -63,7 +63,6 @@ static inline int pico_socket_udp_deliver_ipv4_mcast_initial_checks(struct pico_
return 0;
}
static int pico_socket_udp_deliver_ipv4_mcast(struct pico_socket *s, struct pico_frame *f)
{
struct pico_ip4 s_local;
......
......@@ -625,6 +625,11 @@ static struct pico_socket *pico_socket_transport_open(uint16_t proto, uint16_t f
#endif
#ifdef PICO_SUPPORT_ICMP4
if (proto == PICO_PROTO_ICMP4)
s = pico_socket_icmp4_open();
#endif
return s;
}
......@@ -883,6 +888,10 @@ static void *pico_socket_sendto_get_ip6_src(struct pico_socket *s, struct pico_i
static int pico_socket_sendto_dest_check(struct pico_socket *s, void *dst, uint16_t port)
{
/* Don't execute port/connection state for RAW sockets */
if ((PROTO(s) != PICO_PROTO_TCP) && (PROTO(s) != PICO_PROTO_UDP))
return 0;
/* For the sendto call to be valid,
* dst and remote_port should be always populated.
*/
......@@ -979,8 +988,7 @@ static struct pico_remote_endpoint *pico_socket_sendto_destination(struct pico_s
struct pico_remote_endpoint *ep = NULL;
(void)pico_socket_sendto_destination_ipv6;
/* socket remote info could change in a consecutive call, make persistent */
# ifdef PICO_SUPPORT_UDP
if (PROTO(s) == PICO_PROTO_UDP) {
if (PROTO(s) != PICO_PROTO_TCP) {
# ifdef PICO_SUPPORT_IPV6
if (is_sock_ipv6(s))
ep = pico_socket_sendto_destination_ipv6(s, (struct pico_ip6 *)dst, port);
......@@ -992,8 +1000,6 @@ static struct pico_remote_endpoint *pico_socket_sendto_destination(struct pico_s
# endif
}
# endif
return ep;
}
......@@ -1015,7 +1021,7 @@ static int32_t pico_socket_sendto_set_localport(struct pico_socket *s)
static int pico_socket_sendto_transport_offset(struct pico_socket *s)
{
int header_offset = -1;
int header_offset = 0;
#ifdef PICO_SUPPORT_TCP
if (PROTO(s) == PICO_PROTO_TCP)
header_offset = pico_tcp_overhead(s);
......@@ -1321,12 +1327,6 @@ static int pico_socket_xmit_avail_space(struct pico_socket *s)
} else
#endif
transport_len = (uint16_t)pico_socket_get_mss(s);
header_offset = pico_socket_sendto_transport_offset(s);
if (header_offset < 0) {
pico_err = PICO_ERR_EPROTONOSUPPORT;
return -1;
}
transport_len -= pico_socket_sendto_transport_offset(s);
return transport_len;
}
......@@ -1344,7 +1344,8 @@ static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int le
return -1;
}
if ((PROTO(s) == PICO_PROTO_UDP) && (len > space)) {
if ((PROTO(s) != PICO_PROTO_TCP) && (len > space)) {
total_payload_written = pico_socket_xmit_fragments(s, buf, len, src, ep, msginfo);
/* Implies ep discarding */
return total_payload_written;
......@@ -1361,7 +1362,7 @@ static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int le
}
total_payload_written += w;
if (PROTO(s) == PICO_PROTO_UDP) {
if (PROTO(s) != PICO_PROTO_TCP) {
/* Break after the first datagram sent with at most MTU bytes. */
break;
}
......@@ -1406,12 +1407,21 @@ int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf,
}
remote_endpoint = pico_socket_sendto_destination(s, dst, remote_port);
if (pico_socket_sendto_set_localport(s) < 0) {
pico_endpoint_free(remote_endpoint);
return -1;
if (PROTO(s) == PICO_PROTO_ICMP4) {
if (pico_socket_icmp4_sendto_check(s, buf, len, dst, remote_port) < 0)
return -1;
}
pico_socket_sendto_set_dport(s, remote_port);
if ((PROTO(s) == PICO_PROTO_UDP) || (PROTO(s) == PICO_PROTO_TCP)) {
if (pico_socket_sendto_set_localport(s) < 0) {
pico_endpoint_free(remote_endpoint);
return -1;
}
pico_socket_sendto_set_dport(s, remote_port);
}
return pico_socket_xmit(s, buf, len, src, remote_endpoint, msginfo); /* Implies discarding the endpoint */
}
......@@ -1450,17 +1460,30 @@ int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, voi
return -1;
} else {
/* check if exists in tree */
if (pico_check_socket(s) != 0) {
if ((PROTO(s) != PICO_PROTO_ICMP4) && pico_check_socket(s) != 0) {
pico_err = PICO_ERR_EINVAL;
/* See task #178 */
return -1;
}
}
/* forward request to icmp layer */
#ifdef PICO_SUPPORT_ICMP4
if (PROTO(s) == PICO_PROTO_ICMP4) {
if(len > 0xFFFF) {
pico_err = PICO_ERR_EINVAL;
return -1;
}
return pico_socket_icmp4_recvfrom(s, buf, (uint16_t)len, orig, remote_port);
}
#endif
if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
pico_err = PICO_ERR_EADDRNOTAVAIL;
return -1;
}
#ifdef PICO_SUPPORT_UDP
if (PROTO(s) == PICO_PROTO_UDP) {
......@@ -1601,6 +1624,12 @@ int MOCKABLE pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t
return -1;
}
#ifdef PICO_SUPPORT_ICMP4
if (PROTO(s) == PICO_PROTO_ICMP4) {
return pico_socket_icmp4_bind(s, local_addr, *port);
}
#endif
/* When given port = 0, get a random high port to bind to. */
if (*port == 0) {
*port = pico_socket_high_port(PROTO(s));
......@@ -1916,6 +1945,15 @@ int MOCKABLE pico_socket_close(struct pico_socket *s)
if (!s)
return -1;
#ifdef PICO_SUPPORT_ICMP4
if (PROTO(s) == PICO_PROTO_ICMP4) {
pico_socket_icmp4_close(s);
socket_clean_queues(s);
PICO_FREE(s);
return 0;
}
#endif
#ifdef PICO_SUPPORT_TCP
if (PROTO(s) == PICO_PROTO_TCP) {
if (pico_tcp_check_listen_close(s) == 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment