libnet/microudp: (WIP) fix endianness issues
authorJean-François Nguyen <jf@lse.epita.fr>
Mon, 3 Sep 2018 18:31:16 +0000 (20:31 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 6 Sep 2018 16:43:55 +0000 (18:43 +0200)
litex/boards/targets/arty.py
litex/soc/software/include/base/inet.h [new file with mode: 0644]
litex/soc/software/libbase/libc.c
litex/soc/software/libnet/microudp.c

index 5e0b5aecdde121fc9a6763ab978f43fe2272405d..501a8d7ec91b58c14f4672f43d196f70620e0ae4 100755 (executable)
@@ -136,7 +136,7 @@ class MiniSoC(BaseSoC):
 
         self.submodules.ethphy = LiteEthPHYMII(self.platform.request("eth_clocks"),
                                                self.platform.request("eth"))
-        self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone")
+        self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone", endianness="little")
         self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus)
         self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000)
 
diff --git a/litex/soc/software/include/base/inet.h b/litex/soc/software/include/base/inet.h
new file mode 100644 (file)
index 0000000..3730747
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright © 2005-2014 Rich Felker, et al.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __INET_H
+#define __INET_H
+
+#include <stdint.h>
+
+static __inline uint16_t __bswap_16(uint16_t __x)
+{
+       return (__x<<8) | (__x>>8);
+}
+
+static __inline uint32_t __bswap_32(uint32_t __x)
+{
+       return (__x>>24) | ((__x>>8)&0xff00) | ((__x<<8)&0xff0000) | (__x<<24);
+}
+
+static __inline uint64_t __bswap_64(uint64_t __x)
+{
+       return (__bswap_32(__x)+(0ULL<<32)) | __bswap_32(__x>>32);
+}
+
+#define bswap_16(x) __bswap_16(x)
+#define bswap_32(x) __bswap_32(x)
+#define bswap_64(x) __bswap_64(x)
+
+uint16_t htons(uint16_t n);
+uint32_t htonl(uint32_t n);
+uint16_t ntohs(uint16_t n);
+uint32_t ntohl(uint32_t n);
+
+#endif /* __INET_H */
index e45a79dac31f2a18390e201435be03ab0d935248..f28c4207ed9efdc911f347f57b6c93361a929b95 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include <limits.h>
+#include <inet.h>
 
 /**
  * strchr - Find the first occurrence of a character in a string
@@ -732,3 +733,27 @@ void abort(void)
        printf("Aborted.");
        while(1);
 }
+
+uint32_t htonl(uint32_t n)
+{
+       union { int i; char c; } u = { 1 };
+       return u.c ? bswap_32(n) : n;
+}
+
+uint16_t htons(uint16_t n)
+{
+       union { int i; char c; } u = { 1 };
+       return u.c ? bswap_16(n) : n;
+}
+
+uint32_t ntohl(uint32_t n)
+{
+       union { int i; char c; } u = { 1 };
+       return u.c ? bswap_32(n) : n;
+}
+
+uint16_t ntohs(uint16_t n)
+{
+       union { int i; char c; } u = { 1 };
+       return u.c ? bswap_16(n) : n;
+}
index 6372a37ca27f3b7761b6a21e1753ed0f1e24757c..b54107101bf950eb9b723053318935fee3697549 100644 (file)
@@ -2,6 +2,7 @@
 #ifdef CSR_ETHMAC_BASE
 
 #include <stdio.h>
+#include <inet.h>
 #include <system.h>
 #include <crc.h>
 #include <hw/flags.h>
@@ -41,7 +42,7 @@ static void fill_eth_header(struct ethernet_header *h, const unsigned char *dest
                h->destmac[i] = destmac[i];
        for(i=0;i<6;i++)
                h->srcmac[i] = srcmac[i];
-       h->ethertype = ethertype;
+       h->ethertype = htons(ethertype);
 }
 
 #define ARP_HWTYPE_ETHERNET 0x0001
@@ -133,8 +134,9 @@ static void send_packet(void)
        txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8;
        txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16;
        txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24;
-       txlen += 4;
+       //txlen += 4;
 #endif
+       txlen += 4; // FIXME
 
 #ifdef DEBUG_MICROUDP_TX
        int j;
@@ -167,21 +169,22 @@ static void process_arp(void)
        const struct arp_frame *rx_arp = &rxbuffer->frame.contents.arp;
        struct arp_frame *tx_arp = &txbuffer->frame.contents.arp;
 
-       if(rxlen < ARP_PACKET_LENGTH) return;
-       if(rx_arp->hwtype != ARP_HWTYPE_ETHERNET) return;
-       if(rx_arp->proto != ARP_PROTO_IP) return;
+       //if(rxlen < ARP_PACKET_LENGTH) return; // FIXME
+       if(ntohs(rx_arp->hwtype) != ARP_HWTYPE_ETHERNET) return;
+       if(ntohs(rx_arp->proto) != ARP_PROTO_IP) return;
        if(rx_arp->hwsize != 6) return;
        if(rx_arp->protosize != 4) return;
-       if(rx_arp->opcode == ARP_OPCODE_REPLY) {
-               if(rx_arp->sender_ip == cached_ip) {
+
+       if(ntohs(rx_arp->opcode) == ARP_OPCODE_REPLY) {
+               if(ntohl(rx_arp->sender_ip) == cached_ip) {
                        int i;
                        for(i=0;i<6;i++)
                                cached_mac[i] = rx_arp->sender_mac[i];
                }
                return;
        }
-       if(rx_arp->opcode == ARP_OPCODE_REQUEST) {
-               if(rx_arp->target_ip == my_ip) {
+       if(ntohs(rx_arp->opcode) == ARP_OPCODE_REQUEST) {
+               if(ntohl(rx_arp->target_ip) == my_ip) {
                        int i;
 
                        fill_eth_header(&txbuffer->frame.eth_header,
@@ -189,15 +192,15 @@ static void process_arp(void)
                                my_mac,
                                ETHERTYPE_ARP);
                        txlen = ARP_PACKET_LENGTH;
-                       tx_arp->hwtype = ARP_HWTYPE_ETHERNET;
-                       tx_arp->proto = ARP_PROTO_IP;
+                       tx_arp->hwtype = htons(ARP_HWTYPE_ETHERNET);
+                       tx_arp->proto = htons(ARP_PROTO_IP);
                        tx_arp->hwsize = 6;
                        tx_arp->protosize = 4;
-                       tx_arp->opcode = ARP_OPCODE_REPLY;
-                       tx_arp->sender_ip = my_ip;
+                       tx_arp->opcode = htons(ARP_OPCODE_REPLY);
+                       tx_arp->sender_ip = htonl(my_ip);
                        for(i=0;i<6;i++)
                                tx_arp->sender_mac[i] = my_mac[i];
-                       tx_arp->target_ip = rx_arp->sender_ip;
+                       tx_arp->target_ip = htonl(ntohl(rx_arp->sender_ip));
                        for(i=0;i<6;i++)
                                tx_arp->target_mac[i] = rx_arp->sender_mac[i];
                        send_packet();
@@ -210,7 +213,7 @@ static const unsigned char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 int microudp_arp_resolve(unsigned int ip)
 {
-       struct arp_frame *arp = &txbuffer->frame.contents.arp;
+       struct arp_frame *arp;
        int i;
        int tries;
        int timeout;
@@ -230,17 +233,19 @@ int microudp_arp_resolve(unsigned int ip)
                                my_mac,
                                ETHERTYPE_ARP);
                txlen = ARP_PACKET_LENGTH;
-               arp->hwtype = ARP_HWTYPE_ETHERNET;
-               arp->proto = ARP_PROTO_IP;
+               arp = &txbuffer->frame.contents.arp;
+               arp->hwtype = htons(ARP_HWTYPE_ETHERNET);
+               arp->proto = htons(ARP_PROTO_IP);
                arp->hwsize = 6;
                arp->protosize = 4;
-               arp->opcode = ARP_OPCODE_REQUEST;
-               arp->sender_ip = my_ip;
+               arp->opcode = htons(ARP_OPCODE_REQUEST);
+               arp->sender_ip = htonl(my_ip);
                for(i=0;i<6;i++)
                        arp->sender_mac[i] = my_mac[i];
-               arp->target_ip = ip;
+               arp->target_ip = htonl(ip);
                for(i=0;i<6;i++)
                        arp->target_mac[i] = 0;
+
                send_packet();
 
                /* Do we get a reply ? */
