ftp.nice.ch/pub/next/unix/network/system/cap.5.0.s.tar.gz#/cap_5.0/lib/cap/abkip.c

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; /* 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.