Files
ncpfs/util/ipx_probe.c
ncpfs archive import c6c6fbe4ca Import ncpfs 2.1.1
2026-04-28 20:39:59 +02:00

408 lines
8.2 KiB
C

/*
* ipx_probe.c
*
* Check the network for frames currently active
*
* Copyright (C) 1996 by Volker Lendecke
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/ipx.h>
#include <linux/if.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
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;
}