/* emutli.c 17-Nov-95 */ /* * One short try to emulate TLI with SOCKETS. */ /* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * Some of the Code in this module is stolen from the following * Programms: ipx_interface, ipx_route, ipx_configure, which was * written by Greg Page, Caldera, Inc. * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ #include #include #include #include #include #include #include #include "net.h" #include #include #include #include #include #include #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif static int locipxdebug=0; static int have_ipx_started=0; static void set_sock_debug(int sock) { if (setsockopt(sock, SOL_SOCKET, SO_DEBUG, &locipxdebug, sizeof(int))==-1){ perror("setsockopt SO_DEBUG"); } } static void sock2ipxadr(ipxAddr_t *i, struct sockaddr_ipx *so) { memcpy(i->net, &so->sipx_network, IPX_NET_SIZE + IPX_NODE_SIZE); memcpy(i->sock, &so->sipx_port, 2); } static void ipx2sockadr(struct sockaddr_ipx *so, ipxAddr_t *i) { memcpy(&so->sipx_network, i->net, IPX_NET_SIZE + IPX_NODE_SIZE); memcpy(&so->sipx_port, i->sock, 2); } void set_emu_tli(int ipx_debug) { locipxdebug = ipx_debug; } int init_ipx(char *device, uint32 *network, uint32 intnet, int frame, char *frame_name, int ipx_debug) { int sock=-1; int result=-1; #ifndef OLD_KERNEL_IPX struct ifreq id; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; int i; memset(&id, 0, sizeof(struct ifreq)); strcpy(id.ifr_name, device); locipxdebug = ipx_debug; sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); if (socket < 0) { perror("EMUTLI:init_ipx"); exit(1); } /* NUN DEBUG ein bzw. ausschalten */ set_sock_debug(sock); /* remove old ipx_interface */ if (*network) { sipx->sipx_network = 0L; sipx->sipx_special = IPX_INTERNAL; sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_DLTITF; (void) ioctl(sock, SIOCSIFADDR, &id); sipx->sipx_special = IPX_PRIMARY; sipx->sipx_network = 0L; sipx->sipx_family = AF_IPX; sipx->sipx_type = frame; sipx->sipx_action = IPX_DLTITF; (void) ioctl(sock, SIOCSIFADDR, &id); have_ipx_started++; } sipx->sipx_special = IPX_PRIMARY; /* IPX_SPECIAL_NONE */ /* IPX_INTERNAL */ /* IPX_PRIMARY */ sipx->sipx_network = htonl(*network); sipx->sipx_type = frame; sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_CRTITF; /* anlegen */ /* IPX_DLTITF ist loeschen */ i = 0; do { result = ioctl(sock, SIOCSIFADDR, &id); } while ((++i < 5) && (result < 0) && (errno == EAGAIN)); if (result) { switch (errno) { case EEXIST: DPRINTF(("Primary network already selected.\n")); result = 0; /* not a reallly error */ break; case EADDRINUSE: fprintf(stderr, "Network number (0X%08lX) already in use.\n", htonl(sipx->sipx_network)); break; case EPROTONOSUPPORT: fprintf(stderr, "Invalid frame type (%s).\n", frame_name); break; case ENODEV: fprintf(stderr, "No such device (%s).\n", id.ifr_name); break; case ENETDOWN: fprintf(stderr, "Requested device (%s) is down.\n", id.ifr_name); break; case EINVAL: fprintf(stderr, "Invalid device (%s).\n", id.ifr_name); break; case EAGAIN: fprintf(stderr, "Insufficient memory to create interface.\n"); break; default: perror("ioctl:SIOCSIFADDR"); break; } /* switch */ } #else /* alte Kernel Version vor ???? */ struct ipx_route_def rt; locipxdebug = ipx_debug; rt.ipx_network=htonl(*network); rt.ipx_router_network=IPX_ROUTE_NO_ROUTER; strncpy(rt.ipx_device,"eth0",16); rt.ipx_flags=frame; sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX); if(sock==-1) { perror("EMUTLI:init_ipx"); exit(1); } set_sock_debug(sock); result = ioctl(sock,SIOCADDRT,(void *)&rt); if (result && errno == EEXIST) result =0; if (result) perror("ioctl"); #endif #if 1 if (!*network) { struct sockaddr_ipx ipxs; int maxplen=sizeof(struct sockaddr_ipx); memset((char*)&ipxs, 0, sizeof(struct sockaddr_ipx)); ipxs.sipx_family=AF_IPX; if (bind(sock, (struct sockaddr*)&ipxs, sizeof(struct sockaddr_ipx))==-1){ perror("EMUTLI:init_ipx"); result = -1; } else { if (getsockname(sock, (struct sockaddr*)&ipxs, &maxplen) == -1){ perror("EMUTLI:init_ipx"); result = -1; } else *network=ntohl(ipxs.sipx_network); } if (sock > -1) close(sock); } #endif close(sock); if (result) exit(1); return(result); } void exit_ipx(char *devname, uint32 network, int frame) { if (have_ipx_started) { int sock=-1; int result=-1; struct ifreq id; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)&id.ifr_addr; int i; memset(&id, 0, sizeof(struct ifreq)); strcpy(id.ifr_name, devname); sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); if (socket < 0) { perror("EMUTLI:exit_ipx"); return; } /* Switch DEBUG off */ locipxdebug = 0; set_sock_debug(sock); /* remove routes */ sipx->sipx_network = 0L; sipx->sipx_special = IPX_INTERNAL; sipx->sipx_family = AF_IPX; sipx->sipx_action = IPX_DLTITF; (void) ioctl(sock, SIOCSIFADDR, &id); sipx->sipx_special = IPX_PRIMARY; sipx->sipx_network = 0L; sipx->sipx_family = AF_IPX; sipx->sipx_type = frame; sipx->sipx_action = IPX_DLTITF; (void) ioctl(sock, SIOCSIFADDR, &id); close(sock); } } void myipx_route_add(unsigned char *dest_net, unsigned char *route_net, unsigned char *route_node) { struct rtentry rd; int i; int result; int sock; /* Router */ struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway; /* Target */ struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst; rd.rt_flags = RTF_GATEWAY; memcpy(&(st->sipx_network), dest_net, IPX_NET_SIZE); memcpy(&(sr->sipx_network), route_net, IPX_NET_SIZE); memcpy(sr->sipx_node, route_node, IPX_NODE_SIZE); if ( (sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX)) < 0){ perror("EMUTLI:myipx_route_add"); return; } sr->sipx_family = st->sipx_family = AF_IPX; i = 0; do { result = ioctl(sock, SIOCADDRT, &rd); i++; } while ((i < 5) && (result < 0) && (errno == EAGAIN)); if (result) { switch (errno) { case ENETUNREACH: fprintf(stderr, "Router network (%08X) not reachable.\n", htonl(sr->sipx_network)); break; case EEXIST: case EADDRINUSE: break; default: perror("add route ioctl"); break; } } close(sock); } void myipx_route_del(unsigned char *net) { struct rtentry rd; int i; int result; int sock; /* Router */ struct sockaddr_ipx *sr = (struct sockaddr_ipx *)&rd.rt_gateway; /* Target */ struct sockaddr_ipx *st = (struct sockaddr_ipx *)&rd.rt_dst; rd.rt_flags = RTF_GATEWAY; memcpy(&(st->sipx_network), net, IPX_NET_SIZE); if ( (sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX)) < 0){ perror("EMUTLI:myipx_route_del"); return; } sr->sipx_family = st->sipx_family = AF_IPX; i = 0; do { result = ioctl(sock, SIOCDELRT, &rd); i++; } while ((i < 5) && (result < 0) && (errno == EAGAIN)); /* errors doesn't matter here */ close(sock); } int t_open(char *name, int open_mode, char * p) { int opt=1; int sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); if (sock < 0) return(sock); /* NUN DEBUG ein bzw. ausschalten */ set_sock_debug(sock); /* NUN Broadcast erlauben */ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt,sizeof(opt))==-1){ perror("setsockopt SO_BROADCAST"); close(sock); return(-1); } return(sock); } int t_bind(int sock, struct t_bind *a_in, struct t_bind *a_out) { struct sockaddr_ipx ipxs; int maxplen=sizeof(struct sockaddr_ipx); memset((char*)&ipxs, 0, sizeof(struct sockaddr_ipx)); ipxs.sipx_family=AF_IPX; if (a_in != (struct t_bind*) NULL && a_in->addr.len == sizeof(ipxAddr_t)) ipx2sockadr(&ipxs, (ipxAddr_t*) (a_in->addr.buf)); ipxs.sipx_network = 0L; if (bind(sock, (struct sockaddr*)&ipxs, sizeof(struct sockaddr_ipx))==-1) { char xx[100]; sprintf(xx, "TLI-BIND socket Nr:0x%x", (int)GET_BE16(&(ipxs.sipx_port))); perror(xx); return(-1); } if (a_out != (struct t_bind*) NULL) { if (getsockname(sock, (struct sockaddr*)&ipxs, &maxplen) == -1){ perror("TLI-GETSOCKNAME"); return(-1); } sock2ipxadr((ipxAddr_t*) (a_out->addr.buf), &ipxs); DPRINTF(("T_BIND ADR=%s\n", visable_ipx_adr((ipxAddr_t *) a_out->addr.buf ) )); } return(0); } int t_unbind(int sock) { return(0); } int t_errno=0; void t_error(char *s) { perror(s); t_errno=0; } int t_close(int fd) { return(close(fd)); } int poll( struct pollfd *fds, unsigned long nfds, int timeout) /* z.Z. nur POLL-IN */ { fd_set readfs; /* fd_set writefs; fd_set exceptfs; */ struct pollfd *p = fds; struct timeval time_out; int k = (int)nfds; int result=-1; int high_f=0; FD_ZERO(&readfs); /* FD_ZERO(&writefs); FD_ZERO(&exceptfs); */ while (k--){ if (p->fd > -1 && (p->events & POLLIN)) { FD_SET(p->fd, &readfs); if (p->fd > high_f) high_f = p->fd; } p->revents=0; p++; } if (timeout > 1000) { time_out.tv_sec = timeout / 1000; time_out.tv_usec = 0; } else { time_out.tv_sec = 0; time_out.tv_usec = timeout*1000; } result = select(high_f+1, &readfs, NULL, NULL, &time_out); if (result < 0) return(-1); if (result) { int rest=result; k = (int)nfds; p = fds; while (k--){ if (p->fd > -1 && FD_ISSET(p->fd, &readfs)){ p->revents = POLLIN; if (! --rest) break; /* fertig */ } p++; } } return(result); } int t_rcvudata(int fd, struct t_unitdata *ud, int *flags) { struct sockaddr_ipx ipxs; int sz = sizeof(struct sockaddr_ipx); int result; ipxs.sipx_family=AF_IPX; if (ud->addr.maxlen < sizeof(ipxAddr_t)) return(-1); result = recvfrom(fd, ud->udata.buf, ud->udata.maxlen, 0, (struct sockaddr *) &ipxs, &sz); if (result < 0) return(result); if (ud->opt.maxlen) { *((uint8*)ud->opt.buf) = ipxs.sipx_type; ud->opt.len = 1; } ud->udata.len=result; sock2ipxadr((ipxAddr_t*) (ud->addr.buf), &ipxs); ud->addr.len = sizeof(ipxAddr_t); return(result); } int t_sndudata(int fd, struct t_unitdata *ud) { int result; struct sockaddr_ipx ipxs; memset(&ipxs, 0, sizeof(struct sockaddr_ipx)); ipxs.sipx_family=AF_IPX; if (ud->addr.len != sizeof(ipxAddr_t)) return(-1); ipx2sockadr(&ipxs, (ipxAddr_t*) (ud->addr.buf)); ipxs.sipx_type = (ud->opt.len) ? (uint8) *((uint8*)(ud->opt.buf)) : 0; result = sendto(fd,(void *)ud->udata.buf, ud->udata.len, 0, (struct sockaddr *) &ipxs, sizeof(ipxs)); if (result<0) { char xx[100]; sprintf(xx, "t_sndudata->result=%d, errno=%d\n", result, errno); perror(xx); } return(result); } int t_rcvuderr(int fd, struct t_uderr *ud) { return(0); }