diff --git a/bochs/.bochsrc b/bochs/.bochsrc index 8385fd7b7..d6cfe7e84 100644 --- a/bochs/.bochsrc +++ b/bochs/.bochsrc @@ -594,10 +594,11 @@ private_colormap: enabled=0 # you can use the following 'ethmod's to simulate a virtual network. # null: All packets are discarded, but logged to a few files. # arpback: ARP is simulated. Disabled by default. -# vnet: ARP, ICMP-echo(ping), DHCP and read-only TFTP are simulated. +# vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated. # The virtual host uses 192.168.10.1. # DHCP assignes 192.168.10.2 to the guest. -# TFTP uses the ethdev value for the root directory. +# TFTP uses the ethdev value for the root directory and doesn't +# overwrite files. # #======================================================================= # ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx diff --git a/bochs/iodev/eth_vnet.cc b/bochs/iodev/eth_vnet.cc index 9748865bf..75bffe86c 100644 --- a/bochs/iodev/eth_vnet.cc +++ b/bochs/iodev/eth_vnet.cc @@ -1,10 +1,10 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: eth_vnet.cc,v 1.16 2005-06-08 21:11:54 vruppert Exp $ +// $Id: eth_vnet.cc,v 1.17 2005-06-12 08:59:32 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // // virtual Ethernet locator // -// An implementation of ARP, ping(ICMP-echo), DHCP and read-only TFTP. +// An implementation of ARP, ping(ICMP-echo), DHCP and read/write TFTP. // Virtual host acts as a DHCP server for guest. // There are no connections between the virtual host and real ethernets. // @@ -13,7 +13,7 @@ // Guest IP: 192.168.10.2 // Guest netmask: 255.255.255.0 // Guest broadcast: 192.168.10.255 -// TFTP server uses ethdev value for the root directory +// TFTP server uses ethdev value for the root directory and doesn't overwrite files #define BX_PLUGGABLE @@ -81,6 +81,7 @@ typedef void (*layer4_handler_t)( #define BOOTREQUEST 1 #define BOOTREPLY 2 + #define BOOTPOPT_PADDING 0 #define BOOTPOPT_END 255 #define BOOTPOPT_SUBNETMASK 1 @@ -110,12 +111,13 @@ typedef void (*layer4_handler_t)( #define BOOTPOPT_CLIENT_IDENTIFIER 61 #define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 class bx_vnet_pktmover_c : public eth_pktmover_c { public: @@ -175,16 +177,21 @@ private: unsigned sourceport, unsigned targetport, const Bit8u *data, unsigned data_len); void tftp_send_error( - Bit8u *buffer, + Bit8u *buffer, unsigned sourceport, unsigned targetport, unsigned code, const char *msg); void tftp_send_data( - Bit8u *buffer, - unsigned sourceport, unsigned targetport, + Bit8u *buffer, + unsigned sourceport, unsigned targetport, unsigned block_nr); + void tftp_send_ack( + Bit8u *buffer, + unsigned sourceport, unsigned targetport, + unsigned block_nr); char tftp_filename[BX_PATHNAME_LEN]; char tftp_rootdir[BX_PATHNAME_LEN]; + bx_bool tftp_write; Bit16u tftp_tid; Bit8u host_macaddr[6]; @@ -286,6 +293,7 @@ bx_vnet_pktmover_c::pktmover_init( this->rxarg = rxarg; strcpy(this->tftp_rootdir, netif); this->tftp_tid = 0; + this->tftp_write = 0; memcpy(&host_macaddr[0], macaddr, 6); memcpy(&guest_macaddr[0], macaddr, 6); @@ -1112,6 +1120,11 @@ bx_vnet_pktmover_c::udpipv4_tftp_handler_ns( const Bit8u *data, unsigned data_len) { Bit8u buffer[TFTP_BUFFER_SIZE + 4]; + char path[BX_PATHNAME_LEN]; + FILE *fp; + unsigned block_nr; + unsigned tftp_len; + switch (get_net2(data)) { case TFTP_RRQ: if (tftp_tid == 0) { @@ -1129,6 +1142,7 @@ bx_vnet_pktmover_c::udpipv4_tftp_handler_ns( strcpy(tftp_filename, (char*)buffer); tftp_tid = sourceport; + tftp_write = 0; tftp_send_data(buffer, sourceport, targetport, 1); } else { tftp_send_error(buffer, sourceport, targetport, 4, "Illegal request"); @@ -1148,7 +1162,54 @@ bx_vnet_pktmover_c::udpipv4_tftp_handler_ns( } } - tftp_send_error(buffer, sourceport, targetport, 4, "TFTP WRQ not supported yet"); + strcpy(tftp_filename, (char*)buffer); + sprintf(path, "%s/%s", tftp_rootdir, tftp_filename); + fp = fopen(path, "rb"); + if (fp) { + tftp_send_error(buffer, sourceport, targetport, 6, "File exists"); + fclose(fp); + return; + } + fp = fopen(path, "wb"); + if (!fp) { + tftp_send_error(buffer, sourceport, targetport, 2, "Access violation"); + return; + } + fclose(fp); + tftp_tid = sourceport; + tftp_write = 1; + + tftp_send_ack(buffer, sourceport, targetport, 0); + } else { + tftp_send_error(buffer, sourceport, targetport, 4, "Illegal request"); + } + break; + case TFTP_DATA: + if ((tftp_tid == sourceport) && (tftp_write == 1)) { + block_nr = get_net2(data + 2); + strncpy((char*)buffer, (const char*)data + 4, data_len - 4); + tftp_len = data_len - 4; + buffer[tftp_len] = 0; + if (tftp_len <= 512) { + sprintf(path, "%s/%s", tftp_rootdir, tftp_filename); + fp = fopen(path, "ab"); + if (!fp) { + tftp_send_error(buffer, sourceport, targetport, 2, "Access violation"); + return; + } + if (fseek(fp, (block_nr - 1) * TFTP_BUFFER_SIZE, SEEK_SET) < 0) { + tftp_send_error(buffer, sourceport, targetport, 3, "Block not seekable"); + return; + } + fwrite(buffer, 1, tftp_len, fp); + fclose(fp); + tftp_send_ack(buffer, sourceport, targetport, block_nr); + if (tftp_len < 512) { + tftp_tid = 0; + } + } else { + tftp_send_error(buffer, sourceport, targetport, 4, "Illegal request"); + } } else { tftp_send_error(buffer, sourceport, targetport, 4, "Illegal request"); } @@ -1226,5 +1287,16 @@ bx_vnet_pktmover_c::tftp_send_data( } } +void +bx_vnet_pktmover_c::tftp_send_ack( + Bit8u *buffer, + unsigned sourceport, unsigned targetport, + unsigned block_nr) +{ + put_net2(buffer, TFTP_ACK); + put_net2(buffer + 2, block_nr); + host_to_guest_udpipv4_packet(sourceport, targetport, buffer, 4); +} + #endif /* if BX_NETWORKING */