#include "netlib.h" /* ping - originate ICMP echo requests from the Game Boy (10.0.0.2) and print the replies. Target defaults to 10.0.0.1 (the SLIP peer / host); with NAT on the bridge it can reach real internet hosts too. Usage: ping [A.B.C.D] */ static unsigned char pkt[128]; static unsigned char dst[4]; static unsigned int sum16(unsigned char *d, unsigned int len, unsigned int sum) { unsigned int w, i = 0; while (i + 1 < len) { w = ((unsigned int)d[i] << 8) | d[i + 1]; sum += w; if (sum < w) sum++; i += 2; } if (len & 1) { w = (unsigned int)d[len - 1] << 8; sum += w; if (sum < w) sum++; } return sum; } static unsigned char parse_ip(char *s, unsigned char *out) { unsigned char i, v; for (i = 0; i < 4; i++) { if (*s < '0' || *s > '9') return 0; v = 0; while (*s >= '0' && *s <= '9') { v = (unsigned char)(v * 10 + (*s - '0')); s++; } out[i] = v; if (i < 3) { if (*s != '.') return 0; s++; } } return 1; } static void put_ip(unsigned char *ip) { unsigned char i; for (i = 0; i < 4; i++) { putu(ip[i]); if (i < 3) putc('.'); } } static void send_echo(unsigned char seq) { unsigned int c; pkt[0] = 0x45; pkt[1] = 0; pkt[2] = 0; pkt[3] = 28; /* 20 IP + 8 ICMP */ pkt[4] = 0; pkt[5] = 0; pkt[6] = 0; pkt[7] = 0; pkt[8] = 64; pkt[9] = 1; pkt[10] = 0; pkt[11] = 0; /* TTL, proto ICMP */ pkt[12] = 10; pkt[13] = 0; pkt[14] = 0; pkt[15] = 2; /* src 10.0.0.2 */ pkt[16] = dst[0]; pkt[17] = dst[1]; pkt[18] = dst[2]; pkt[19] = dst[3]; c = ~sum16(pkt, 20, 0); pkt[10] = (unsigned char)(c >> 8); pkt[11] = (unsigned char)c; pkt[20] = 8; pkt[21] = 0; pkt[22] = 0; pkt[23] = 0; /* echo request */ pkt[24] = 0x12; pkt[25] = 0x34; pkt[26] = 0; pkt[27] = seq; c = ~sum16(pkt + 20, 8, 0); pkt[22] = (unsigned char)(c >> 8); pkt[23] = (unsigned char)c; slip_send((char *)pkt, 28); } /* wait for the ICMP echo reply for 'seq', skipping unrelated frames (the shared 10.0.0.0/24 carries IGMP/mDNS/SSDP noise). Returns 1 on match, 0 on timeout. The emulator runs uncapped, so the spin budget is generous to span the wall-clock round trip through the host bridge. */ static unsigned char ping_wait(unsigned char seq) { unsigned int o, i; unsigned char len = 0, c, ihl; int b; for (o = 0; o < 20; o++) { for (i = 0; i < 60000; i++) { b = srecv_nb(); if (b < 0) continue; c = (unsigned char)b; if (c == SLIP_END) { if (len) { ihl = (unsigned char)((pkt[0] & 0x0f) << 2); if (len >= (unsigned char)(ihl + 8) && pkt[9] == 1 && pkt[ihl] == 0 && pkt[ihl + 7] == seq) return 1; len = 0; /* not ours - keep waiting */ } continue; } if (c == SLIP_ESC) { c = srecv(); if (c == SLIP_ESC_END) c = SLIP_END; else if (c == SLIP_ESC_ESC) c = SLIP_ESC; } if (len < 128) pkt[len++] = c; else len = 0; } } return 0; } void main(void) { char *arg; unsigned char seq, got = 0; arg = getargs(); if (!arg || !*arg) { dst[0] = 10; dst[1] = 0; dst[2] = 0; dst[3] = 1; } else if (!parse_ip(arg, dst)) { puts("ping: bad address"); nl(); sexit(1); } puts("PING "); put_ip(dst); nl(); for (seq = 1; seq <= 4; seq++) { send_echo(seq); if (ping_wait(seq)) { got++; puts(" reply from "); put_ip(pkt + 12); puts(" seq="); putu(seq); puts(" ttl="); putu(pkt[8]); nl(); } else { puts(" seq="); putu(seq); puts(" timeout"); nl(); } } puts("-- "); putu(got); puts("/4 received"); nl(); }