@@ -309,20 +314,20 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
 
        txbuffer->frame.contents.udp.ip.version = IP_IPV4;
        txbuffer->frame.contents.udp.ip.diff_services = 0;
-       txbuffer->frame.contents.udp.ip.total_length = length + sizeof(struct udp_frame);
-       txbuffer->frame.contents.udp.ip.identification = 0;
-       txbuffer->frame.contents.udp.ip.fragment_offset = IP_DONT_FRAGMENT;
+       txbuffer->frame.contents.udp.ip.total_length = htons(length + sizeof(struct udp_frame));
+       txbuffer->frame.contents.udp.ip.identification = htons(0);
+       txbuffer->frame.contents.udp.ip.fragment_offset = htons(IP_DONT_FRAGMENT);
        txbuffer->frame.contents.udp.ip.ttl = IP_TTL;
        h.proto = txbuffer->frame.contents.udp.ip.proto = IP_PROTO_UDP;
        txbuffer->frame.contents.udp.ip.checksum = 0;
-       h.src_ip = txbuffer->frame.contents.udp.ip.src_ip = my_ip;
-       h.dst_ip = txbuffer->frame.contents.udp.ip.dst_ip = cached_ip;
-       txbuffer->frame.contents.udp.ip.checksum = ip_checksum(0, &txbuffer->frame.contents.udp.ip,
-               sizeof(struct ip_header), 1);
-
-       txbuffer->frame.contents.udp.udp.src_port = src_port;
-       txbuffer->frame.contents.udp.udp.dst_port = dst_port;
-       h.length = txbuffer->frame.contents.udp.udp.length = length + sizeof(struct udp_header);
+       h.src_ip = txbuffer->frame.contents.udp.ip.src_ip = htonl(my_ip);
+       h.dst_ip = txbuffer->frame.contents.udp.ip.dst_ip = htonl(cached_ip);
+       txbuffer->frame.contents.udp.ip.checksum = htons(ip_checksum(0, &txbuffer->frame.contents.udp.ip,
+               sizeof(struct ip_header), 1));
+
+       txbuffer->frame.contents.udp.udp.src_port = htons(src_port);
+       txbuffer->frame.contents.udp.udp.dst_port = htons(dst_port);
+       h.length = txbuffer->frame.contents.udp.udp.length = htons(length + sizeof(struct udp_header));
        txbuffer->frame.contents.udp.udp.checksum = 0;
 
        h.zero = 0;
