Commit 9515bdd8 authored by Alessandro Rubini's avatar Alessandro Rubini

net: add support for UDP sockets, use it (receive only by now)

We are going to add more UDP services, so this commit adds the
generic management of UDP sockets, with udp protocol and port matching.
Thus, we now have two IPV4 sockets: one for ICMP and one for bootp;
whose receive part relies on generic code for the match.

We still miss the output helpers, so with this commit bootp still
builds the whole frame by itself.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 3e26f250
......@@ -15,7 +15,8 @@
#include <board.h>
//#include <inttypes.h>
#define PTPD_SOCK_RAW_ETHERNET 1 /* used in ppsi to no aim: remove this */
#define PTPD_SOCK_UDP 0 /* wrong name, it should be "WRPC" */
#define PTPD_SOCK_RAW_ETHERNET 1 /* but used in ppsi, which I won't change */
// GCC-specific
#ifndef PACKED
......@@ -31,10 +32,11 @@ typedef uint8_t mac_addr_t[6];
struct wr_sockaddr {
// MAC address
mac_addr_t mac;
// Destination MASC address, filled by recvfrom()
// Destination MAC address, filled by recvfrom()
mac_addr_t mac_dest;
// RAW ethertype
uint16_t ethertype;
uint16_t udpport;
};
struct sockq {
......@@ -79,7 +81,7 @@ PACKED struct wr_timestamp {
// physical_port field to bind the socket to specific switch port only.
struct wrpc_socket *ptpd_netif_create_socket(struct wrpc_socket *s,
struct wr_sockaddr * bind_addr,
int unused, int unused2);
int udp_or_raw, int udpport);
// Sends a UDP/RAW packet (data, data_length) to addr in wr_sockaddr.
// For raw frames, mac/ethertype needs to be provided, for UDP - ip/port.
......
......@@ -44,7 +44,7 @@ void arp_init(void)
saddr.ethertype = htons(0x0806); /* ARP */
arp_socket = ptpd_netif_create_socket(&__static_arp_socket, &saddr,
0, 0 /* both unused */);
PTPD_SOCK_RAW_ETHERNET, 0);
}
static int process_arp(uint8_t * buf, int len)
......
......@@ -29,7 +29,7 @@
#define BOOTP_VEND (BOOTP_FILE+128)
#define BOOTP_END (BOOTP_VEND+64)
int send_bootp(uint8_t * buf, int retry)
int prepare_bootp(struct wr_sockaddr *addr, uint8_t * buf, int retry)
{
unsigned short sum;
......@@ -110,6 +110,8 @@ int send_bootp(uint8_t * buf, int retry)
buf[IP_CHECKSUM + 0] = sum >> 8;
buf[IP_CHECKSUM + 1] = sum & 0xff;
/* and fix destination before sending it */
memset(addr->mac, 0xFF, 6);
// pp_printf("Sending BOOTP request...\n");
return BOOTP_END;
}
......@@ -124,12 +126,7 @@ int process_bootp(uint8_t * buf, int len)
if (len != BOOTP_END)
return 0;
if (buf[IP_VERSION] != 0x45)
return 0;
if (buf[IP_PROTOCOL] != 17 ||
buf[UDP_DPORT] != 0 || buf[UDP_DPORT + 1] != 68 ||
buf[UDP_SPORT] != 0 || buf[UDP_SPORT + 1] != 67)
if (buf[UDP_SPORT] != 0 || buf[UDP_SPORT + 1] != 67)
return 0;
if (memcmp(buf + BOOTP_CHADDR, mac, 6))
......
......@@ -18,14 +18,25 @@
#define htons(x) x
#endif
int needIP = 1;
int needIP;
static uint8_t myIP[4];
static uint8_t __ipv4_queue[512];
static struct wrpc_socket __static_ipv4_socket = {
.queue.buff = __ipv4_queue,
.queue.size = sizeof(__ipv4_queue),
/* bootp: bigger buffer, UDP based */
static uint8_t __bootp_queue[512];
static struct wrpc_socket __static_bootp_socket = {
.queue.buff = __bootp_queue,
.queue.size = sizeof(__bootp_queue),
};
static struct wrpc_socket *bootp_socket;
/* ICMP: smaller buffer */
static uint8_t __icmp_queue[128];
static struct wrpc_socket __static_icmp_socket = {
.queue.buff = __icmp_queue,
.queue.size = sizeof(__icmp_queue),
};
static struct wrpc_socket *ipv4_socket;
static struct wrpc_socket *icmp_socket;
unsigned int ipv4_checksum(unsigned short *buf, int shorts)
{
......@@ -49,46 +60,68 @@ void ipv4_init(void)
/* Reset => need a fresh IP */
needIP = 1;
/* Configure socket filter */
/* Bootp: use UDP engine activated but function arguments */
memset(&saddr, 0, sizeof(saddr));
get_mac_addr(&saddr.mac[0]); /* Unicast */
saddr.ethertype = htons(0x0800); /* IPv4 */
ipv4_socket = ptpd_netif_create_socket(&__static_ipv4_socket, &saddr,
0, 0 /* both unused */);
bootp_socket = ptpd_netif_create_socket(&__static_bootp_socket, &saddr,
PTPD_SOCK_UDP, 68 /* bootpc */);
/* ICMP: specify raw (not UDP), with IPV4 ethtype */
saddr.ethertype = htons(0x0800);
icmp_socket = ptpd_netif_create_socket(&__static_icmp_socket, &saddr,
PTPD_SOCK_RAW_ETHERNET, 0);
}
static int bootp_retry = 0;
static uint32_t bootp_tics;
void ipv4_poll(void)
/* receive bootp through the UDP mechanism */
static void bootp_poll(void)
{
uint8_t buf[400];
struct wr_sockaddr addr;
uint8_t buf[400];
int len;
if (!bootp_tics)
if (!bootp_tics) /* first time ever */
bootp_tics = timer_get_tics() - 1;
len = ptpd_netif_recvfrom(bootp_socket, &addr,
buf, sizeof(buf), NULL);
if (len > 0 && needIP)
process_bootp(buf, len);
if (!needIP)
return;
if (time_before(timer_get_tics(), bootp_tics))
return;
if ((len = ptpd_netif_recvfrom(ipv4_socket, &addr,
buf, sizeof(buf), 0)) > 0) {
if (needIP)
process_bootp(buf, len);
len = prepare_bootp(&addr, buf, ++bootp_retry);
ptpd_netif_sendto(bootp_socket, &addr, buf, len, 0);
bootp_tics = timer_get_tics() + TICS_PER_SECOND;
}
if (!needIP && (len = process_icmp(buf, len)) > 0)
ptpd_netif_sendto(ipv4_socket, &addr, buf, len, 0);
}
static void icmp_poll(void)
{
struct wr_sockaddr addr;
uint8_t buf[128];
int len;
if (needIP && time_after(timer_get_tics(), bootp_tics)) {
len = send_bootp(buf, ++bootp_retry);
len = ptpd_netif_recvfrom(icmp_socket, &addr,
buf, sizeof(buf), NULL);
if (len <= 0)
return;
if (needIP)
return;
memset(addr.mac, 0xFF, 6);
addr.ethertype = htons(0x0800); /* IPv4 */
ptpd_netif_sendto(ipv4_socket, &addr, buf, len, 0);
bootp_tics = timer_get_tics() + TICS_PER_SECOND;
}
if ((len = process_icmp(buf, len)) > 0)
ptpd_netif_sendto(icmp_socket, &addr, buf, len, 0);
}
void ipv4_poll(void)
{
bootp_poll();
icmp_poll();
}
void getIP(unsigned char *IP)
......
......@@ -7,6 +7,7 @@
#define IPV4_H
#include <inttypes.h>
#include "ptpd_netif.h" /* for sockaddr in prototype */
#define IP_VERSION 0
#define IP_TOS (IP_VERSION+1)
......@@ -47,6 +48,6 @@ void getIP(unsigned char *IP);
int process_icmp(uint8_t * buf, int len);
int process_bootp(uint8_t * buf, int len); /* non-zero if IP was set */
int send_bootp(uint8_t * buf, int retry);
int prepare_bootp(struct wr_sockaddr *addr, uint8_t * buf, int retry);
#endif
......@@ -22,6 +22,7 @@
#include "minic.h"
#include "endpoint.h"
#include "softpll_ng.h"
#include "ipv4.h"
#define min(x,y) ((x) < (y) ? (x) : (y))
......@@ -53,10 +54,11 @@ void ptpd_netif_set_phase_transition(uint32_t phase)
struct wrpc_socket *ptpd_netif_create_socket(struct wrpc_socket *sock,
struct wr_sockaddr * bind_addr,
int unused, int unusd2)
int udp_or_raw, int udpport)
{
int i;
struct hal_port_state pstate;
static mac_addr_t zero_mac;
/* Look for the first available socket. */
for (i = 0; i < ARRAY_SIZE(socks); i++)
......@@ -72,7 +74,15 @@ struct wrpc_socket *ptpd_netif_create_socket(struct wrpc_socket *sock,
if (wrpc_get_port_state(&pstate, "wr0" /* unused */) < 0)
return NULL;
/* copy and complete the bind information. If MAC is 0 use unicast */
memcpy(&sock->bind_addr, bind_addr, sizeof(struct wr_sockaddr));
if (!memcmp(sock->bind_addr.mac, zero_mac, ETH_ALEN))
get_mac_addr(sock->bind_addr.mac);
sock->bind_addr.udpport = 0;
if (udp_or_raw == PTPD_SOCK_UDP) {
sock->bind_addr.ethertype = htons(0x0800); /* IPv4 */
sock->bind_addr.udpport = udpport;
}
/*get mac from endpoint */
get_mac_addr(sock->local_mac);
......@@ -273,7 +283,7 @@ int ptpd_netif_sendto(struct wrpc_socket * sock, struct wr_sockaddr *to, void *d
memcpy(hdr.dstmac, to->mac, 6);
memcpy(hdr.srcmac, s->local_mac, 6);
hdr.ethtype = to->ethertype;
hdr.ethtype = sock->bind_addr.ethertype;
rval =
minic_tx_frame((uint8_t *) & hdr, (uint8_t *) data,
......@@ -298,7 +308,7 @@ void update_rx_queues()
static struct ethhdr hdr;
int recvd, i, q_required;
static uint8_t payload[NET_MAX_SKBUF_SIZE - 32];
uint16_t size;
uint16_t size, port;
recvd =
minic_rx_frame((uint8_t *) & hdr, payload, sizeof(payload),
......@@ -309,13 +319,29 @@ void update_rx_queues()
for (i = 0; i < ARRAY_SIZE(socks); i++) {
s = socks[i];
if (s && !memcmp(hdr.dstmac, s->bind_addr.mac, 6)
&& hdr.ethtype == s->bind_addr.ethertype)
break; /*they match */
s = NULL; /* may be non-null but not matching */
if (!s)
continue;
if (memcmp(hdr.dstmac, s->bind_addr.mac, 6))
continue;
if (hdr.ethtype != s->bind_addr.ethertype)
continue;
if (s->bind_addr.udpport == 0)
break; /* raw socket: match */
/* Now make IP/UDP checks */
if (payload[IP_VERSION] != 0x45)
continue;
if (payload[IP_PROTOCOL] != 17)
continue;
port = payload[UDP_DPORT] << 8 | payload[UDP_DPORT + 1];
if (port != s->bind_addr.udpport)
continue;
break; /* udp match */
}
if (!s) {
if (i == ARRAY_SIZE(socks)) {
net_verbose("%s: could not find socket for packet\n",
__FUNCTION__);
return;
......
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