This is abkip.c in view mode; [Download] [Up]
/* * $Author: cck $ $Date: 88/05/19 13:14:04 $ * $Header: abkip.c,v 1.36 88/05/19 13:14:04 cck Rel $ * $Revision: 1.36 $ */ /* * abkip.c - KIP (UDP encapsulated DDP packets) network module * * abkip provides the interface from DDP to the outside world as it * sees it. It includes the DDP module "routeddp". * * NOTE: when running KIP, no other LAP protocols are allowed * * The justification for including parts of "lap", "ddp", etc. is that * that we are "gatewaying" and are allowed to do funny things at the * boundaries * * AppleTalk package for UNIX (4.2 BSD). * * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University * in the City of New York. * * * Edit History: * * June 14, 1986 Schilit Created. * June 18, 1986 CCKim Chuck's handler runs protocol * */ /* * The following list of exported routines is provided so you'll know what * have to be done to do another interface type (ethertalk, etc) * * EXPORTED ROUTINES: * * OSErr GetNodeAddress(int *mynode, int *mynet) * Return node addresses * int abInit(boolean dispay_message) * Initialize AppleTalk * int abOpen(int *returnsocket, int wantsocket, struct iovec iov[], iovlen) * Open a DDP socket * int abClose(int socket) * Close a DDP socket * void abnet_cacheit(word srcNet, byte srcNode) * Call in DDP protocol layer to tell the lower layer that * the last packet that came in was from srcNet, srcNode * int routeddp(struct iovec *iov, int iovlen) * This is the DDP incursion. With a full AppleTalk implementation, * this would be part of DDP (abddp2). This routes the DDP packet: * normally would decide where to send and then send via lap, with KIP * decides where and sends via UDP. * */ #include <stdio.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> #include <sys/param.h> #include <netinet/in.h> #include <netdb.h> #include <netat/appletalk.h> #include <netat/abnbp.h> /* for nbpNIS */ #include <netat/compat.h> /* to cover difference between bsd systems */ /* * Configuration defines * * NORECVMSG - no recvmsg * NOSENDMSG - no sendmsg * NEEDMSGHDR - no msghdr in sockets.h - define our own * */ #ifdef NORECVMSG # ifndef NEEDNETBUF # define NEEDNETBUF # endif #endif #ifdef NOSENDMSG # ifndef NEEDNETBUF # define NEEDNETBUF # endif #endif /* for forwarding */ /* These three define a lookaside */ /* could possibly be an array */ /* cf. ip_resolve */ private struct in_addr ipaddr_src; /* ip address */ /* ddp address */ private word ddp_srcnet; /* ddp network part */ private byte ddp_srcnode; /* ddp node part */ import struct in_addr bridge_addr; /* .. nearest known bridge */ private struct sockaddr_in from_sin; /* network struct of last packet rec. */ #define rebPort 902 /* 0x386 */ word rebport; /* used to hold swabbed rebPort */ private struct sockaddr_in abfsin; /* apple bus foreign socketaddr/internet */ import word this_net; /* our network number */ import byte this_node; /* our node number */ import word nis_net; /* network number of our nis */ import byte nis_node; /* node number of our nis */ import int ddp_protocol(); /* DDP protocol handler */ private int kip_get(); export DBUG dbug; /* debug flags */ /* BUG: bind doesn't work when lsin is on the stack! */ private struct sockaddr_in lsin; /* local socketaddr/internet */ private int skt2fd[ddpMaxSkt+1]; /* translate socket to file descriptor */ private int ddpskt2udpport[ddpMaxWKS+1]; /* ddp "wks" socket to udp port */ private LAP laph; /* don't really need this */ #ifdef notdef private char lapdata[lapMaxData]; private struct iovec lapiov[IOV_LAP_SIZE+1]; /* lap header + data */ #endif /* * OSErr GetNodeAddress(int *myNode,*myNet) * * GetNodeAddress returns the net and node numbers for the current * host. * * N.B. - the myNet address is in net (htons) format. * */ export OSErr GetNodeAddress(myNode,myNet) int *myNode,*myNet; { *myNode = this_node; *myNet = this_net; return(noErr); /* is ok */ } /* * ddp to udp wks translate table * */ struct wks { char *name; /* name of wks (as in /etc/services) */ int ddpport; /* ddp port to map from */ int udpport; /* udp port to map to */ int notinited; /* tried /etc/services? */ }; /* udpport is set to the old values for compatiblity */ /* insert in order to be nice */ #define WKS_entry(name, ddpsock) {(name), (ddpsock), ddpWKSUnix+(ddpsock), 1} private struct wks wks[] = { WKS_entry("at-rtmp",rtmpSkt), WKS_entry("at-nbp",nbpNIS), WKS_entry("at-echo",echoSkt), WKS_entry("at-zip",zipZIS), WKS_entry(NULL, 0) }; /* * Translate ddp socket to UDP port: returns 0 if no mapping * */ ddp2ipskt(ddpskt) int ddpskt; { struct wks *wksp; struct servent *serv; if (ddpskt < 0 || ddpskt > ddpMaxSkt) return(0); if (ddpskt & ddpWKS) /* 128+x means non-wks */ return(ddpskt + ddpNWKSUnix); if (ddpskt2udpport[ddpskt] < 0) { for (wksp = wks; wksp->name != NULL; wksp++) if (wksp->ddpport == ddpskt) { if ((serv = getservbyname(wksp->name, "udp")) != NULL) wksp->udpport = ntohs(serv->s_port); /* silliness */ if (dbug.db_ini) fprintf(stderr, "port for %s is %d\n",wksp->name,wksp->udpport); endservent(); ddpskt2udpport[ddpskt] = wksp->udpport; return(wksp->udpport); } ddpskt2udpport[ddpskt] = 0; } return(ddpskt2udpport[ddpskt]); } /* * initialize * */ export abInit(disp) { int i; for (i=0; i < ddpMaxSkt+1; i++) { skt2fd[i] = -1; /* mark all these as unused */ } for (i=0; i < ddpMaxWKS; i++) ddpskt2udpport[i] = -1; /* mark unknown */ rebport = htons(rebPort); /* swap to netorder */ init_fdlistening(); abfsin.sin_family = AF_INET; abfsin.sin_addr.s_addr = INADDR_ANY; openatalkdb(NULL); /* sets up this_* (take default file) */ if (disp) { printf("abInit: [ddp: %3d.%02d, %d]", ntohs(this_net)>>8, htons(this_net)&0xff, this_node); if (this_net != nis_net || this_node != nis_node) printf(", [NBP (atis) Server: %3d.%02d, %d]", ntohs(nis_net)>>8, htons(nis_net)&0xff, nis_node); printf(" starting\n"); } DDPInit(); #ifdef notdef /* nonsensical */ LAPOpenProtocol(lapDDP,ddp_protocol); /* open protocol */ #endif return(0); } /* * int abOpen(int *skt,rskt, iov, iovlen) * * abOpen opens the ddp socket in "skt" or if "skt" is zero allocates * and opens a new socket. Upon return "skt" contains the socket number * and the returned value is >=0 if no error, < 0 if error. * * iov should be an array of type "struct iov" of length at least * IOV_LAP_SIZE+1. Levels after IOV_LAP_LVL are assume to filled. * */ int abOpen(skt,rskt, iov, iovlen) int *skt; int rskt; struct iovec *iov; int iovlen; { int i,fd,err; word ipskt; #ifdef notdef /* could check iov not null and set to lapiov if not, etc */ /* but necessary since only (likely) client is ddp */ /* note: story is different for ethertalk, etc */ #endif /* good enough for now */ if (iov == NULL || iovlen < IOV_LAP_SIZE+1 || iovlen > IOV_READ_MAX) return(-1); if ((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0) { perror("abopen"); return(fd); } lsin.sin_family = AF_INET; lsin.sin_addr.s_addr = INADDR_ANY; *skt = (rskt == 0 ? ddpWKS : rskt); /* zero rskt is free choice */ ipskt = ddp2ipskt(*skt); /* translate into ip socket number */ if (ipskt == 0) /* bad socket? */ return(ddpSktErr); for (i=0; i < 128; i++,ipskt++,(*skt)++) { lsin.sin_port = htons(ipskt); if ((err = bind(fd, (struct sockaddr *)&lsin, sizeof(lsin))) == 0) break; if (rskt != 0) /* bind failed and wanted exact? */ return(err); /* yes... */ } if (err == 0 && i < 128) { iov[IOV_LAP_LVL].iov_base = (caddr_t)&laph; /* remember this */ iov[IOV_LAP_LVL].iov_len = lapSize; /* and this */ fdlistener(fd, kip_get, iov, iovlen); /* remember for later */ skt2fd[*skt] = fd; /* remember file descriptor for socket */ return(noErr); } perror("abopen bind"); close(fd); return(err); } /* * close off socket opened by abClose * */ export int abClose(skt) int skt; { int fd; if (skt < 0 || skt > ddpMaxSkt) { fprintf(stderr,"abClose: skt out of range\n"); exit(0); } fd = skt2fd[skt]; if (fd < 0) return(0); if (close(fd) != 0) perror("abClose"); /* some error... */ fdunlisten(fd); skt2fd[skt] = -1; /* mark as unused */ return(0); } #ifdef NEEDNETBUF #ifdef NEEDMSGHDR struct msghdr { caddr_t msg_name; /* name to send to */ int msg_namelen; /* size of name */ struct iovec *msg_iov; /* io vec */ int msg_iovlen; /* length */ int msg_accrights; /* dummy */ int msg_accrightslen; }; #endif /* buffer larger than maximum ddp pkt by far */ private char net_buffer[ddpMaxData*2]; #ifdef NOSENDMSG /* * limited sendmsg - limits to sizeof(net_buffer) * */ sendmsg(fd, msg, flags) int fd; struct msghdr *msg; int flags; { int err; int i, pos, len; struct iovec *iov; iov = msg->msg_iov; for (i=0, pos=0; i < msg->msg_iovlen; i++, iov++) { len = iov->iov_len; if (len+pos > sizeof(net_buffer)) /* if overflow */ len = sizeof(net_buffer)-pos; /* then limit */ bcopy(iov->iov_base, net_buffer+pos, len); pos+= len; if (len != iov->iov_len) /* we don't have any more space */ break; } len = pos; if ((err=sendto(fd,net_buffer,len,0,msg->msg_name,msg->msg_namelen)) < 0) perror("abwrite"); return(err); } #endif /* NO SENDMSG */ #ifdef NORECVMSG recvmsg(fd, msg, flags) int fd; struct msghdr *msg; int flags; { int err; int i, pos, len, blen; struct iovec *iov; err = recvfrom(fd, net_buffer, sizeof(net_buffer), 0, msg->msg_name, &msg->msg_namelen); if (err < 0) perror("abread"); for (blen=err,pos=0,i=0,iov=msg->msg_iov; i < msg->msg_iovlen; i++, iov++) { len = min(iov->iov_len, blen); if ((pos + len) > sizeof(net_buffer)) /* if asking for too much */ len = sizeof(net_buffer) - pos; /* then limit */ bcopy(net_buffer+pos, iov->iov_base, len); pos += len; blen -= len; /* either no more room or no more data */ if (len != iov->iov_len) break; } return(err); } #endif /* NO RECVMSG */ #endif private int kip_get(fd, iov, iovlen) int fd; struct iovec *iov; int iovlen; { struct msghdr msg; int len; LAP *lap; msg.msg_name = (caddr_t) &from_sin; msg.msg_namelen = sizeof(from_sin); msg.msg_iov = iov; msg.msg_iovlen = iovlen; msg.msg_accrights = 0; msg.msg_accrightslen = 0; if ((len = recvmsg(fd,&msg,0)) < 0) { perror("abread"); return(len); } if (iov->iov_len != lapSize) /* check */ return(-1); lap = (LAP *)iov->iov_base; switch (lap->type) { case lapDDP: return(ddp_protocol(iov+1, iovlen-1, len-lapSize)); break; default: return(-1); } return(-1); } /* * This is the DDP/UDP interface * */ /* srcNet and node of last incoming packet sent to DDP */ /* and valid */ export void abnet_cacheit(srcNet, srcNode) word srcNet; byte srcNode; { ddp_srcnet = srcNet; /* remember where last packet came from */ ddp_srcnode = srcNode; ipaddr_src.s_addr = (from_sin.sin_port == rebport) ? 0 : from_sin.sin_addr.s_addr; } private int ip_resolve(ddpnet, ddpnode, iphost) word ddpnet; byte ddpnode; struct in_addr *iphost; { if (ipaddr_src.s_addr != 0 && ddpnet == ddp_srcnet && ddpnode == ddp_srcnode) iphost->s_addr = ipaddr_src.s_addr; else iphost->s_addr = bridge_addr.s_addr; } private LAP lap; export int routeddp(iov, iovlen) struct iovec *iov; int iovlen; { struct msghdr msg; word destskt; struct in_addr desthost; DDP *ddp; int err; int fd; ddp = (DDP *)iov[IOV_DDP_LVL].iov_base; /* pick out ddp header */ /* check ddp socket(s) for validity */ if ( ddp->srcSkt == 0 || ddp->srcSkt == ddpMaxSkt || ddp->dstSkt == 0 || ddp->dstSkt == ddpMaxSkt || (fd = skt2fd[ddp->srcSkt]) == -1 ) return(ddpSktErr); /* KIP routing code */ /* establish dest socket */ destskt = (word)htons(ddp2ipskt(ddp->dstSkt)); if (destskt == 0) /* byte swapped zero is still zero */ return(ddpSktErr); /* resolve mapping */ ip_resolve(ddp->dstNet, ddp->dstNode, &desthost); /* establish a dummy lap header */ lap.type = lapDDP; lap.dst = ddp->dstNode; lap.src = this_node; iov[IOV_LAP_LVL].iov_base = (caddr_t) ⪅ /* LAP header */ iov[IOV_LAP_LVL].iov_len = lapSize; /* size */ /* send through */ abfsin.sin_addr = desthost; abfsin.sin_port = destskt; msg.msg_name = (caddr_t) &abfsin; msg.msg_namelen = sizeof(abfsin); msg.msg_iov = iov; msg.msg_iovlen = iovlen; msg.msg_accrights = 0; msg.msg_accrightslen = 0; if ((err = sendmsg(fd,&msg,0)) < 0) perror("abwrite"); return(err); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.