be45f4d02a
using a #define to turn one into the other, this is pointless and causes more portability issues than it solves (admittedly, in the year 1702 when this code was written the opposite may have been the case).
281 lines
7.1 KiB
C
281 lines
7.1 KiB
C
/* $NetBSD: hwaddr.c,v 1.9 2007/05/27 16:31:42 tls Exp $ */
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: hwaddr.c,v 1.9 2007/05/27 16:31:42 tls Exp $");
|
|
#endif
|
|
|
|
/*
|
|
* hwaddr.c - routines that deal with hardware addresses.
|
|
* (i.e. Ethernet)
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#if defined(SUNOS) || defined(SVR4)
|
|
#include <sys/sockio.h>
|
|
#endif
|
|
#ifdef SVR4
|
|
#include <sys/stream.h>
|
|
#include <stropts.h>
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#include <net/if_arp.h>
|
|
#include <netinet/in.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <strings.h>
|
|
#ifndef NO_UNISTD
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <syslog.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "bptypes.h"
|
|
#include "hwaddr.h"
|
|
#include "report.h"
|
|
|
|
extern int debug;
|
|
|
|
/*
|
|
* Hardware address lengths (in bytes) and network name based on hardware
|
|
* type code. List in order specified by Assigned Numbers RFC; Array index
|
|
* is hardware type code. Entries marked as zero are unknown to the author
|
|
* at this time. . . .
|
|
*/
|
|
|
|
struct hwinfo hwinfolist[] =
|
|
{
|
|
{0, "Reserved"}, /* Type 0: Reserved (don't use this) */
|
|
{6, "Ethernet"}, /* Type 1: 10Mb Ethernet (48 bits) */
|
|
{1, "3Mb Ethernet"}, /* Type 2: 3Mb Ethernet (8 bits) */
|
|
{0, "AX.25"}, /* Type 3: Amateur Radio AX.25 */
|
|
{1, "ProNET"}, /* Type 4: Proteon ProNET Token Ring */
|
|
{0, "Chaos"}, /* Type 5: Chaos */
|
|
{6, "IEEE 802"}, /* Type 6: IEEE 802 Networks */
|
|
{0, "ARCNET"} /* Type 7: ARCNET */
|
|
};
|
|
int hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
|
|
|
|
|
|
/*
|
|
* Setup the arp cache so that IP address 'ia' will be temporarily
|
|
* bound to hardware address 'ha' of length 'len'.
|
|
* s is the socket fd.
|
|
*/
|
|
void
|
|
setarp(int s, struct in_addr *ia, u_char *ha, int len)
|
|
{
|
|
#ifdef SIOCSARP
|
|
struct arpreq arpreq; /* Arp request ioctl block */
|
|
struct sockaddr_in *si;
|
|
#ifdef SVR4
|
|
int fd;
|
|
struct strioctl iocb;
|
|
#endif /* SVR4 */
|
|
|
|
bzero((caddr_t) & arpreq, sizeof(arpreq));
|
|
arpreq.arp_flags = ATF_INUSE | ATF_COM;
|
|
|
|
/* Set up the protocol address. */
|
|
arpreq.arp_pa.sa_family = AF_INET;
|
|
si = (struct sockaddr_in *) &arpreq.arp_pa;
|
|
si->sin_addr = *ia;
|
|
|
|
/* Set up the hardware address. */
|
|
bcopy(ha, arpreq.arp_ha.sa_data, len);
|
|
|
|
#ifdef SVR4
|
|
/*
|
|
* And now the stuff for System V Rel 4.x which does not
|
|
* appear to allow SIOCxxx ioctls on a socket descriptor.
|
|
* Thanks to several people: (all sent the same fix)
|
|
* Barney Wolff <barney@databus.com>,
|
|
* bear@upsys.se (Bj|rn Sj|holm),
|
|
* Michael Kuschke <Michael.Kuschke@Materna.DE>,
|
|
*/
|
|
if ((fd=open("/dev/arp", O_RDWR)) < 0) {
|
|
report(LOG_ERR, "open /dev/arp: %s\n", get_errmsg());
|
|
}
|
|
iocb.ic_cmd = SIOCSARP;
|
|
iocb.ic_timout = 0;
|
|
iocb.ic_dp = (char *)&arpreq;
|
|
iocb.ic_len = sizeof(arpreq);
|
|
if (ioctl(fd, I_STR, (caddr_t)&iocb) < 0) {
|
|
report(LOG_ERR, "ioctl I_STR: %s\n", get_errmsg());
|
|
}
|
|
close (fd);
|
|
|
|
#else /* SVR4 */
|
|
/*
|
|
* On SunOS, the ioctl sometimes returns ENXIO, and it
|
|
* appears to happen when the ARP cache entry you tried
|
|
* to add is already in the cache. (Sigh...)
|
|
* XXX - Should this error simply be ignored? -gwr
|
|
*/
|
|
if (ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) {
|
|
report(LOG_ERR, "ioctl SIOCSARP: %s", get_errmsg());
|
|
}
|
|
#endif /* SVR4 */
|
|
#else /* SIOCSARP */
|
|
/*
|
|
* Oh well, SIOCSARP is not defined. Just run arp(8).
|
|
* XXX - Gag!
|
|
*/
|
|
int status;
|
|
char buf[256];
|
|
char *a;
|
|
|
|
a = inet_ntoa(*ia);
|
|
snprintf(buf, sizeof(buf), "arp -d %s; arp -s %s %s temp",
|
|
a, a, haddrtoa(ha, len));
|
|
if (debug > 2)
|
|
report(LOG_INFO, "%s", buf);
|
|
status = system(buf);
|
|
if (status)
|
|
report(LOG_ERR, "arp failed, exit code=0x%x", status);
|
|
return;
|
|
#endif /* SIOCSARP */
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert a hardware address to an ASCII string.
|
|
*/
|
|
char *
|
|
haddrtoa(u_char *haddr, int hlen)
|
|
{
|
|
static char haddrbuf[3 * MAXHADDRLEN + 1];
|
|
char *bufptr;
|
|
|
|
if (hlen > MAXHADDRLEN)
|
|
hlen = MAXHADDRLEN;
|
|
|
|
bufptr = haddrbuf;
|
|
while (hlen > 0) {
|
|
snprintf(bufptr, sizeof(haddrbuf) - (bufptr - haddrbuf),
|
|
"%02X:", (unsigned) (*haddr++ & 0xFF));
|
|
bufptr += 3;
|
|
hlen--;
|
|
}
|
|
bufptr[-1] = 0;
|
|
return (haddrbuf);
|
|
}
|
|
|
|
|
|
/*
|
|
* haddr_conv802()
|
|
* --------------
|
|
*
|
|
* Converts a backwards address to a canonical address and a canonical address
|
|
* to a backwards address.
|
|
*
|
|
* INPUTS:
|
|
* adr_in - pointer to six byte string to convert (unsigned char *)
|
|
* addr_len - how many bytes to convert
|
|
*
|
|
* OUTPUTS:
|
|
* addr_out - The string is updated to contain the converted address.
|
|
*
|
|
* CALLER:
|
|
* many
|
|
*
|
|
* DATA:
|
|
* Uses conv802table to bit-reverse the address bytes.
|
|
*/
|
|
|
|
static u_char conv802table[256] =
|
|
{
|
|
/* 0x00 */ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
|
|
/* 0x08 */ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
|
/* 0x10 */ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
|
/* 0x18 */ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
|
/* 0x20 */ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
|
|
/* 0x28 */ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
|
/* 0x30 */ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
|
/* 0x38 */ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
|
/* 0x40 */ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
|
|
/* 0x48 */ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
|
/* 0x50 */ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
|
|
/* 0x58 */ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
|
/* 0x60 */ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
|
|
/* 0x68 */ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
|
/* 0x70 */ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
|
|
/* 0x78 */ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
|
/* 0x80 */ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
|
|
/* 0x88 */ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
|
/* 0x90 */ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
|
|
/* 0x98 */ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
|
/* 0xA0 */ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
|
|
/* 0xA8 */ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
|
/* 0xB0 */ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
|
|
/* 0xB8 */ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
|
/* 0xC0 */ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
|
|
/* 0xC8 */ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
|
/* 0xD0 */ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
|
|
/* 0xD8 */ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
|
/* 0xE0 */ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
|
/* 0xE8 */ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
|
/* 0xF0 */ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
|
|
/* 0xF8 */ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
|
|
};
|
|
|
|
void
|
|
haddr_conv802(u_char *addr_in, u_char *addr_out, int len)
|
|
{
|
|
u_char *lim;
|
|
|
|
lim = addr_out + len;
|
|
while (addr_out < lim)
|
|
*addr_out++ = conv802table[*addr_in++];
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* For the record, here is a program to generate the
|
|
* bit-reverse table above.
|
|
*/
|
|
static int
|
|
bitrev(int n)
|
|
{
|
|
int i, r;
|
|
|
|
r = 0;
|
|
for (i = 0; i < 8; i++) {
|
|
r <<= 1;
|
|
r |= (n & 1);
|
|
n >>= 1;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
main(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i <= 0xFF; i++) {
|
|
if ((i & 7) == 0)
|
|
printf("/* 0x%02X */", i);
|
|
printf(" 0x%02X,", bitrev(i));
|
|
if ((i & 7) == 7)
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Local Variables:
|
|
* tab-width: 4
|
|
* c-indent-level: 4
|
|
* c-argdecl-indent: 4
|
|
* c-continued-statement-offset: 4
|
|
* c-continued-brace-offset: -4
|
|
* c-label-offset: -4
|
|
* c-brace-offset: 0
|
|
* End:
|
|
*/
|