@@ -333,7 +338,7 @@ int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int
        }
        r = ip_checksum(r, &txbuffer->frame.contents.udp.udp,
                sizeof(struct udp_header)+length, 1);
-       txbuffer->frame.contents.udp.udp.checksum = r;
+       txbuffer->frame.contents.udp.udp.checksum = htons(r);
 
        send_packet();
 
@@ -345,19 +350,21 @@ static udp_callback rx_callback;
 static void process_ip(void)
 {
        if(rxlen < (sizeof(struct ethernet_header)+sizeof(struct udp_frame))) return;
+       struct udp_frame *udp_ip = &rxbuffer->frame.contents.udp;
        /* We don't verify UDP and IP checksums and rely on the Ethernet checksum solely */
-       if(rxbuffer->frame.contents.udp.ip.version != IP_IPV4) return;
+       if(udp_ip->ip.version != IP_IPV4) return;
        // check disabled for QEMU compatibility
        //if(rxbuffer->frame.contents.udp.ip.diff_services != 0) return;
-       if(rxbuffer->frame.contents.udp.ip.total_length < sizeof(struct udp_frame)) return;
+       if(ntohs(udp_ip->ip.total_length) < sizeof(struct udp_frame)) return;
        // check disabled for QEMU compatibility
-       //if(rxbuffer->frame.contents.udp.ip.fragment_offset != IP_DONT_FRAGMENT) return;
-       if(rxbuffer->frame.contents.udp.ip.proto != IP_PROTO_UDP) return;
-       if(rxbuffer->frame.contents.udp.ip.dst_ip != my_ip) return;
-       if(rxbuffer->frame.contents.udp.udp.length < sizeof(struct udp_header)) return;
+       //if(ntohs(rxbuffer->frame.contents.udp.ip.fragment_offset) != IP_DONT_FRAGMENT) return;
+       if(udp_ip->ip.proto != IP_PROTO_UDP) return;
+       if(ntohl(udp_ip->ip.dst_ip) != my_ip) return;
+       if(ntohs(udp_ip->udp.length) < sizeof(struct udp_header)) return;
 
        if(rx_callback)
-               rx_callback(rxbuffer->frame.contents.udp.ip.src_ip, rxbuffer->frame.contents.udp.udp.src_port, rxbuffer->frame.contents.udp.udp.dst_port, rxbuffer->frame.contents.udp.payload, rxbuffer->frame.contents.udp.udp.length-sizeof(struct udp_header));
+               rx_callback(ntohl(udp_ip->ip.src_ip), ntohs(udp_ip->udp.src_port), ntohs(udp_ip->udp.dst_port),
+                           udp_ip->payload, ntohs(udp_ip->udp.length)-sizeof(struct udp_header));
 }
 
 void microudp_set_callback(udp_callback callback)
@@ -397,8 +404,8 @@ static void process_frame(void)
        rxlen -= 4; /* strip CRC here to be consistent with TX */
 #endif
 
-       if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_ARP) process_arp();
-       else if(rxbuffer->frame.eth_header.ethertype == ETHERTYPE_IP) process_ip();
+       if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_ARP) process_arp();
+       else if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_IP) process_ip();
 }
 
 void microudp_start(const unsigned char *macaddr, unsigned int ip)