diff --git a/src/ethernet.c b/src/ethernet.c index 3c11d10..e249a77 100644 --- a/src/ethernet.c +++ b/src/ethernet.c @@ -154,17 +154,15 @@ bool ethII_frame_unpack(const novell_ipx_packet **packet, size_t *packet_len, co size_t novell_frame_size(size_t ipx_payload_len) { - static const size_t OVERHEAD - = sizeof(ethernet_header) - + sizeof(novell_ipx_packet); - if(ipx_payload_len > NOVELL_IPX_PACKET_MAX_PAYLOAD - || ipx_payload_len > (1500 - OVERHEAD)) + || ipx_payload_len > (1500 - sizeof(novell_ipx_packet))) { return 0; } - return OVERHEAD + ipx_payload_len; + return sizeof(ethernet_header) + + sizeof(novell_ipx_packet) + + ipx_payload_len; } void novell_frame_pack(void *frame_buffer, @@ -224,18 +222,16 @@ bool novell_frame_unpack(const novell_ipx_packet **packet, size_t *packet_len, c size_t llc_frame_size(size_t ipx_payload_len) { - static const size_t OVERHEAD - = sizeof(ethernet_header) - + sizeof(llc_header) - + sizeof(novell_ipx_packet); - if(ipx_payload_len > NOVELL_IPX_PACKET_MAX_PAYLOAD - || ipx_payload_len > (1500 - OVERHEAD)) + || ipx_payload_len > (1500 - (sizeof(llc_header) + sizeof(novell_ipx_packet)))) { return 0; } - return OVERHEAD + ipx_payload_len; + return sizeof(ethernet_header) + + sizeof(llc_header) + + sizeof(novell_ipx_packet) + + ipx_payload_len; } void llc_frame_pack(void *frame_buffer, diff --git a/tests/30-eth-ipx.t b/tests/30-eth-ipx.t index 24a0da0..2e21130 100644 --- a/tests/30-eth-ipx.t +++ b/tests/30-eth-ipx.t @@ -44,6 +44,7 @@ my $node_c_net = "00:00:00:00"; my $ipx_eth_capture_class; my $ipx_eth_send_func; +my $max_payload_size; shared_examples_for "ipx over ethernet" => sub { @@ -502,6 +503,96 @@ shared_examples_for "ipx over ethernet" => sub }; }; + it "can transmit the largest possible packet" => sub + { + my $capture = $ipx_eth_capture_class->new($local_dev_a); + + run_remote_cmd( + $remote_ip_a, "Z:\\tools\\ipx-send.exe", + "-l" => $max_payload_size, + "-s" => "4324", "-h" => $remote_mac_a, + "00:00:00:01", $local_mac_a, "6789", + ); + + sleep(1); + + my @packets = $capture->read_available(); + + cmp_hashes_partial(\@packets, [ + { + src_network => "00:00:00:01", + src_node => $remote_mac_a, + src_socket => 4324, + + dst_network => "00:00:00:01", + dst_node => $local_mac_a, + dst_socket => 6789, + + data => (chr(0xAA) x $max_payload_size), + }, + ]); + }; + + it "refuses to transmit larger than the largest possible packet" => sub + { + my $capture = $ipx_eth_capture_class->new($local_dev_a); + + trap { + run_remote_cmd( + $remote_ip_a, "Z:\\tools\\ipx-send.exe", + "-l" => $max_payload_size + 1, + "-s" => "1111", "-h" => $remote_mac_a, + "00:00:00:01", $local_mac_a, "2222", + ); + }; + + sleep(1); + + # Ensure sendto() failed with WSAEMSGSIZE + like($trap->die(), qr/^sendto: 10040$/m); + + # Ensure no packets were transmitted. + my @packets = $capture->read_available(); + cmp_hashes_partial(\@packets, []); + }; + + it "can receive the largest possible packet" => sub + { + my $capture = IPXWrapper::Tool::IPXRecv->new( + $remote_ip_a, + "00:00:00:00", $remote_mac_a, "3456", + ); + + $ipx_eth_send_func->($local_dev_a, + tc => 0, + type => 0, + + dest_network => "00:00:00:01", + dest_node => $remote_mac_a, + dest_socket => 3456, + + src_network => "00:00:00:01", + src_node => $local_mac_a, + src_socket => 4567, + + data => ("x" x $max_payload_size), + ); + + sleep(1); + + my @packets = $capture->kill_and_read(); + + cmp_hashes_partial(\@packets, [ + { + src_network => "00:00:00:01", + src_node => $local_mac_a, + src_socket => 4567, + + data => ("x" x $max_payload_size), + }, + ]); + }; + before all => sub { $ptype_capture_class = $ipx_eth_capture_class; @@ -542,6 +633,7 @@ describe "IPXWrapper using Ethernet encapsulation" => sub $ipx_eth_capture_class = "IPXWrapper::Capture::IPX"; $ipx_eth_send_func = \&send_ipx_packet_ethernet; + $max_payload_size = 1470; }; it_should_behave_like "ipx over ethernet"; @@ -559,6 +651,7 @@ describe "IPXWrapper using Novell Ethernet encapsulation" => sub $ipx_eth_capture_class = "IPXWrapper::Capture::IPXNovell"; $ipx_eth_send_func = \&send_ipx_packet_novell; + $max_payload_size = 1470; }; it_should_behave_like "ipx over ethernet"; @@ -576,6 +669,7 @@ describe "IPXWrapper using LLC (802.2) Ethernet encapsulation" => sub $ipx_eth_capture_class = "IPXWrapper::Capture::IPXLLC"; $ipx_eth_send_func = \&send_ipx_packet_llc; + $max_payload_size = 1467; }; it_should_behave_like "ipx over ethernet"; diff --git a/tests/ethernet.c b/tests/ethernet.c index dd527c8..6190abd 100644 --- a/tests/ethernet.c +++ b/tests/ethernet.c @@ -241,8 +241,8 @@ int main() CHECK_FRAME_SIZE(novell_frame_size, 0, 44); CHECK_FRAME_SIZE(novell_frame_size, 50, 94); - CHECK_FRAME_SIZE(novell_frame_size, 1456, 1500); - CHECK_FRAME_SIZE(novell_frame_size, 1457, 0); + CHECK_FRAME_SIZE(novell_frame_size, 1470, 1514); + CHECK_FRAME_SIZE(novell_frame_size, 1471, 0); /* +===================+ * | novell_frame_pack | @@ -510,8 +510,8 @@ int main() CHECK_FRAME_SIZE(llc_frame_size, 0, 47); CHECK_FRAME_SIZE(llc_frame_size, 50, 97); - CHECK_FRAME_SIZE(llc_frame_size, 1453, 1500); - CHECK_FRAME_SIZE(llc_frame_size, 1454, 0); + CHECK_FRAME_SIZE(llc_frame_size, 1467, 1514); + CHECK_FRAME_SIZE(llc_frame_size, 1468, 0); /* +================+ * | llc_frame_pack | diff --git a/tests/lib/IPXWrapper/Capture/IPX.pm b/tests/lib/IPXWrapper/Capture/IPX.pm index 6063285..e991851 100644 --- a/tests/lib/IPXWrapper/Capture/IPX.pm +++ b/tests/lib/IPXWrapper/Capture/IPX.pm @@ -28,7 +28,7 @@ sub new my ($class, $dev) = @_; my $err; - my $pcap = Net::Pcap::pcap_open_live($dev, 1500, 0, 1, \$err) + my $pcap = Net::Pcap::pcap_open_live($dev, 2000, 0, 1, \$err) or die("Cannot open device $dev: $err"); return bless(\$pcap, $class); diff --git a/tests/lib/IPXWrapper/Capture/IPXLLC.pm b/tests/lib/IPXWrapper/Capture/IPXLLC.pm index a7f2607..462f52a 100644 --- a/tests/lib/IPXWrapper/Capture/IPXLLC.pm +++ b/tests/lib/IPXWrapper/Capture/IPXLLC.pm @@ -28,7 +28,7 @@ sub new my ($class, $dev) = @_; my $err; - my $pcap = Net::Pcap::pcap_open_live($dev, 1500, 0, 1, \$err) + my $pcap = Net::Pcap::pcap_open_live($dev, 2000, 0, 1, \$err) or die("Cannot open device $dev: $err"); return bless(\$pcap, $class); diff --git a/tests/lib/IPXWrapper/Capture/IPXNovell.pm b/tests/lib/IPXWrapper/Capture/IPXNovell.pm index bd5cbf6..656f190 100644 --- a/tests/lib/IPXWrapper/Capture/IPXNovell.pm +++ b/tests/lib/IPXWrapper/Capture/IPXNovell.pm @@ -28,7 +28,7 @@ sub new my ($class, $dev) = @_; my $err; - my $pcap = Net::Pcap::pcap_open_live($dev, 1500, 0, 1, \$err) + my $pcap = Net::Pcap::pcap_open_live($dev, 2000, 0, 1, \$err) or die("Cannot open device $dev: $err"); return bless(\$pcap, $class); diff --git a/tests/lib/IPXWrapper/Util.pm b/tests/lib/IPXWrapper/Util.pm index cfd8f3e..b4323f4 100644 --- a/tests/lib/IPXWrapper/Util.pm +++ b/tests/lib/IPXWrapper/Util.pm @@ -55,12 +55,14 @@ sub run_remote_cmd note(join(" ", @command)); my $output = ""; - IPC::Run::run(\@command, ">&" => \$output) - or die("Failure running $exe_name:\n$output"); + my $ok = IPC::Run::run(\@command, ">&" => \$output); # Oh line endings, how do I hate thee? Let me count the ways. $output =~ s/\r//g; + die("Failure running $exe_name:\n$output") + unless($ok); + return $output; } diff --git a/tools/ipx-recv.c b/tools/ipx-recv.c index 320a1f9..d21b564 100644 --- a/tools/ipx-recv.c +++ b/tools/ipx-recv.c @@ -28,7 +28,7 @@ #include "tools.h" const int MAX_SOCKETS = 32; -const int BUFSIZE = 64; +const int BUFSIZE = 2048; static void usage(const char *argv0) { diff --git a/tools/ipx-send.c b/tools/ipx-send.c index 8335201..5228d75 100644 --- a/tools/ipx-send.c +++ b/tools/ipx-send.c @@ -43,7 +43,7 @@ int main(int argc, char **argv) BOOL reuse = FALSE; int opt; - while((opt = getopt(argc, argv, "n:h:s:t:d:br")) != -1) + while((opt = getopt(argc, argv, "n:h:s:t:d:l:br")) != -1) { if(opt == 'n') { @@ -65,6 +65,13 @@ int main(int argc, char **argv) { data = optarg; } + else if(opt == 'l') + { + int len = atoi(optarg); + assert((data = malloc(len)) != NULL); + + memset((char*)(data), 0xAA, len); + } else if(opt == 'b') { bcast = TRUE; @@ -87,6 +94,7 @@ int main(int argc, char **argv) "[-s ]\n" "[-t ]\n" "[-d ]\n" + "[-l ]\n" "[-b (enable SO_BROADCAST)]\n" "[-r (enable SO_REUSEADDR)]\n" "\n" @@ -132,7 +140,14 @@ int main(int argc, char **argv) printf("Bound to local address: %s\n", formatted_addr); } - assert(sendto(sock, data, strlen(data), 0, (struct sockaddr*)(&remote_addr), sizeof(remote_addr)) == strlen(data)); + int sr = sendto(sock, data, strlen(data), 0, (struct sockaddr*)(&remote_addr), sizeof(remote_addr)); + if(sr == -1) + { + fprintf(stderr, "sendto: %u\n", (unsigned int)(WSAGetLastError())); + return 1; + } + + assert(sr == strlen(data)); closesocket(sock);