ftp.nice.ch/pub/next/developer/resources/libraries/eni.a.tar.gz#/eni/libeni.c

This is libeni.c in view mode; [Download] [Up]

/*
    User level interface to the Ethernet.

    These routines constitute a library, that can be linked with user
    programs, to provide low level access to the Ethernet.

				    - Bill Heelan (wheelan@cs.mcgill.ca)
*/

#include <stdio.h>
#include <stdlib.h>
#include <mach.h>
#include <servers/netname.h>
#include <sys/message.h>
#include <net/etherdefs.h>
#include <errno.h>
#include "eni.h"
#include "libeni.h"
#include "messages.h"


#define ENI_PORT_NAME	"eni0"


extern int bcopy(char *src, char *dst, int len) ;


kern_return_t eni_errno = KERN_SUCCESS ;

static port_t eni_port ;    /* send packets and status requests */
static port_t rc_port ;	    /* receive return codes and status info here */
static port_t rpck_port ;   /* receive packets on this port */
static int init_success = 0 ;


/*
    Do necessary initializations.  Set up a separate message port to receive
    packets.

    Return 0 on success, -1 on failure.  In the case of failure set the
    variable 'eni_errno' to the value of the last kernel return code.
*/

int eni_init(void)
{
    kern_return_t r ;
    msg_return_t m ;
    struct m_init init_m ;


    eni_errno = 0 ;
    if(init_success)
    {
	eni_errno = EAGAIN ;
	return -1 ;
    }

    r = netname_look_up(name_server_port, "", ENI_PORT_NAME, &eni_port) ;
    if(r != NETNAME_SUCCESS)
    {
	eni_errno = ENXIO ;
	return -1 ;
    }

    r = port_allocate(task_self(), &rc_port) ;
    if(r != KERN_SUCCESS)
    {
	eni_errno = ENOBUFS ;
	return -1 ;
    }

    r = port_allocate(task_self(), &rpck_port) ;
    if(r != KERN_SUCCESS)
    {
	eni_errno = ENOBUFS ;
	return -1 ;
    }
    
    /*
	Give the kernel module access to the port on which we want to
	receive packets.
    */
    
    init_m.head.msg_simple = TRUE ;
    init_m.head.msg_size = sizeof init_m ;
    init_m.head.msg_type = MSG_TYPE_NORMAL ;
    init_m.head.msg_local_port = rpck_port ; /* receive packets here */
    init_m.head.msg_remote_port = eni_port ;
    init_m.head.msg_id = MSG_INIT ;

    if((m = msg_send((msg_header_t *)&init_m, MSG_OPTION_NONE, 0)) != SEND_SUCCESS)
    {
	eni_errno = ENOINIT ;
	return -1 ;
    }
    else
    {
	init_success = 1 ;
	return 0 ;
    }
}


/*
    Wait for a packet to be put on our receive queue.

    Return 0 on success, -1 if an error occurs.

    We must do a bit of massaging, since the packet in the message we get
    will have the format:

       daddr:saddr:type:utype:...data...

    while the user should see:

       daddr:saddr:utype:...data...

    (type is the frame type we have reserved, and utype is the frame type
    specified by the user.)
*/

int eni_get_packet(unsigned char *packet, int *dlen)
{
    msg_return_t m ;
    struct m_packet rpck_m ;


    eni_errno = 0 ;
    if( ! init_success)
    {
	eni_errno = ENOINIT ;
	return -1 ;
    }

    rpck_m.head.msg_size = sizeof rpck_m ;
    rpck_m.head.msg_local_port = rpck_port ;
    
    if((m = msg_receive((msg_header_t *)&rpck_m, MSG_OPTION_NONE, 0)) != RCV_SUCCESS)
    {
	eni_errno = ENXIO ;
	return -1 ;
    }
    else
    {
	*dlen = rpck_m.eh.data_length ;
#ifdef DEBUG
	fprintf(stderr, "eni_get_packet: got packet with data length %d.\n",
		*dlen) ;
#endif
	bcopy((char *)rpck_m.data, (char *)packet, 2 * ADDR_SIZE) ;
	bcopy((char *)(rpck_m.data + DATA_OFFSET), (char *)(packet + TYPE_OFFSET),
	      *dlen + TYPE_SIZE) ;
	return 0 ;
    }
}


