/* * ipx_probe.c * * Check the network for frames currently active * * Copyright (C) 1996 by Volker Lendecke * */ #include #include #include #include #include #include #include #include #include #include #include static char *progname; int verbose = 0; static void usage () { fprintf (stderr, "usage: %s [options]\n", progname); fprintf (stderr, "type '%s -h' for help\n", progname); } static void help () { printf ("\n" "Probe an interface for ipx networks\n" "\n"); printf ("usage: %s [options]\n", progname); printf ("\n" "-v Verbose output\n" "-i interface Interface to probe, default: eth0\n" "-t timeout Seconds to wait for answer, default: 3\n" "-h Print this help text\n\n"); } #define IPX_SAP_PTYPE (0x04) #define IPX_SAP_NEAREST_QUERY (0x0003) #define IPX_SAP_PORT (0x0452) #define IPX_BROADCAST_NODE ("\xff\xff\xff\xff\xff\xff") #define BVAL(buf,pos) (((__u8 *)(buf))[pos]) #define BSET(buf,pos,val) (BVAL(buf,pos) = (val)) static inline void WSET_HL (__u8 * buf, int pos, __u16 val) { BSET (buf, pos, val >> 8); BSET (buf, pos + 1, val & 0xff); } struct frame_type { char *ft_name; unsigned char ft_val; }; static struct frame_type frame_types[] = { { "802.2", IPX_FRAME_8022 } , #ifdef IPX_FRAME_TR_8022 { "802.2TR", IPX_FRAME_TR_8022 } , #endif { "802.3", IPX_FRAME_8023 } , { "SNAP", IPX_FRAME_SNAP } , { "EtherII", IPX_FRAME_ETHERII } }; #define NFTYPES (sizeof(frame_types)/sizeof(struct frame_type)) static char * frame_name (int frame_type) { int i; for (i = 0; i < NFTYPES; i++) { if (frame_types[i].ft_val == frame_type) { return frame_types[i].ft_name; } } return NULL; } static int ipx_recvfrom (int sock, void *buf, int len, unsigned int flags, struct sockaddr_ipx *sender, int *addrlen, int timeout, long *err) { fd_set rd, wr, ex; struct timeval tv; int result; FD_ZERO (&rd); FD_ZERO (&wr); FD_ZERO (&ex); FD_SET (sock, &rd); tv.tv_sec = timeout; tv.tv_usec = 0; if ((result = select (sock + 1, &rd, &wr, &ex, &tv)) == -1) { *err = errno; return -1; } if (FD_ISSET (sock, &rd)) { result = recvfrom (sock, buf, len, flags, (struct sockaddr *) sender, addrlen); } else { result = -1; errno = ETIMEDOUT; } if (result < 0) { *err = errno; } return result; } static int ipx_recv (int sock, void *buf, int len, unsigned int flags, int timeout, long *err) { struct sockaddr_ipx sender; int addrlen = sizeof (sender); return ipx_recvfrom (sock, buf, len, flags, &sender, &addrlen, timeout, err); } static int probe_frame (char *interface, int frame_type, int timeout, unsigned long *net) { int i, sock, opt; int result; long err; char errmsg[strlen (progname) + 20]; char data[1024]; static struct ifreq id; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &id.ifr_addr; if (verbose != 0) { printf ("probing %s on %s -- ", frame_name (frame_type), interface); fflush (stdout); } sock = socket (AF_IPX, SOCK_DGRAM, AF_IPX); if (sock < 0) { int old_errno = errno; sprintf (errmsg, "%s: socket", progname); perror (errmsg); if (old_errno == -EINVAL) { fprintf (stderr, "Probably you have no IPX support in " "your kernel\n"); } close (sock); return -1; } memset (&id, 0, sizeof (id)); strncpy (id.ifr_name, interface, sizeof (id.ifr_name) - 1); sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_CRTITF; sipx->sipx_special = IPX_PRIMARY; sipx->sipx_network = 0L; sipx->sipx_type = frame_type; i = 0; do { result = ioctl (sock, SIOCSIFADDR, &id); i++; } while ((i < 5) && (result < 0) && (errno == EAGAIN)); if (result < 0) { int old_errno = errno; close (sock); errno = old_errno; return result; } /* We do a GNS request on the new socket. If something comes back, we assume that the frame type is valid. */ opt = 1; if ((result = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof (opt))) < 0) { int old_errno = errno; close (sock); errno = old_errno; return result; } memset (&id, 0, sizeof (id)); sipx->sipx_family = AF_IPX; sipx->sipx_network = htonl (0x0); sipx->sipx_port = htons (0x0); sipx->sipx_type = IPX_SAP_PTYPE; if ((result = bind (sock, (struct sockaddr *) sipx, sizeof (*sipx))) < 0 - 1) { int old_errno = errno; close (sock); errno = old_errno; return result; } WSET_HL (data, 0, IPX_SAP_NEAREST_QUERY); WSET_HL (data, 2, 4); memset (&id, 0, sizeof (id)); sipx->sipx_family = AF_IPX; sipx->sipx_port = htons (IPX_SAP_PORT); sipx->sipx_type = IPX_SAP_PTYPE; sipx->sipx_network = htonl (0x0); memcpy (sipx->sipx_node, IPX_BROADCAST_NODE, 6); if ((result = sendto (sock, data, 4, 0, (struct sockaddr *) sipx, sizeof (*sipx))) < 0) { int old_errno = errno; close (sock); errno = old_errno; return result; } result = ipx_recv (sock, data, 1024, 0, timeout, &err); if (result > 0) { struct sockaddr_ipx sipx; int namelen = sizeof (sipx); if (getsockname (sock, (struct sockaddr *) &sipx, &namelen) < 0) { fprintf (stderr, "%s: Could not find socket address\n", progname); exit (1); } *net = ntohl (sipx.sipx_network); } memset (&id, 0, sizeof (id)); strncpy (id.ifr_name, interface, sizeof (id.ifr_name) - 1); sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_DLTITF; sipx->sipx_network = 0L; sipx->sipx_type = frame_type; result = ioctl (sock, SIOCSIFADDR, &id); close (sock); if (result < 0) { fprintf (stderr, "%s: could not delete interface\n", progname); exit (1); } if (err == ETIMEDOUT) { if (verbose != 0) { printf ("no network found\n"); } return -1; } if (verbose != 0) { printf ("found IPX network %8.8lX\n", *net); } return 0; } static int file_lines (char *name) { FILE *f = fopen (name, "r"); char buf[100]; int lines = 0; if (f == NULL) { return -errno; } while (fgets (buf, sizeof (buf), f) != NULL) { lines += 1; } fclose (f); return lines; } static int ipx_interfaces (void) { int result = file_lines ("/proc/net/ipx_interface"); if (result == 0) { result = -EIO; } return result - 1; } static int ipx_auto_off (void) { int s; char errmsg[strlen (progname) + 20]; int val = 0; s = socket (AF_IPX, SOCK_DGRAM, AF_IPX); if (s < 0) { int old_errno = errno; sprintf (errmsg, "%s: socket", progname); perror (errmsg); if (old_errno == -EINVAL) { fprintf (stderr, "Probably you have no IPX support in " "your kernel\n"); } close (s); return -1; } sprintf (errmsg, "%s: ioctl", progname); if (ioctl (s, SIOCAIPXPRISLT, &val) < 0) { perror (errmsg); close (s); return -1; } if (ioctl (s, SIOCAIPXITFCRT, &val) < 0) { perror (errmsg); close (s); return -1; } close (s); return 0; } int main (int argc, char *argv[]) { int interfaces; char *interface = "eth0"; int opt; int timeout = 3; unsigned long network[5] = {0,}; progname = argv[0]; while ((opt = getopt (argc, argv, "vi:ht:")) != EOF) { switch (opt) { case 'v': verbose = 1; break; case 'i': interface = optarg; break; case 't': timeout = atoi (optarg); break; case 'h': help (); exit (1); default: usage (); exit (1); } } if (ipx_auto_off () < 0) { exit (1); } interfaces = ipx_interfaces (); if (interfaces > 0) { fprintf (stderr, "%s must be run with no interfaces configured." " Found %d interface%s.\n", progname, interfaces, interfaces == 1 ? "" : "s"); exit (1); } if (interfaces < 0) { fprintf (stderr, "%s: %s\n", progname, strerror (interfaces)); exit (1); } probe_frame (interface, IPX_FRAME_8022, timeout, &(network[0])); probe_frame (interface, IPX_FRAME_8023, timeout, &(network[1])); probe_frame (interface, IPX_FRAME_SNAP, timeout, &(network[2])); probe_frame (interface, IPX_FRAME_ETHERII, timeout, &(network[3])); if (verbose == 0) { if (network[0] != 0) { printf ("%s %8.8lX\n", frame_name (IPX_FRAME_8022), network[0]); } if (network[1] != 0) { printf ("%s %8.8lX\n", frame_name (IPX_FRAME_8023), network[1]); } if (network[2] != 0) { printf ("%s %8.8lX\n", frame_name (IPX_FRAME_SNAP), network[2]); } if (network[3] != 0) { printf ("%s %8.8lX\n", frame_name (IPX_FRAME_ETHERII), network[3]); } } return 0; }