From 77a288d2672905d4a2164cdca961725328019823 Mon Sep 17 00:00:00 2001
From: Alessandro Rubini <rubini@gnudd.com>
Date: Thu, 14 Jan 2016 00:39:18 +0100
Subject: [PATCH] net: added UDP helper; use it in bootp

This pair of commits costs around 300 bytes overall, in network-using
configurations.

Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
---
 lib/bootp.c | 56 ++++++---------------------------------
 lib/ipv4.h  | 11 ++++++++
 lib/lib.mk  |  2 +-
 lib/udp.c   | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 95 insertions(+), 49 deletions(-)
 create mode 100644 lib/udp.c

diff --git a/lib/bootp.c b/lib/bootp.c
index 197c13d57..7e4338d3a 100644
--- a/lib/bootp.c
+++ b/lib/bootp.c
@@ -31,7 +31,7 @@
 
 int prepare_bootp(struct wr_sockaddr *addr, uint8_t * buf, int retry)
 {
-	unsigned short sum;
+	struct wr_udp_addr uaddr;
 
 	// ----------- BOOTP ------------
 	buf[BOOTP_OP] = 1;	/* bootrequest */
@@ -62,53 +62,13 @@ int prepare_bootp(struct wr_sockaddr *addr, uint8_t * buf, int retry)
 	memset(buf + BOOTP_FILE, 0, 128);	/* desired BOOTP file */
 	memset(buf + BOOTP_VEND, 0, 64);	/* vendor extensions */
 
-	// ------------ UDP -------------
-	memset(buf + UDP_VIRT_SADDR, 0, 4);
-	memset(buf + UDP_VIRT_DADDR, 0xFF, 4);
-	buf[UDP_VIRT_ZEROS] = 0;
-	buf[UDP_VIRT_PROTO] = 0x11;	/* UDP */
-	buf[UDP_VIRT_LENGTH] = (BOOTP_END - IP_END) >> 8;
-	buf[UDP_VIRT_LENGTH + 1] = (BOOTP_END - IP_END) & 0xff;
-
-	buf[UDP_SPORT] = 0;
-	buf[UDP_SPORT + 1] = 68;	/* BOOTP client */
-	buf[UDP_DPORT] = 0;
-	buf[UDP_DPORT + 1] = 67;	/* BOOTP server */
-	buf[UDP_LENGTH] = (BOOTP_END - IP_END) >> 8;
-	buf[UDP_LENGTH + 1] = (BOOTP_END - IP_END) & 0xff;
-	buf[UDP_CHECKSUM] = 0;
-	buf[UDP_CHECKSUM + 1] = 0;
-
-	sum =
-	    ipv4_checksum((unsigned short *)(buf + UDP_VIRT_SADDR),
-			  (BOOTP_END - UDP_VIRT_SADDR) / 2);
-	if (sum == 0)
-		sum = 0xFFFF;
-
-	buf[UDP_CHECKSUM + 0] = (sum >> 8);
-	buf[UDP_CHECKSUM + 1] = sum & 0xff;
-
-	// ------------ IP --------------
-	buf[IP_VERSION] = 0x45;
-	buf[IP_TOS] = 0;
-	buf[IP_LEN + 0] = (BOOTP_END) >> 8;
-	buf[IP_LEN + 1] = (BOOTP_END) & 0xff;
-	buf[IP_ID + 0] = 0;
-	buf[IP_ID + 1] = 0;
-	buf[IP_FLAGS + 0] = 0;
-	buf[IP_FLAGS + 1] = 0;
-	buf[IP_TTL] = 63;
-	buf[IP_PROTOCOL] = 17;	/* UDP */
-	buf[IP_CHECKSUM + 0] = 0;
-	buf[IP_CHECKSUM + 1] = 0;
-	memset(buf + IP_SOURCE, 0, 4);
-	memset(buf + IP_DEST, 0xFF, 4);
-
-	sum =
-	    ipv4_checksum((unsigned short *)(buf + IP_VERSION),
-			  (IP_END - IP_VERSION) / 2);
-	buf[IP_CHECKSUM + 0] = sum >> 8;
-	buf[IP_CHECKSUM + 1] = sum & 0xff;
+	/* complete with udp helper */
+	memset(&uaddr.saddr, 0, 4);
+	memset(&uaddr.daddr, 0xff, 4);
+	uaddr.sport = ntohs(68);
+	uaddr.dport = ntohs(67);
+
+	fill_udp(buf, BOOTP_END, &uaddr);
 
 	/* and fix destination before sending it */
 	memset(addr->mac, 0xFF, 6);
diff --git a/lib/ipv4.h b/lib/ipv4.h
index 34b839598..2c5a3dbe8 100644
--- a/lib/ipv4.h
+++ b/lib/ipv4.h
@@ -50,4 +50,15 @@ int process_icmp(uint8_t * buf, int len);
 int process_bootp(uint8_t * buf, int len);	/* non-zero if IP was set */
 int prepare_bootp(struct wr_sockaddr *addr, uint8_t * buf, int retry);
 
+/* The UDP helper needs some information, if not replying to a frame */
+struct wr_udp_addr {
+	uint32_t saddr; /* all fields in network order, for memcpy */
+	uint32_t daddr;
+	uint16_t sport;
+	uint16_t dport;
+};
+
+void fill_udp(uint8_t * buf, int len, struct wr_udp_addr *uaddr);
+
+
 #endif
diff --git a/lib/lib.mk b/lib/lib.mk
index b477d4e43..b68a722a6 100644
--- a/lib/lib.mk
+++ b/lib/lib.mk
@@ -1,5 +1,5 @@
 obj-y += lib/util.o lib/atoi.o
 obj-y += lib/usleep.o
-obj-$(CONFIG_WR_NODE) += lib/net.o
+obj-$(CONFIG_WR_NODE) += lib/net.o lib/udp.o
 
 obj-$(CONFIG_WR_NODE) += lib/arp.o lib/icmp.o lib/ipv4.o lib/bootp.o
diff --git a/lib/udp.c b/lib/udp.c
new file mode 100644
index 000000000..99262aa17
--- /dev/null
+++ b/lib/udp.c
@@ -0,0 +1,75 @@
+/*
+ * This work is part of the White Rabbit project
+ *
+ * Copyright (C) 2016 GSI (www.gsi.de)
+ * Author: Alessandro Rubini <a.rubini@gsi.de>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ */
+
+#include <string.h>
+#include "ipv4.h"
+#include "ptpd_netif.h"
+
+void fill_udp(uint8_t * buf, int len, struct wr_udp_addr *uaddr)
+{
+	unsigned short sum;
+	struct wr_udp_addr addr;
+
+	/* if there is no user-provided uaddr, we are replying */
+	if (!uaddr) {
+		memcpy(&addr.daddr, buf + IP_SOURCE, 4);
+		memcpy(&addr.saddr, buf + IP_DEST, 4);
+		memcpy(&addr.dport, buf + UDP_SPORT, 2);
+		memcpy(&addr.sport, buf + UDP_DPORT, 2);
+		uaddr = &addr;
+	}
+
+	// ------------ UDP -------------
+	memcpy(buf + UDP_VIRT_SADDR, &uaddr->saddr, 4);
+	memcpy(buf + UDP_VIRT_DADDR, &uaddr->daddr, 4);
+	buf[UDP_VIRT_ZEROS] = 0;
+	buf[UDP_VIRT_PROTO] = 0x11;	/* UDP */
+	buf[UDP_VIRT_LENGTH] = (len - IP_END) >> 8;
+	buf[UDP_VIRT_LENGTH + 1] = (len - IP_END) & 0xff;
+
+	memcpy(buf + UDP_SPORT, &uaddr->sport, 2);
+	memcpy(buf + UDP_DPORT, &uaddr->dport, 2);
+	buf[UDP_LENGTH] = (len - IP_END) >> 8;
+	buf[UDP_LENGTH + 1] = (len - IP_END) & 0xff;
+	buf[UDP_CHECKSUM] = 0;
+	buf[UDP_CHECKSUM + 1] = 0;
+
+	sum =
+	    ipv4_checksum((unsigned short *)(buf + UDP_VIRT_SADDR),
+			  (len - UDP_VIRT_SADDR) / 2);
+	if (sum == 0)
+		sum = 0xFFFF;
+
+	buf[UDP_CHECKSUM + 0] = (sum >> 8);
+	buf[UDP_CHECKSUM + 1] = sum & 0xff;
+
+	// ------------ IP --------------
+	buf[IP_VERSION] = 0x45;
+	buf[IP_TOS] = 0;
+	buf[IP_LEN + 0] = len >> 8;
+	buf[IP_LEN + 1] = len & 0xff;
+	buf[IP_ID + 0] = 0;
+	buf[IP_ID + 1] = 0;
+	buf[IP_FLAGS + 0] = 0;
+	buf[IP_FLAGS + 1] = 0;
+	buf[IP_TTL] = 63;
+	buf[IP_PROTOCOL] = 17;	/* UDP */
+	buf[IP_CHECKSUM + 0] = 0;
+	buf[IP_CHECKSUM + 1] = 0;
+	memcpy(buf + IP_SOURCE, &uaddr->saddr, 4);
+	memcpy(buf + IP_DEST, &uaddr->daddr, 4);
+
+	sum =
+	    ipv4_checksum((unsigned short *)(buf + IP_VERSION),
+			  (IP_END - IP_VERSION) / 2);
+	buf[IP_CHECKSUM + 0] = sum >> 8;
+	buf[IP_CHECKSUM + 1] = sum & 0xff;
+
+	return;
+}
-- 
GitLab