From: Florent Kermarrec Date: Mon, 18 May 2020 19:04:54 +0000 (+0200) Subject: software/bios: rename libnet to libliteeth and move all ethernet files to it. X-Git-Tag: 24jan2021_ls180~328^2~9 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=70a67ce7ed0791eb79eb05d075f310612f9f50fb;p=litex.git software/bios: rename libnet to libliteeth and move all ethernet files to it. --- diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index 4fd1b233..79c6b95d 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -25,7 +25,7 @@ __all__ = ["soc_software_packages", "soc_directory", soc_software_packages = [ "libcompiler_rt", "libbase", - "libnet", + "libliteeth", "bios" ] diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index ac7725e6..8d4090b7 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -59,15 +59,15 @@ endif bios.elf: $(BIOS_DIRECTORY)/linker.ld $(OBJECTS) -%.elf: ../libbase/crt0-ctr.o ../libnet/libnet.a ../libbase/libbase-nofloat.a ../libcompiler_rt/libcompiler_rt.a +%.elf: ../libbase/crt0-ctr.o ../libliteeth/libliteeth.a ../libbase/libbase-nofloat.a ../libcompiler_rt/libcompiler_rt.a $(LD) $(LDFLAGS) -T $(BIOS_DIRECTORY)/linker.ld -N -o $@ \ ../libbase/crt0-ctr.o \ $(OBJECTS) \ - -L../libnet \ + -L../libliteeth \ -L../libbase \ -L../libcompiler_rt \ $(BP_LIBS) \ - -lnet -lbase-nofloat -lcompiler_rt \ + -lliteeth -lbase-nofloat -lcompiler_rt \ $(BP_FLAGS) ifneq ($(OS),Windows_NT) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index c12cfe25..36993a6f 100644 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -21,8 +21,8 @@ #include #ifdef CSR_ETHMAC_BASE -#include -#include +#include +#include #endif #ifdef CSR_SPIFLASH_BASE @@ -340,7 +340,7 @@ void netboot(void) ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4); - microudp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4)); + udp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4)); tftp_port = TFTP_SERVER_PORT; printf("Fetching from: UDP/%d\n", tftp_port); diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 7864260a..a9857c88 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -30,7 +30,7 @@ #include #ifdef CSR_ETHMAC_BASE -#include +#include "udp.h" #endif #ifdef CSR_SPIFLASH_BASE diff --git a/litex/soc/software/common.mak b/litex/soc/software/common.mak index 83f1aba4..fb97fc48 100644 --- a/litex/soc/software/common.mak +++ b/litex/soc/software/common.mak @@ -45,7 +45,12 @@ DEPFLAGS += -MD -MP # Toolchain options # -INCLUDES = -I$(SOC_DIRECTORY)/software/include/base -I$(SOC_DIRECTORY)/software/include -I$(SOC_DIRECTORY)/common -I$(BUILDINC_DIRECTORY) -I$(CPU_DIRECTORY) +INCLUDES = -I$(SOC_DIRECTORY)/software/include/base \ + -I$(SOC_DIRECTORY)/software/include \ + -I$(SOC_DIRECTORY)/common \ + -I$(BUILDINC_DIRECTORY) \ + -I$(CPU_DIRECTORY) \ + -I$(SOC_DIRECTORY)/software/libliteeth COMMONFLAGS = $(DEPFLAGS) -Os $(CPUFLAGS) -g3 -fomit-frame-pointer -Wall -fno-builtin -nostdinc $(INCLUDES) CFLAGS = $(COMMONFLAGS) -fexceptions -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes CXXFLAGS = $(COMMONFLAGS) -std=c++11 -I$(SOC_DIRECTORY)/software/include/basec++ -fexceptions -fno-rtti -ffreestanding diff --git a/litex/soc/software/include/net/microudp.h b/litex/soc/software/include/net/microudp.h deleted file mode 100644 index f148a341..00000000 --- a/litex/soc/software/include/net/microudp.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __MICROUDP_H -#define __MICROUDP_H - -#define IPTOINT(a, b, c, d) ((a << 24)|(b << 16)|(c << 8)|d) - -#define MICROUDP_BUFSIZE (5*1532) - -typedef void (*udp_callback)(unsigned int src_ip, unsigned short src_port, unsigned short dst_port, void *data, unsigned int length); - -void microudp_start(const unsigned char *macaddr, unsigned int ip); -int microudp_arp_resolve(unsigned int ip); -void *microudp_get_tx_buffer(void); -int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int length); -void microudp_set_callback(udp_callback callback); -void microudp_service(void); - -void eth_init(void); -void eth_mode(void); - -#endif /* __MICROUDP_H */ diff --git a/litex/soc/software/include/net/tftp.h b/litex/soc/software/include/net/tftp.h deleted file mode 100644 index 788731ba..00000000 --- a/litex/soc/software/include/net/tftp.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __TFTP_H -#define __TFTP_H - -#include - -int tftp_get(uint32_t ip, uint16_t server_port, const char *filename, - void *buffer); -int tftp_put(uint32_t ip, uint16_t server_port, const char *filename, - const void *buffer, int size); - -#endif /* __TFTP_H */ - diff --git a/litex/soc/software/libliteeth/Makefile b/litex/soc/software/libliteeth/Makefile new file mode 100644 index 00000000..593acc20 --- /dev/null +++ b/litex/soc/software/libliteeth/Makefile @@ -0,0 +1,23 @@ +include ../include/generated/variables.mak +include $(SOC_DIRECTORY)/software/common.mak + +OBJECTS=udp.o tftp.o + +all: libliteeth.a + +libliteeth.a: $(OBJECTS) + $(AR) crs libliteeth.a $(OBJECTS) + +# pull in dependency info for *existing* .o files +-include $(OBJECTS:.o=.d) + +%.o: $(LIBLITEETH_DIRECTORY)/%.c + $(compile) + +%.o: %.S + $(assemble) + +.PHONY: all clean + +clean: + $(RM) $(OBJECTS) libliteeth.a .*~ *~ diff --git a/litex/soc/software/libliteeth/tftp.c b/litex/soc/software/libliteeth/tftp.c new file mode 100644 index 00000000..c5ac5f38 --- /dev/null +++ b/litex/soc/software/libliteeth/tftp.c @@ -0,0 +1,236 @@ +// This file is Copyright (c) 2013 Werner Almesberger +// This file is Copyright (c) 2013-2015 Sebastien Bourdeauducq +// This file is Copyright (c) 2014-2015 Florent Kermarec +// This file is Copyright (c) 2017 Greg Darke +// This file is Copyright (c) 2018 Ewen McNeill + +// License: BSD + +#include +#include +#include + +#include "udp.h" +#include "tftp.h" + +/* Local TFTP client port (arbitrary) */ +#define PORT_IN 7642 + +enum { + TFTP_RRQ = 1, /* Read request */ + TFTP_WRQ = 2, /* Write request */ + TFTP_DATA = 3, /* Data */ + TFTP_ACK = 4, /* Acknowledgment */ + TFTP_ERROR = 5, /* Error */ +}; + +#define BLOCK_SIZE 512 /* block size in bytes */ + + +static int format_request(uint8_t *buf, uint16_t op, const char *filename) +{ + int len = strlen(filename); + + *buf++ = op >> 8; /* Opcode */ + *buf++ = op; + memcpy(buf, filename, len); + buf += len; + *buf++ = 0x00; + *buf++ = 'o'; + *buf++ = 'c'; + *buf++ = 't'; + *buf++ = 'e'; + *buf++ = 't'; + *buf++ = 0x00; + return 9+strlen(filename); +} + +static int format_ack(uint8_t *buf, uint16_t block) +{ + *buf++ = 0x00; /* Opcode: Ack */ + *buf++ = TFTP_ACK; + *buf++ = (block & 0xff00) >> 8; + *buf++ = (block & 0x00ff); + return 4; +} + +static int format_data(uint8_t *buf, uint16_t block, const void *data, int len) +{ + *buf++ = 0x00; /* Opcode: Data*/ + *buf++ = TFTP_DATA; + *buf++ = (block & 0xff00) >> 8; + *buf++ = (block & 0x00ff); + memcpy(buf, data, len); + return len+4; +} + +static uint8_t *packet_data; +static int total_length; +static int transfer_finished; +static uint8_t *dst_buffer; +static int last_ack; /* signed, so we can use -1 */ +static uint16_t data_port; + +static void rx_callback(uint32_t src_ip, uint16_t src_port, + uint16_t dst_port, void *_data, unsigned int length) +{ + uint8_t *data = _data; + uint16_t opcode; + uint16_t block; + int i; + int offset; + + if(length < 4) return; + if(dst_port != PORT_IN) return; + opcode = data[0] << 8 | data[1]; + block = data[2] << 8 | data[3]; + if(opcode == TFTP_ACK) { /* Acknowledgement */ + data_port = src_port; + last_ack = block; + return; + } + if(block < 1) return; + if(opcode == TFTP_DATA) { /* Data */ + length -= 4; + offset = (block-1)*BLOCK_SIZE; + for(i=0;i 0) || transfer_finished) break; + } + if((total_length > 0) || transfer_finished) break; + tries--; + if(tries == 0) { + udp_set_callback(NULL); + return -1; + } + } + + i = 12000000; + length_before = total_length; + while(!transfer_finished) { + if(length_before != total_length) { + i = 12000000; + length_before = total_length; + if ((total_length & 0x7fff) == 0) { // every 32K + putchar("|/-\\"[spin++ % 4]); + putchar('\b'); + } + } + if(i-- == 0) { + udp_set_callback(NULL); + return -1; + } + udp_service(); + } + + udp_set_callback(NULL); + + return total_length; +} + +int tftp_put(uint32_t ip, uint16_t server_port, const char *filename, + const void *buffer, int size) +{ + int len, send; + int tries; + int i; + int block = 0, sent = 0; + + if(!udp_arp_resolve(ip)) + return -1; + + udp_set_callback(rx_callback); + + packet_data = udp_get_tx_buffer(); + + total_length = 0; + transfer_finished = 0; + tries = 5; + while(1) { + packet_data = udp_get_tx_buffer(); + len = format_request(packet_data, TFTP_WRQ, filename); + udp_send(PORT_IN, server_port, len); + for(i=0;i<2000000;i++) { + last_ack = -1; + udp_service(); + if(last_ack == block) + goto send_data; + if(transfer_finished) + goto fail; + } + tries--; + if(tries == 0) + goto fail; + } + +send_data: + do { + block++; + send = sent+BLOCK_SIZE > size ? size-sent : BLOCK_SIZE; + tries = 5; + while(1) { + packet_data = udp_get_tx_buffer(); + len = format_data(packet_data, block, buffer, send); + udp_send(PORT_IN, data_port, len); + for(i=0;i<12000000;i++) { + udp_service(); + if(transfer_finished) + goto fail; + if(last_ack == block) + goto next; + } + if (!--tries) + goto fail; + } +next: + sent += send; + buffer += send; + } while (send == BLOCK_SIZE); + + udp_set_callback(NULL); + + return sent; + +fail: + udp_set_callback(NULL); + return -1; +} diff --git a/litex/soc/software/libliteeth/tftp.h b/litex/soc/software/libliteeth/tftp.h new file mode 100644 index 00000000..788731ba --- /dev/null +++ b/litex/soc/software/libliteeth/tftp.h @@ -0,0 +1,12 @@ +#ifndef __TFTP_H +#define __TFTP_H + +#include + +int tftp_get(uint32_t ip, uint16_t server_port, const char *filename, + void *buffer); +int tftp_put(uint32_t ip, uint16_t server_port, const char *filename, + const void *buffer, int size); + +#endif /* __TFTP_H */ + diff --git a/litex/soc/software/libliteeth/udp.c b/litex/soc/software/libliteeth/udp.c new file mode 100644 index 00000000..d8696213 --- /dev/null +++ b/litex/soc/software/libliteeth/udp.c @@ -0,0 +1,474 @@ +// This file is Copyright (c) 2013 Werner Almesberger +// This file is Copyright (c) 2014-2015 Sebastien Bourdeauducq +// This file is Copyright (c) 2014-2019 Florent Kermarrec +// This file is Copyright (c) 2018 Jean-François Nguyen +// This file is Copyright (c) 2013 Robert Jordens +// License: BSD + +#include +#include + +#ifdef CSR_ETHMAC_BASE + +#include +#include +#include +#include +#include + +#include "udp.h" + +//#define DEBUG_UDP_TX +//#define DEBUG_UDP_RX + +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_IP 0x0800 + +#ifdef CSR_ETHMAC_PREAMBLE_CRC_ADDR +#define HW_PREAMBLE_CRC +#endif + +struct ethernet_header { +#ifndef HW_PREAMBLE_CRC + unsigned char preamble[8]; +#endif + unsigned char destmac[6]; + unsigned char srcmac[6]; + unsigned short ethertype; +} __attribute__((packed)); + +static void fill_eth_header(struct ethernet_header *h, const unsigned char *destmac, const unsigned char *srcmac, unsigned short ethertype) +{ + int i; + +#ifndef HW_PREAMBLE_CRC + for(i=0;i<7;i++) + h->preamble[i] = 0x55; + h->preamble[7] = 0xd5; +#endif + for(i=0;i<6;i++) + h->destmac[i] = destmac[i]; + for(i=0;i<6;i++) + h->srcmac[i] = srcmac[i]; + h->ethertype = htons(ethertype); +} + +#define ARP_HWTYPE_ETHERNET 0x0001 +#define ARP_PROTO_IP 0x0800 +#ifndef HW_PREAMBLE_CRC +#define ARP_PACKET_LENGTH 68 +#else +#define ARP_PACKET_LENGTH 60 +#endif + +#define ARP_OPCODE_REQUEST 0x0001 +#define ARP_OPCODE_REPLY 0x0002 + +struct arp_frame { + unsigned short hwtype; + unsigned short proto; + unsigned char hwsize; + unsigned char protosize; + unsigned short opcode; + unsigned char sender_mac[6]; + unsigned int sender_ip; + unsigned char target_mac[6]; + unsigned int target_ip; + unsigned char padding[18]; +} __attribute__((packed)); + +#define IP_IPV4 0x45 +#define IP_DONT_FRAGMENT 0x4000 +#define IP_TTL 64 +#define IP_PROTO_UDP 0x11 + +struct ip_header { + unsigned char version; + unsigned char diff_services; + unsigned short total_length; + unsigned short identification; + unsigned short fragment_offset; + unsigned char ttl; + unsigned char proto; + unsigned short checksum; + unsigned int src_ip; + unsigned int dst_ip; +} __attribute__((packed)); + +struct udp_header { + unsigned short src_port; + unsigned short dst_port; + unsigned short length; + unsigned short checksum; +} __attribute__((packed)); + +struct udp_frame { + struct ip_header ip; + struct udp_header udp; + char payload[]; +} __attribute__((packed)); + +struct ethernet_frame { + struct ethernet_header eth_header; + union { + struct arp_frame arp; + struct udp_frame udp; + } contents; +} __attribute__((packed)); + +typedef union { + struct ethernet_frame frame; + unsigned char raw[ETHMAC_SLOT_SIZE]; +} ethernet_buffer; + +static unsigned int rxslot; +static unsigned int rxlen; +static ethernet_buffer *rxbuffer; + +static unsigned int txslot; +static unsigned int txlen; +static ethernet_buffer *txbuffer; + +static void send_packet(void) +{ + /* wait buffer to be available */ + while(!(ethmac_sram_reader_ready_read())); + + /* fill txbuffer */ +#ifndef HW_PREAMBLE_CRC + unsigned int crc; + crc = crc32(&txbuffer->raw[8], txlen-8); + txbuffer->raw[txlen ] = (crc & 0xff); + txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8; + txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16; + txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24; + txlen += 4; +#endif + +#ifdef DEBUG_LITEETH_UDP_TX + int j; + printf(">>>> txlen : %d\n", txlen); + for(j=0;jraw[j]); + printf("\n"); +#endif + + /* fill slot, length and send */ + ethmac_sram_reader_slot_write(txslot); + ethmac_sram_reader_length_write(txlen); + ethmac_sram_reader_start_write(1); + + /* update txslot / txbuffer */ + txslot = (txslot+1)%ETHMAC_TX_SLOTS; + txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot)); +} + +static unsigned char my_mac[6]; +static unsigned int my_ip; + +/* ARP cache - one entry only */ +static unsigned char cached_mac[6]; +static unsigned int cached_ip; + +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(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(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(ntohs(rx_arp->opcode) == ARP_OPCODE_REQUEST) { + if(ntohl(rx_arp->target_ip) == my_ip) { + int i; + + fill_eth_header(&txbuffer->frame.eth_header, + rx_arp->sender_mac, + my_mac, + ETHERTYPE_ARP); + txlen = ARP_PACKET_LENGTH; + 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 = 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 = htonl(ntohl(rx_arp->sender_ip)); + for(i=0;i<6;i++) + tx_arp->target_mac[i] = rx_arp->sender_mac[i]; + send_packet(); + } + return; + } +} + +static const unsigned char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +int udp_arp_resolve(unsigned int ip) +{ + struct arp_frame *arp; + int i; + int tries; + int timeout; + + if(cached_ip == ip) { + for(i=0;i<6;i++) + if(cached_mac[i]) return 1; + } + cached_ip = ip; + for(i=0;i<6;i++) + cached_mac[i] = 0; + + for(tries=0;tries<100;tries++) { + /* Send an ARP request */ + fill_eth_header(&txbuffer->frame.eth_header, + broadcast, + my_mac, + ETHERTYPE_ARP); + txlen = ARP_PACKET_LENGTH; + 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 = 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 = htonl(ip); + for(i=0;i<6;i++) + arp->target_mac[i] = 0; + + send_packet(); + + /* Do we get a reply ? */ + for(timeout=0;timeout<100000;timeout++) { + udp_service(); + for(i=0;i<6;i++) + if(cached_mac[i]) return 1; + } + } + + return 0; +} + +static unsigned short ip_checksum(unsigned int r, void *buffer, unsigned int length, int complete) +{ + unsigned char *ptr; + unsigned int i; + + ptr = (unsigned char *)buffer; + length >>= 1; + + for(i=0;i> 16) + r = (r & 0xffff) + (r >> 16); + + if(complete) { + r = ~r; + r &= 0xffff; + if(r == 0) r = 0xffff; + } + return r; +} + +void *udp_get_tx_buffer(void) +{ + return txbuffer->frame.contents.udp.payload; +} + +struct pseudo_header { + unsigned int src_ip; + unsigned int dst_ip; + unsigned char zero; + unsigned char proto; + unsigned short length; +} __attribute__((packed)); + +int udp_send(unsigned short src_port, unsigned short dst_port, unsigned int length) +{ + struct pseudo_header h; + unsigned int r; + + if((cached_mac[0] == 0) && (cached_mac[1] == 0) && (cached_mac[2] == 0) + && (cached_mac[3] == 0) && (cached_mac[4] == 0) && (cached_mac[5] == 0)) + return 0; + + txlen = length + sizeof(struct ethernet_header) + sizeof(struct udp_frame); + if(txlen < ARP_PACKET_LENGTH) txlen = ARP_PACKET_LENGTH; + + fill_eth_header(&txbuffer->frame.eth_header, + cached_mac, + my_mac, + ETHERTYPE_IP); + + txbuffer->frame.contents.udp.ip.version = IP_IPV4; + txbuffer->frame.contents.udp.ip.diff_services = 0; + 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 = 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; + r = ip_checksum(0, &h, sizeof(struct pseudo_header), 0); + if(length & 1) { + txbuffer->frame.contents.udp.payload[length] = 0; + length++; + } + r = ip_checksum(r, &txbuffer->frame.contents.udp.udp, + sizeof(struct udp_header)+length, 1); + txbuffer->frame.contents.udp.udp.checksum = htons(r); + + send_packet(); + + return 1; +} + +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(udp_ip->ip.version != IP_IPV4) return; + // check disabled for QEMU compatibility + //if(rxbuffer->frame.contents.udp.ip.diff_services != 0) return; + if(ntohs(udp_ip->ip.total_length) < sizeof(struct udp_frame)) return; + // check disabled for QEMU compatibility + //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(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 udp_set_callback(udp_callback callback) +{ + rx_callback = callback; +} + +static void process_frame(void) +{ + flush_cpu_dcache(); + +#ifdef DEBUG_LITEETH_UDP_RX + int j; + printf("<<< rxlen : %d\n", rxlen); + for(j=0;jraw[j]); + printf("\n"); +#endif + +#ifndef HW_PREAMBLE_CRC + int i; + for(i=0;i<7;i++) + if(rxbuffer->frame.eth_header.preamble[i] != 0x55) return; + if(rxbuffer->frame.eth_header.preamble[7] != 0xd5) return; +#endif + +#ifndef HW_PREAMBLE_CRC + unsigned int received_crc; + unsigned int computed_crc; + received_crc = ((unsigned int)rxbuffer->raw[rxlen-1] << 24) + |((unsigned int)rxbuffer->raw[rxlen-2] << 16) + |((unsigned int)rxbuffer->raw[rxlen-3] << 8) + |((unsigned int)rxbuffer->raw[rxlen-4]); + computed_crc = crc32(&rxbuffer->raw[8], rxlen-12); + if(received_crc != computed_crc) return; + + rxlen -= 4; /* strip CRC here to be consistent with TX */ +#endif + + if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_ARP) process_arp(); + else if(ntohs(rxbuffer->frame.eth_header.ethertype) == ETHERTYPE_IP) process_ip(); +} + +void udp_start(const unsigned char *macaddr, unsigned int ip) +{ + int i; + ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER); + ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); + + for(i=0;i<6;i++) + my_mac[i] = macaddr[i]; + my_ip = ip; + + cached_ip = 0; + for(i=0;i<6;i++) + cached_mac[i] = 0; + + txslot = 0; + ethmac_sram_reader_slot_write(txslot); + txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot)); + + rxslot = 0; + rxbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * rxslot); + rx_callback = (udp_callback)0; +} + +void udp_service(void) +{ + if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) { + rxslot = ethmac_sram_writer_slot_read(); + rxbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * rxslot); + rxlen = ethmac_sram_writer_length_read(); + process_frame(); + ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); + } +} + +void eth_init(void) +{ + printf("Ethernet init...\n"); +#ifdef CSR_ETHPHY_CRG_RESET_ADDR + ethphy_crg_reset_write(1); + busy_wait(200); + ethphy_crg_reset_write(0); + busy_wait(200); +#endif +} + +#ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR +void eth_mode(void) +{ + printf("Ethernet phy mode: "); + if (ethphy_mode_detection_mode_read()) + printf("MII"); + else + printf("GMII"); + printf("\n"); +} +#endif + +#endif diff --git a/litex/soc/software/libliteeth/udp.h b/litex/soc/software/libliteeth/udp.h new file mode 100644 index 00000000..132ef76d --- /dev/null +++ b/litex/soc/software/libliteeth/udp.h @@ -0,0 +1,20 @@ +#ifndef __UDP_H +#define __UDP_H + +#define IPTOINT(a, b, c, d) ((a << 24)|(b << 16)|(c << 8)|d) + +#define UDP_BUFSIZE (5*1532) + +typedef void (*udp_callback)(unsigned int src_ip, unsigned short src_port, unsigned short dst_port, void *data, unsigned int length); + +void udp_start(const unsigned char *macaddr, unsigned int ip); +int udp_arp_resolve(unsigned int ip); +void *udp_get_tx_buffer(void); +int udp_send(unsigned short src_port, unsigned short dst_port, unsigned int length); +void udp_set_callback(udp_callback callback); +void udp_service(void); + +void eth_init(void); +void eth_mode(void); + +#endif /* __UDP_H */ diff --git a/litex/soc/software/libnet/Makefile b/litex/soc/software/libnet/Makefile deleted file mode 100644 index 188e48d6..00000000 --- a/litex/soc/software/libnet/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -include ../include/generated/variables.mak -include $(SOC_DIRECTORY)/software/common.mak - -OBJECTS=microudp.o tftp.o - -all: libnet.a - -libnet.a: $(OBJECTS) - $(AR) crs libnet.a $(OBJECTS) - -# pull in dependency info for *existing* .o files --include $(OBJECTS:.o=.d) - -%.o: $(LIBNET_DIRECTORY)/%.c - $(compile) - -%.o: %.S - $(assemble) - -.PHONY: all clean - -clean: - $(RM) $(OBJECTS) libnet.a .*~ *~ diff --git a/litex/soc/software/libnet/microudp.c b/litex/soc/software/libnet/microudp.c deleted file mode 100644 index 3199456e..00000000 --- a/litex/soc/software/libnet/microudp.c +++ /dev/null @@ -1,474 +0,0 @@ -// This file is Copyright (c) 2013 Werner Almesberger -// This file is Copyright (c) 2014-2015 Sebastien Bourdeauducq -// This file is Copyright (c) 2014-2019 Florent Kermarrec -// This file is Copyright (c) 2018 Jean-François Nguyen -// This file is Copyright (c) 2013 Robert Jordens -// License: BSD - -#include -#include - -#ifdef CSR_ETHMAC_BASE - -#include -#include -#include -#include -#include - -#include - -//#define DEBUG_MICROUDP_TX -//#define DEBUG_MICROUDP_RX - -#define ETHERTYPE_ARP 0x0806 -#define ETHERTYPE_IP 0x0800 - -#ifdef CSR_ETHMAC_PREAMBLE_CRC_ADDR -#define HW_PREAMBLE_CRC -#endif - -struct ethernet_header { -#ifndef HW_PREAMBLE_CRC - unsigned char preamble[8]; -#endif - unsigned char destmac[6]; - unsigned char srcmac[6]; - unsigned short ethertype; -} __attribute__((packed)); - -static void fill_eth_header(struct ethernet_header *h, const unsigned char *destmac, const unsigned char *srcmac, unsigned short ethertype) -{ - int i; - -#ifndef HW_PREAMBLE_CRC - for(i=0;i<7;i++) - h->preamble[i] = 0x55; - h->preamble[7] = 0xd5; -#endif - for(i=0;i<6;i++) - h->destmac[i] = destmac[i]; - for(i=0;i<6;i++) - h->srcmac[i] = srcmac[i]; - h->ethertype = htons(ethertype); -} - -#define ARP_HWTYPE_ETHERNET 0x0001 -#define ARP_PROTO_IP 0x0800 -#ifndef HW_PREAMBLE_CRC -#define ARP_PACKET_LENGTH 68 -#else -#define ARP_PACKET_LENGTH 60 -#endif - -#define ARP_OPCODE_REQUEST 0x0001 -#define ARP_OPCODE_REPLY 0x0002 - -struct arp_frame { - unsigned short hwtype; - unsigned short proto; - unsigned char hwsize; - unsigned char protosize; - unsigned short opcode; - unsigned char sender_mac[6]; - unsigned int sender_ip; - unsigned char target_mac[6]; - unsigned int target_ip; - unsigned char padding[18]; -} __attribute__((packed)); - -#define IP_IPV4 0x45 -#define IP_DONT_FRAGMENT 0x4000 -#define IP_TTL 64 -#define IP_PROTO_UDP 0x11 - -struct ip_header { - unsigned char version; - unsigned char diff_services; - unsigned short total_length; - unsigned short identification; - unsigned short fragment_offset; - unsigned char ttl; - unsigned char proto; - unsigned short checksum; - unsigned int src_ip; - unsigned int dst_ip; -} __attribute__((packed)); - -struct udp_header { - unsigned short src_port; - unsigned short dst_port; - unsigned short length; - unsigned short checksum; -} __attribute__((packed)); - -struct udp_frame { - struct ip_header ip; - struct udp_header udp; - char payload[]; -} __attribute__((packed)); - -struct ethernet_frame { - struct ethernet_header eth_header; - union { - struct arp_frame arp; - struct udp_frame udp; - } contents; -} __attribute__((packed)); - -typedef union { - struct ethernet_frame frame; - unsigned char raw[ETHMAC_SLOT_SIZE]; -} ethernet_buffer; - -static unsigned int rxslot; -static unsigned int rxlen; -static ethernet_buffer *rxbuffer; - -static unsigned int txslot; -static unsigned int txlen; -static ethernet_buffer *txbuffer; - -static void send_packet(void) -{ - /* wait buffer to be available */ - while(!(ethmac_sram_reader_ready_read())); - - /* fill txbuffer */ -#ifndef HW_PREAMBLE_CRC - unsigned int crc; - crc = crc32(&txbuffer->raw[8], txlen-8); - txbuffer->raw[txlen ] = (crc & 0xff); - txbuffer->raw[txlen+1] = (crc & 0xff00) >> 8; - txbuffer->raw[txlen+2] = (crc & 0xff0000) >> 16; - txbuffer->raw[txlen+3] = (crc & 0xff000000) >> 24; - txlen += 4; -#endif - -#ifdef DEBUG_MICROUDP_TX - int j; - printf(">>>> txlen : %d\n", txlen); - for(j=0;jraw[j]); - printf("\n"); -#endif - - /* fill slot, length and send */ - ethmac_sram_reader_slot_write(txslot); - ethmac_sram_reader_length_write(txlen); - ethmac_sram_reader_start_write(1); - - /* update txslot / txbuffer */ - txslot = (txslot+1)%ETHMAC_TX_SLOTS; - txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot)); -} - -static unsigned char my_mac[6]; -static unsigned int my_ip; - -/* ARP cache - one entry only */ -static unsigned char cached_mac[6]; -static unsigned int cached_ip; - -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(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(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(ntohs(rx_arp->opcode) == ARP_OPCODE_REQUEST) { - if(ntohl(rx_arp->target_ip) == my_ip) { - int i; - - fill_eth_header(&txbuffer->frame.eth_header, - rx_arp->sender_mac, - my_mac, - ETHERTYPE_ARP); - txlen = ARP_PACKET_LENGTH; - 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 = 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 = htonl(ntohl(rx_arp->sender_ip)); - for(i=0;i<6;i++) - tx_arp->target_mac[i] = rx_arp->sender_mac[i]; - send_packet(); - } - return; - } -} - -static const unsigned char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -int microudp_arp_resolve(unsigned int ip) -{ - struct arp_frame *arp; - int i; - int tries; - int timeout; - - if(cached_ip == ip) { - for(i=0;i<6;i++) - if(cached_mac[i]) return 1; - } - cached_ip = ip; - for(i=0;i<6;i++) - cached_mac[i] = 0; - - for(tries=0;tries<100;tries++) { - /* Send an ARP request */ - fill_eth_header(&txbuffer->frame.eth_header, - broadcast, - my_mac, - ETHERTYPE_ARP); - txlen = ARP_PACKET_LENGTH; - 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 = 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 = htonl(ip); - for(i=0;i<6;i++) - arp->target_mac[i] = 0; - - send_packet(); - - /* Do we get a reply ? */ - for(timeout=0;timeout<100000;timeout++) { - microudp_service(); - for(i=0;i<6;i++) - if(cached_mac[i]) return 1; - } - } - - return 0; -} - -static unsigned short ip_checksum(unsigned int r, void *buffer, unsigned int length, int complete) -{ - unsigned char *ptr; - unsigned int i; - - ptr = (unsigned char *)buffer; - length >>= 1; - - for(i=0;i> 16) - r = (r & 0xffff) + (r >> 16); - - if(complete) { - r = ~r; - r &= 0xffff; - if(r == 0) r = 0xffff; - } - return r; -} - -void *microudp_get_tx_buffer(void) -{ - return txbuffer->frame.contents.udp.payload; -} - -struct pseudo_header { - unsigned int src_ip; - unsigned int dst_ip; - unsigned char zero; - unsigned char proto; - unsigned short length; -} __attribute__((packed)); - -int microudp_send(unsigned short src_port, unsigned short dst_port, unsigned int length) -{ - struct pseudo_header h; - unsigned int r; - - if((cached_mac[0] == 0) && (cached_mac[1] == 0) && (cached_mac[2] == 0) - && (cached_mac[3] == 0) && (cached_mac[4] == 0) && (cached_mac[5] == 0)) - return 0; - - txlen = length + sizeof(struct ethernet_header) + sizeof(struct udp_frame); - if(txlen < ARP_PACKET_LENGTH) txlen = ARP_PACKET_LENGTH; - - fill_eth_header(&txbuffer->frame.eth_header, - cached_mac, - my_mac, - ETHERTYPE_IP); - - txbuffer->frame.contents.udp.ip.version = IP_IPV4; - txbuffer->frame.contents.udp.ip.diff_services = 0; - 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 = 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; - r = ip_checksum(0, &h, sizeof(struct pseudo_header), 0); - if(length & 1) { - txbuffer->frame.contents.udp.payload[length] = 0; - length++; - } - r = ip_checksum(r, &txbuffer->frame.contents.udp.udp, - sizeof(struct udp_header)+length, 1); - txbuffer->frame.contents.udp.udp.checksum = htons(r); - - send_packet(); - - return 1; -} - -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(udp_ip->ip.version != IP_IPV4) return; - // check disabled for QEMU compatibility - //if(rxbuffer->frame.contents.udp.ip.diff_services != 0) return; - if(ntohs(udp_ip->ip.total_length) < sizeof(struct udp_frame)) return; - // check disabled for QEMU compatibility - //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(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) -{ - rx_callback = callback; -} - -static void process_frame(void) -{ - flush_cpu_dcache(); - -#ifdef DEBUG_MICROUDP_RX - int j; - printf("<<< rxlen : %d\n", rxlen); - for(j=0;jraw[j]); - printf("\n"); -#endif - -#ifndef HW_PREAMBLE_CRC - int i; - for(i=0;i<7;i++) - if(rxbuffer->frame.eth_header.preamble[i] != 0x55) return; - if(rxbuffer->frame.eth_header.preamble[7] != 0xd5) return; -#endif - -#ifndef HW_PREAMBLE_CRC - unsigned int received_crc; - unsigned int computed_crc; - received_crc = ((unsigned int)rxbuffer->raw[rxlen-1] << 24) - |((unsigned int)rxbuffer->raw[rxlen-2] << 16) - |((unsigned int)rxbuffer->raw[rxlen-3] << 8) - |((unsigned int)rxbuffer->raw[rxlen-4]); - computed_crc = crc32(&rxbuffer->raw[8], rxlen-12); - if(received_crc != computed_crc) return; - - rxlen -= 4; /* strip CRC here to be consistent with TX */ -#endif - - 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) -{ - int i; - ethmac_sram_reader_ev_pending_write(ETHMAC_EV_SRAM_READER); - ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); - - for(i=0;i<6;i++) - my_mac[i] = macaddr[i]; - my_ip = ip; - - cached_ip = 0; - for(i=0;i<6;i++) - cached_mac[i] = 0; - - txslot = 0; - ethmac_sram_reader_slot_write(txslot); - txbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * (ETHMAC_RX_SLOTS + txslot)); - - rxslot = 0; - rxbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * rxslot); - rx_callback = (udp_callback)0; -} - -void microudp_service(void) -{ - if(ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER) { - rxslot = ethmac_sram_writer_slot_read(); - rxbuffer = (ethernet_buffer *)(ETHMAC_BASE + ETHMAC_SLOT_SIZE * rxslot); - rxlen = ethmac_sram_writer_length_read(); - process_frame(); - ethmac_sram_writer_ev_pending_write(ETHMAC_EV_SRAM_WRITER); - } -} - -void eth_init(void) -{ - printf("Ethernet init...\n"); -#ifdef CSR_ETHPHY_CRG_RESET_ADDR - ethphy_crg_reset_write(1); - busy_wait(200); - ethphy_crg_reset_write(0); - busy_wait(200); -#endif -} - -#ifdef CSR_ETHPHY_MODE_DETECTION_MODE_ADDR -void eth_mode(void) -{ - printf("Ethernet phy mode: "); - if (ethphy_mode_detection_mode_read()) - printf("MII"); - else - printf("GMII"); - printf("\n"); -} -#endif - -#endif diff --git a/litex/soc/software/libnet/tftp.c b/litex/soc/software/libnet/tftp.c deleted file mode 100644 index 439b3e07..00000000 --- a/litex/soc/software/libnet/tftp.c +++ /dev/null @@ -1,236 +0,0 @@ -// This file is Copyright (c) 2013 Werner Almesberger -// This file is Copyright (c) 2013-2015 Sebastien Bourdeauducq -// This file is Copyright (c) 2014-2015 Florent Kermarec -// This file is Copyright (c) 2017 Greg Darke -// This file is Copyright (c) 2018 Ewen McNeill - -// License: BSD - -#include -#include -#include - -#include -#include - -/* Local TFTP client port (arbitrary) */ -#define PORT_IN 7642 - -enum { - TFTP_RRQ = 1, /* Read request */ - TFTP_WRQ = 2, /* Write request */ - TFTP_DATA = 3, /* Data */ - TFTP_ACK = 4, /* Acknowledgment */ - TFTP_ERROR = 5, /* Error */ -}; - -#define BLOCK_SIZE 512 /* block size in bytes */ - - -static int format_request(uint8_t *buf, uint16_t op, const char *filename) -{ - int len = strlen(filename); - - *buf++ = op >> 8; /* Opcode */ - *buf++ = op; - memcpy(buf, filename, len); - buf += len; - *buf++ = 0x00; - *buf++ = 'o'; - *buf++ = 'c'; - *buf++ = 't'; - *buf++ = 'e'; - *buf++ = 't'; - *buf++ = 0x00; - return 9+strlen(filename); -} - -static int format_ack(uint8_t *buf, uint16_t block) -{ - *buf++ = 0x00; /* Opcode: Ack */ - *buf++ = TFTP_ACK; - *buf++ = (block & 0xff00) >> 8; - *buf++ = (block & 0x00ff); - return 4; -} - -static int format_data(uint8_t *buf, uint16_t block, const void *data, int len) -{ - *buf++ = 0x00; /* Opcode: Data*/ - *buf++ = TFTP_DATA; - *buf++ = (block & 0xff00) >> 8; - *buf++ = (block & 0x00ff); - memcpy(buf, data, len); - return len+4; -} - -static uint8_t *packet_data; -static int total_length; -static int transfer_finished; -static uint8_t *dst_buffer; -static int last_ack; /* signed, so we can use -1 */ -static uint16_t data_port; - -static void rx_callback(uint32_t src_ip, uint16_t src_port, - uint16_t dst_port, void *_data, unsigned int length) -{ - uint8_t *data = _data; - uint16_t opcode; - uint16_t block; - int i; - int offset; - - if(length < 4) return; - if(dst_port != PORT_IN) return; - opcode = data[0] << 8 | data[1]; - block = data[2] << 8 | data[3]; - if(opcode == TFTP_ACK) { /* Acknowledgement */ - data_port = src_port; - last_ack = block; - return; - } - if(block < 1) return; - if(opcode == TFTP_DATA) { /* Data */ - length -= 4; - offset = (block-1)*BLOCK_SIZE; - for(i=0;i 0) || transfer_finished) break; - } - if((total_length > 0) || transfer_finished) break; - tries--; - if(tries == 0) { - microudp_set_callback(NULL); - return -1; - } - } - - i = 12000000; - length_before = total_length; - while(!transfer_finished) { - if(length_before != total_length) { - i = 12000000; - length_before = total_length; - if ((total_length & 0x7fff) == 0) { // every 32K - putchar("|/-\\"[spin++ % 4]); - putchar('\b'); - } - } - if(i-- == 0) { - microudp_set_callback(NULL); - return -1; - } - microudp_service(); - } - - microudp_set_callback(NULL); - - return total_length; -} - -int tftp_put(uint32_t ip, uint16_t server_port, const char *filename, - const void *buffer, int size) -{ - int len, send; - int tries; - int i; - int block = 0, sent = 0; - - if(!microudp_arp_resolve(ip)) - return -1; - - microudp_set_callback(rx_callback); - - packet_data = microudp_get_tx_buffer(); - - total_length = 0; - transfer_finished = 0; - tries = 5; - while(1) { - packet_data = microudp_get_tx_buffer(); - len = format_request(packet_data, TFTP_WRQ, filename); - microudp_send(PORT_IN, server_port, len); - for(i=0;i<2000000;i++) { - last_ack = -1; - microudp_service(); - if(last_ack == block) - goto send_data; - if(transfer_finished) - goto fail; - } - tries--; - if(tries == 0) - goto fail; - } - -send_data: - do { - block++; - send = sent+BLOCK_SIZE > size ? size-sent : BLOCK_SIZE; - tries = 5; - while(1) { - packet_data = microudp_get_tx_buffer(); - len = format_data(packet_data, block, buffer, send); - microudp_send(PORT_IN, data_port, len); - for(i=0;i<12000000;i++) { - microudp_service(); - if(transfer_finished) - goto fail; - if(last_ack == block) - goto next; - } - if (!--tries) - goto fail; - } -next: - sent += send; - buffer += send; - } while (send == BLOCK_SIZE); - - microudp_set_callback(NULL); - - return sent; - -fail: - microudp_set_callback(NULL); - return -1; -}