/*
    Send an Ethernet packet to the machine whose hardware Ethernet address
    is given by 'dst_addr'.  'frame_type' is the value to be put into the
    type field of the packet, while 'data' and 'dlen' are a pointer to the
    packet data and the length of this data, respectively.

    Both 'dst_addr' and 'frame_type' are expected to already be in network
    byte order.

    Return 0 on sucess, -1 otherwise.
*/

int eni_send_packet(unsigned char *dst_addr, u_short frame_type, void *data,
		    int dlen)
{
    msg_return_t m ;
    struct m_reply_ret_code rep_m ;
    struct m_packet pck_m ;


    eni_errno = KERN_SUCCESS ;
    if( ! init_success)
    {
	eni_errno = ENOINIT ;
	return -1 ;
    }

    if(dlen > ENI_MTU)
    {
	eni_errno = E2BIG ;
	return -1 ;
    }

    pck_m.head.msg_simple = TRUE ;
    pck_m.head.msg_size = sizeof pck_m ;
    pck_m.head.msg_type = MSG_TYPE_NORMAL ;
    pck_m.head.msg_local_port = rc_port ;   /* return code port */
    pck_m.head.msg_remote_port = eni_port ;
    pck_m.head.msg_id = MSG_SEND_PACKET ;

    pck_m.type_1.msg_type_name = MSG_TYPE_BYTE ; /* ??? */
    pck_m.type_1.msg_type_size = sizeof pck_m.eh * 8 ;
    pck_m.type_1.msg_type_number = 1 ;
    pck_m.type_1.msg_type_inline = TRUE ;
    pck_m.type_1.msg_type_longform = FALSE ;
    pck_m.type_1.msg_type_deallocate = FALSE ;

    pck_m.eh.data_length = dlen ;
    pck_m.eh.frame_type = frame_type ;
    bcopy((char *)dst_addr, (char *)&pck_m.eh.daddr, ADDR_SIZE) ;

    pck_m.type_2.msg_type_name = MSG_TYPE_BYTE ;
    pck_m.type_2.msg_type_size = 8 ;
    pck_m.type_2.msg_type_number = ENI_MTU ; /* change to dlen+header+...? */
    pck_m.type_2.msg_type_inline = TRUE ;
    pck_m.type_2.msg_type_longform = FALSE ;
    pck_m.type_2.msg_type_deallocate = FALSE ;

    bcopy((char *)data, (char *)&pck_m.data[0], dlen) ;

#ifdef DEBUG
    fprintf(stderr, "eni_send_packet: sending packet with data length %d.\n",
	    dlen) ;
#endif

    if((m = msg_send((msg_header_t *)&pck_m, MSG_OPTION_NONE, 0)) != SEND_SUCCESS)
    {
	eni_errno = ENXIO ;
	return -1 ;
    }

    rep_m.head.msg_size = sizeof rep_m ;
    rep_m.head.msg_local_port = rc_port ;
    
    if((m = msg_receive((msg_header_t *)&rep_m, MSG_OPTION_NONE, 0)) != RCV_SUCCESS)
    {
	return 0 ;  /* We have to hope... */
    }
    else
    {
	return (eni_errno = rep_m.ret_code) == 0 ? 0 : -1 ;
    }
}


#if 0
/*
    Get statistics on the number of packet sent, received and errors.

    UNFINISHED.
*/

int eni_stats(struct eni_stats *s)
{
    msg_return_t m ;
    struct m_reply_stats sr_m ;
    

    sr_m.head.msg_simple = TRUE ;
    sr_m.head.msg_size = sizeof sr_m ;
    sr_m.head.msg_type = MSG_TYPE_NORMAL ;
    sr_m.head.msg_local_port = rc_port ;   /* return code port */
    sr_m.head.msg_remote_port = eni_port ;
    sr_m.head.msg_id = MSG_STATS ;

    sr_m.type.msg_type_name = MSG_TYPE_BYTE ; /* ??? */
    sr_m.type.msg_type_size = sizeof(struct eni_stats) * 8 ;
    sr_m.type.msg_type_number = 1 ;
    sr_m.type.msg_type_inline = TRUE ;
    sr_m.type.msg_type_longform = FALSE ;
    sr_m.type.msg_type_deallocate = FALSE ;

    m = msg_send((msg_header_t *)&sr_m, MSG_OPTION_NONE, 0) ;
    if(m != SEND_SUCCESS)
    {
	eni_errno = m ;
	return -1 ;
    }

    return 0 ;
}
#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.