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.