CAP/support/ethertalk/dlip.c
2015-03-18 22:05:00 +01:00

316 lines
6.7 KiB
C

static char rcsid[] = "$Author: djh $ $Date: 91/02/15 23:06:01 $";
static char rcsident[] = "$Header: dlip.c,v 2.1 91/02/15 23:06:01 djh Rel $";
static char revision[] = "$Revision: 2.1 $";
/*
* dlip.c - Simple "protocol" level interface to DLI
*
* Provides ability to read/write packets at ethernet level
*
* Copyright (c) 1988 by The Trustees of Columbia University
* in the City of New York.
*
* Permission is granted to any individual or institution to use,
* copy, or redistribute this software so long as it is not sold for
* profit, provided that this notice and the original copyright
* notices are retained. Columbia University nor the author make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
*
* Edit History:
*
* April 3, 1988 CCKim Created
*
*/
static char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
Columbia University in the City of New York";
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netdnet/dli_var.h>
#include <netat/appletalk.h>
#include "../uab/proto_intf.h"
typedef struct ephandle { /* ethernet protocol driver handle */
int inuse; /* true if inuse */
int fd; /* file descriptor of socket */
int protocol; /* ethernet protocol */
int socket; /* ddp socket */
struct sockaddr_dl sdli; /* dli interface: to send with */
struct sockaddr_dl rdli; /* dli interface: to receive with */
} EPHANDLE;
private inited = FALSE;
private EPHANDLE ephlist[MAXOPENPROT];
extern char interface[50];
/*
* setup for particular device devno
* all pi_open's will go this device
*
*/
export
pi_setup()
{
int i;
if (!inited) {
for (i = 0 ; i < MAXOPENPROT; i++)
ephlist[i].inuse = FALSE;
(void)init_fdlistening();
inited = TRUE; /* don't forget now */
}
}
/*
* Open up a protocol handle:
* user level data:
* file descriptor
* protocol
*
* returns -1 and ephandle == NULL if memory allocation problems
* returns -1 for other errors
* return 0 for okay
*/
export int
pi_open(protocol, sock, dev, devno)
int protocol;
int sock;
char *dev;
int devno;
{
struct ephandle *eph;
struct sockaddr_dl *dl;
int s, i;
for (i = 0; i < MAXOPENPROT; i++) {
if (!ephlist[i].inuse)
break;
}
if (i == MAXOPENPROT)
return(0); /* nothing */
eph = &ephlist[i]; /* find handle */
dl = &eph->sdli; /* point */
dl->dli_family = AF_DLI;
strcpy(dl->dli_device.dli_devname, dev);
dl->dli_device.dli_devnumber = devno;
dl->dli_substructype = DLI_ETHERNET;
/* update these */
dl->choose_addr.dli_eaddr.dli_ioctlflg = DLI_EXCLUSIVE;
dl->choose_addr.dli_eaddr.dli_protype = protocol;
if ((s = socket(AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0)
return(-1);
if (bind(s, dl, sizeof(struct sockaddr_dl)) < 0) {
close(s);
return(-1);
}
bcopy(dl, &eph->rdli, sizeof(struct sockaddr_dl));
eph->inuse = TRUE;
eph->fd = s;
eph->protocol = protocol;
eph->socket = sock;
return(i+1); /* skip zero */
}
/* returns TRUE if machine will see own broadcasts */
export int
pi_delivers_self_broadcasts()
{
return(TRUE);
}
export int
pi_close(edx)
int edx;
{
if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
return(-1);
fdunlisten(ephlist[edx-1].fd); /* toss listener */
close(ephlist[edx-1].fd);
ephlist[edx-1].inuse = 0;
return(0);
}
export int
pi_get_ethernet_address(edx,ea)
int edx;
u_char *ea;
{
struct ifdevea buf;
struct ephandle *eph;
if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
return(-1);
eph = &ephlist[edx-1]; /* find handle */
sprintf(buf.ifr_name, "%s%d",eph->sdli.dli_device.dli_devname,
eph->sdli.dli_device.dli_devnumber);
if (ioctl(eph->fd,SIOCRPHYSADDR, &buf) < 0) {
perror("iotcl");
return(-1);
}
bcopy(buf.current_pa, ea, DLI_EADDRSIZE);
return(0);
}
export
pi_listener(edx, listener, arg)
int edx;
int (*listener)();
caddr_t arg;
{
if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
return(-1);
fdlistener(ephlist[edx-1].fd, listener, arg, edx);
return(0);
}
export
pi_listener_2(edx, listener, arg1, arg2)
int edx;
int (*listener)();
caddr_t arg1;
int arg2;
{
if (edx < 1 || edx > MAXOPENPROT || !ephlist[edx-1].inuse)
return(-1);
fdlistener(ephlist[edx-1].fd, listener, arg1, arg2);
}
export int
pi_readv(edx, iov, iovlen)
int edx;
struct iovec *iov;
int iovlen;
{
struct msghdr msg;
int cc;
struct ephandle *eph ;
struct ethernet_addresses *ea;
if (edx < 1 || edx > MAXOPENPROT)
return(-1);
eph = &ephlist[edx-1];
if (!eph->inuse)
return(-1);
msg.msg_iov = iov+1;
msg.msg_iovlen = iovlen-1;
msg.msg_name = (caddr_t)&eph->rdli;
msg.msg_namelen = sizeof(eph->rdli);
msg.msg_accrights = 0;
msg.msg_accrightslen = 0;
if ((cc = recvmsg(eph->fd, &msg, 0)) < 0) {
perror("recvmsg");
return(cc);
}
ea = (struct ethernet_addresses *)iov[0].iov_base;
ea->etype = eph->protocol;
/* check length -- naw */
bcopy(eph->rdli.choose_addr.dli_eaddr.dli_target, ea->saddr, EHRD);
bcopy(eph->rdli.choose_addr.dli_eaddr.dli_dest, ea->daddr, EHRD);
return(cc+iov[0].iov_len);
}
export int
pi_read(edx, buf, bufsiz)
int edx;
caddr_t buf;
int bufsiz;
{
struct iovec iov[2];
struct ethernet_addresses ea;
int cc;
iov[0].iov_base = (caddr_t)&ea;
iov[0].iov_len = sizeof(ea);
iov[1].iov_base = (caddr_t)buf;
iov[1].iov_len = bufsiz;
cc = pi_readv(edx, iov, 2);
return(cc - sizeof(ea));
}
export int
pi_reada(fd, buf, bufsiz, eaddr)
int fd;
caddr_t buf;
int bufsiz;
char *eaddr;
{
struct iovec iov[2];
int cc;
iov[0].iov_base = (caddr_t)eaddr;
iov[0].iov_len = 14;
iov[1].iov_base = (caddr_t)buf;
iov[1].iov_len = bufsiz;
if ((cc = readv(fd, iov, 2)) < 0) {
perror("abread");
return(cc);
}
return(cc - 14);
}
export int
pi_write(edx, buf, buflen, eaddr)
int edx;
caddr_t buf;
int buflen;
char *eaddr;
{
struct iovec iov[1];
iov[0].iov_base = buf;
iov[0].iov_len = buflen;
return(pi_writev(edx, iov, 1, eaddr));
}
export int
pi_writev(edx, iov, iovlen, eaddr)
int edx;
struct iovec *iov;
int iovlen;
char *eaddr;
{
struct ephandle *eph;
struct msghdr msg;
int cc;
if (edx < 1 || edx > MAXOPENPROT || eaddr == NULL)
return(-1);
eph = &ephlist[edx-1];
if (!eph->inuse)
return(-1);
bcopy(eaddr, eph->sdli.choose_addr.dli_eaddr.dli_target, DLI_EADDRSIZE);
msg.msg_name = (caddr_t)&eph->sdli;
msg.msg_namelen = sizeof(eph->sdli);
msg.msg_accrights = 0;
msg.msg_accrightslen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = iovlen;
cc = sendmsg(eph->fd, &msg, 0);
return(cc);
}