From: Stefan E. <se...@us...> - 2003-03-17 15:15:32
|
Update of /cvsroot/blob/blob/src/lib In directory sc8-pr-cvs1:/tmp/cvs-serv26797 Added Files: arp.c tftp.c bootp.c ip_bits.c Log Message: - Russell King's bootp/tftp code. Only minimal changes to make it compile under BLOB. --- NEW FILE: arp.c --- /* * arp.c * * Copyright 1996-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ //#include "init.h" #include <util.h> #include <net/ether.h> #include <net/arp.h> #define memeq( x, y, s ) (memcmp((x), (y), (s)) == 0) #define memzero( x, s ) memset((x), 0, (s)) static const unsigned char arp_txpacket[] = { /* destination address */ /* source address */ 0x08, 0x06, /* proto */ /* arp */ 0x00, 0x01, /* hardware format: ethernet */ 0x08, 0x00, /* protocol format: ip */ 0x06, /* hardware length */ 0x04, /* protocol length */ 0x00, 0x01 /* arp request */ }; static unsigned char arp_tx[64]; static unsigned char arp_rx[64]; extern unsigned char hwaddress[6]; extern unsigned char clientipaddress[4]; int arp_rcv (unsigned char *thwaddress) { unsigned int size; size = readether (arp_rx, 64); if (!size) return 0; if (!memeq (arp_rx + 12, arp_tx + 12, 9)) return 0; /* not valid reply */ if (arp_rx[21] != 2) return 0; /* reply */ if (!memeq (arp_rx + 28, arp_tx + 38, 4)) return 0; /* target ip address */ memcpy (thwaddress, arp_rx + 22, 6); return 1; } void do_arp (unsigned char *thwaddress, unsigned char *tipaddress) { int i; unsigned char *p = arp_tx; memzero (p, sizeof (arp_tx)); memset (p, 0xff, 6); memcpy (p + 12, arp_txpacket, sizeof (arp_txpacket)); memcpy (p + 22, hwaddress, 6); memcpy (p + 28, clientipaddress, 4); memcpy (p + 38, tipaddress, 4); do { writeether (p, 60); for (i = 0; i < 0x00040000; i++) { if (arp_rcv (thwaddress)) return; } } while (1); } --- NEW FILE: tftp.c --- /* * tftp.c * * Copyright 1996-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ //#include "init.h" #include <util.h> #include <serial.h> #include <net/ip_bits.h> #include <net/arp.h> #define memeq( x, y, s ) (memcmp((x), (y), (s)) == 0) #define memzero( x, s ) memset((x), 0, (s)) #define printascii( s ) SerialOutputString( s ) #define printch( c ) SerialOutputChar( c ) static const unsigned char tftp_txpacket[] = { /*+destination */ /*+source */ /* proto */ /* IP */ 0x45, 0x00, 0x00, 0xa4, /* ver/ihl, TOS, length */ 0x00, 0x00, /*+id */ 0x00, 0x00, 0x40, 0x11, /* frag off, ttl, proto */ 0x00, 0x00, /*+checksum */ 0x00, 0x00, 0x00, 0x00, /*+source address */ 0x00, 0x00, 0x00, 0x00, /*+destination address */ /* UDP */ 0x80, 0x00, /* source port */ 0x00, 0x45, /* destination port */ 0x00, 0x90, /* length (inc header) */ 0x00, 0x00, /*+checksum */ /* TFTP */ 0x00, 0x01 /* opcode: RRQ */ /* filename */ }; static unsigned char serverhwaddress[6]; static char octet[] = "octet"; static unsigned char tftp_tx[200]; static unsigned char tftp_rx[800]; static int serverport; static unsigned int tftp_length; static unsigned int block; extern unsigned char clientipaddress[4]; extern unsigned char serveripaddress[4]; int tftp_rcv(unsigned long *addr) { unsigned int tftp_off, tftp_sz, nblk; unsigned char *tftp; tftp_off = ipbits_rcv (tftp_rx, 800, &tftp_sz, serverport, 0x8000); if (!tftp_off || tftp_rx[tftp_off] != 0) return 0; tftp = tftp_rx + tftp_off; switch (tftp[1]) { case 5: /* error */ printascii ("\nTFTP error: "); printascii (tftp + 4); printch ('\n'); while (1); break; case 3: /* acknowledge block */ if (block == 0) { serverport = (tftp[-8] << 8) | tftp[-7]; /* copy replied-source port */ tftp_tx[OFF_UDP + 2] = serverport >> 8; tftp_tx[OFF_UDP + 3] = serverport; tftp_tx[OFF_UDP + 5] = 12; tftp_tx[OFF_IP + 3] = 32; tftp_tx[OFF_TFTP + 1] = 4; /* ack code */ block = 1; tftp_length = 12; } nblk = (tftp[2] << 8) | tftp[3]; if (nblk == block) { tftp_tx[OFF_TFTP + 2] = block >> 8; tftp_tx[OFF_TFTP + 3] = block; ipbits_tx (tftp_tx, 12); memcpy((void *)*addr, tftp + 4, tftp_sz - 4); *addr += tftp_sz - 4; if ((block & 31) == 1) printch ('.'); block ++; } else if (nblk == block - 1) ipbits_tx (tftp_tx, 12); if (tftp_sz != 516) return 1; return -1; default: return 0; } } void do_tftp(char *file, unsigned long addr) { unsigned int i; do_arp(serverhwaddress, serveripaddress); serverport = -1; tftp_length = 144; block = 0; memzero(tftp_tx, sizeof (tftp_tx)); memcpy(tftp_tx + 14, tftp_txpacket, sizeof (tftp_txpacket)); memcpy(tftp_tx + OFF_ETHER, serverhwaddress, 6); memcpy(tftp_tx + OFF_IP + 12, clientipaddress, 4); memcpy(tftp_tx + OFF_IP + 16, serveripaddress, 4); for (i = 0; file[i]; i++) tftp_tx[OFF_TFTP + 2 + i] = file[i]; memcpy(tftp_tx + OFF_TFTP + 3 + i, octet, 6); printascii("TFTPing "); printascii(file); do { printch('.'); ipbits_tx(tftp_tx, tftp_length); for (i = 0; i < 0x00040000; i++) switch (tftp_rcv(&addr)) { case 1: goto done; case -1: i = 0; } } while (1); done: printascii(" Ok\n"); } --- NEW FILE: bootp.c --- /* * bootp.c * * Copyright 1996-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ //#include "init.h" #include <util.h> #include <serial.h> #include <net/ip_bits.h> #define memeq( x, y, s ) (memcmp((x), (y), (s)) == 0) #define memzero( x, s ) memset((x), 0, (s)) #define printascii( s ) SerialOutputString( s ) #define printch( c ) SerialOutputChar( c ) static const unsigned char bootp_txpacket[] = { /* destination - broadcast */ /*+source address */ /* protocol - ip */ /* IP (14) */ 0x45, 0x00, 0x01, 0x48, /* ver/ihl, TOS, length */ 0x00, 0x00, /*+id */ 0x00, 0x00, 0x40, 0x11, /* frag off, ttl, proto */ 0x00, 0x00, /*+checksum */ 0x00, 0x00, 0x00, 0x00, /* source address (unknown) */ 0xff, 0xff, 0xff, 0xff, /* destination address (broadcast) */ /* UDP (34) */ 0x00, 0x44, /* source port */ 0x00, 0x43, /* destination port */ 0x01, 0x34, /* length (inc header) */ 0x00, 0x00, /*+checksum */ /* BOOTP (42) */ 0x01, /* Bootp REQUEST */ 0x01, /* Hardware type - ethernet */ 0x06, /* Hardware address length */ #if 0 0x00, /* HOPS ??? */ 0x00, 0x00, 0x00, 0x00, /*+random ID */ 0x00, 0x00, 0x00, 0x00, /*+time */ 0x00, 0x00, 0x00, 0x00, /* Client IP */ 0x00, 0x00, 0x00, 0x00, /* Your IP */ 0x00, 0x00, 0x00, 0x00, /* Server IP */ 0x00, 0x00, 0x00, 0x00, /* Gateway IP */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*+Hardware address we're asking for */ #endif }; static unsigned int bootp_xid = 0xd1030000; /* bootp_xid is net byte order */ static unsigned long zero = 0; static unsigned char bootp_tx[42 + 300]; static unsigned char bootp_rx[42 + 400]; extern unsigned char hwaddress[6]; unsigned char clientipaddress[4]; unsigned char serveripaddress[4]; unsigned char tftpfilename[128]; int bootp_rcv (void) { unsigned int bootp_off, bootp_sz; unsigned char *bootp; int i; if ((bootp_off = ipbits_rcv (bootp_rx, 360, &bootp_sz, 0x43, 0x44)) == 0) return 0; bootp = bootp_rx + bootp_off; if (bootp[0] != 2 || bootp[1] != 1 || bootp[2] != 6) return 0; /* not reply or wrong hardware type (error?) */ if (!memeq (bootp + 4, &bootp_xid, 4)) return 0; /* wrong xid */ if (!memeq (bootp + 12, &zero, 4)) return 0; /* not our client IP (error?) */ if (!memeq (bootp + 28, hwaddress, 6)) return 0; /* not our hardware address (error?) */ memcpy (clientipaddress, bootp + 16, 4); /* grab our & server ip addresses */ memcpy (serveripaddress, bootp + 20, 4); for (i = 0; i < 127; i++) if ((tftpfilename[i] = bootp[108 + i]) == 0) break; tftpfilename[i] = '\0'; printip ("\nOur IP : ", clientipaddress); printip ("\nServer IP: ", serveripaddress); printascii ("\nTFTP file: "); printascii (tftpfilename); printascii ("\n"); return 1; } char *do_bootp (void) { unsigned int request_time = 0; unsigned int packet_length; int i; memzero (bootp_tx, sizeof (bootp_tx)); memcpy (bootp_tx + 14, bootp_txpacket, sizeof (bootp_txpacket)); memset (bootp_tx + OFF_ETHER, 0xff, 6); memcpy (bootp_tx + OFF_BOOTP + 28, hwaddress, 6); memcpy (bootp_tx + OFF_BOOTP + 4, &bootp_xid, 4); packet_length = (bootp_tx[OFF_UDP + 4] << 8) + bootp_tx[OFF_UDP + 5]; printascii ("Sending bootp request"); do { printch ('.'); bootp_tx[OFF_BOOTP + 8] = request_time >> 8; bootp_tx[OFF_BOOTP + 9] = request_time; request_time ++; ipbits_tx (bootp_tx, packet_length); for (i = 0; i < 0x00030000; i++) if (bootp_rcv()) return tftpfilename; } while (1); } --- NEW FILE: ip_bits.c --- /* * ip_bits.c * * Copyright 1996-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ //#include "init.h" #include <util.h> #include <serial.h> #include <net/ether.h> #include <net/ip_bits.h> #define memeq( x, y, s ) (memcmp((x), (y), (s)) == 0) #define memzero( x, s ) memset((x), 0, (s)) #define printascii( s ) SerialOutputString( s ) #define printch( c ) SerialOutputChar( c ) extern unsigned char hwaddress[6]; unsigned long ip_sequence = 0; unsigned int checksum (unsigned char *ptr, int len, unsigned int cksum) { int i; for (i = 0; i < len - 1; i += 2) cksum += (ptr[i] << 8) | ptr[i + 1]; if (len & 1) cksum += ptr[len - 1] << 8; cksum = (cksum & 0xffff) + (cksum >> 16); cksum = (cksum & 0xffff) + (cksum >> 16); return cksum; } void printip (char *msg, unsigned char *ip) { int i; printascii (msg); for (i = 0; i < 4; i++) { printf( "%02x", ip[i]); printch (i == 3 ? ' ' : '.'); } } int ipbits_tx (unsigned char *ptr, unsigned int size) { unsigned int cksum; ptr[OFF_ETHER + 12] = 8; ptr[OFF_ETHER + 13] = 0; ptr[OFF_UDP + 6] = 0; ptr[OFF_UDP + 7] = 0; ptr[OFF_IP + 4] = ip_sequence >> 8; ptr[OFF_IP + 5] = ip_sequence; ptr[OFF_IP + 10] = 0; ptr[OFF_IP + 11] = 0; ip_sequence ++; cksum = checksum (ptr + OFF_IP + 12, 8, 0x11 + size); cksum = ~checksum (ptr + OFF_UDP, size, cksum); if (cksum == 0) cksum = -1; ptr[OFF_UDP + 6] = cksum >> 8; ptr[OFF_UDP + 7] = cksum; cksum = ~checksum (ptr + OFF_IP, SIZE_IP, 0); if (cksum == 0) cksum = -1; ptr[OFF_IP + 10] = cksum >> 8; ptr[OFF_IP + 11] = cksum; if (size < 32) size = 32; return writeether (ptr, size + OFF_UDP); } int ipbits_rcv (unsigned char *ptr, unsigned int size, unsigned int *dsz, int sport, int dport) { unsigned int cksum, hdrlen, off_udp; size = readether(ptr, size); if (!size) return 0; if (size < MIN_UDPPKTSIZE) /* must be at least this size for UDP */ return 0; if (!memeq (ptr + OFF_ETHER, hwaddress, 6)) return 0; /* not for us */ if (((ptr[OFF_ETHER + 12] << 8) | ptr[OFF_ETHER + 13]) != 0x800) return 0; /* not IP */ hdrlen = (ptr[OFF_IP] - 0x40) * 4; if (hdrlen < 20 || hdrlen > 60) return 0; /* not an IP packet we know about */ cksum = checksum (ptr + OFF_IP, hdrlen, 0); if (cksum != 0xffff) return 0; /* bad ip header checksum */ if (ptr[OFF_IP + 9] != 0x11) return 0; /* not UDP */ off_udp = OFF_IP + hdrlen; hdrlen = (ptr[off_udp + 4] << 8) | ptr[off_udp + 5]; if ((ptr[off_udp + 6] | ptr[off_udp + 7]) != 0) { cksum = checksum (ptr + OFF_IP + 12, 8, 0x11 + hdrlen); cksum = checksum (ptr + off_udp, hdrlen, cksum); if (cksum != 0xffff) return 0; /* bad udp checksum */ } if (sport != -1 && sport != ((ptr[off_udp] << 8) | ptr[off_udp + 1])) return 0; if (((ptr[off_udp + 2] << 8) | ptr[off_udp + 3]) != dport) return 0; /* wrong UDP ports */ *dsz = hdrlen - SIZE_UDP; return off_udp + SIZE_UDP; } |