From: els@icf.hrb.com (Eric L. Schott)
Newsgroups: comp.dcom.lans.ethernet
Subject: Help writing to /dev/nit
Date: 10 Nov 92 20:50:13 EST
Organization: HRB Systems, Inc.

With SunOS 4.1.2, I am attempting to open an Ethernet interface
to send/receive my own protocol.  I have the receive side working,
put I cannot send.  Has any one done this and have some sample code?
Can someone tell me what I am doing wrong?  I
  open /dev/nit
  push pf
  build and set filter
  bind to device (le0)
  flush
I am then able to use read to read discrete message.  However write
does not appear to send any thing on net.  Portions of source follow.
-- 

Eric L. Schott,    HRB Systems, Inc.    814/238-4311     els@icf.hrb.com
  "As we acquire more knowledge, things do not become more comprehensible
   but more mysterious."                  Albert Schweitzer, "Paris Notes"
--

static char	SCCS_id[] = "%W%";
/*
 *%*- -starsis -dpr12
 *%security @control & handling@
 *%classification UNCLASSIFIED
 *%s1text  JPxxMI_Sun_IO
 *%s2text  JPxxMI_Sun_IO Overview
 *%nofill
 *%nojustify
 *
 *	DATE:				%G%
 *
 *	VERSION:			%I%
 *
 *	UNIT CLASSIFICATION:		UNCLASSIFIED
 *
 *	ROUTINE CLASSIFICATION:		UNCLASSIFIED
 *
 *%s3text JPxxMI_Sun_IO Description
 *
 *	(U) The JPxxMI_Sun_IO provides Sun Ethernet I/O for the boot daemon.
 *
 *%s3text JPxxMI_Sun_IO Entry and Exit Conditions
 *
 *	(U) The functions within the JPxxMI_Sun_IO software are called
 *	as needed based upon their prototypes.
 *
 *%s3text JPxxMI_Sun_IO Equipment Environment
 *
 *	(U) The JPxxMI_Sun_IO software has been developed to run
 *	in the following environments:
 *	       Sun4	    (SunOS 4.1.x)
 *
 *%s3error JPxxMI_Sun_IO Error & Message Handling
 *.
 *.	(U) These routines return all error as a return status.
 *.
 *%s2text JPxxMI_Sun_IO Commons and Data Items
 *	(U) This section contains a list of all the interfaces used 
 *	by this unit.
 *
 *%s3edi JPxxMI_Sun_IO External Commons and Data Items
 */
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/stropts.h>		/* RMSGD */

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in.h>


#include <netdb.h>

#include <net/nit.h>
#include <net/nit_if.h>			 /* NIOCBIND */
#include <net/nit_pf.h>			 /* NIOCSETF */
#include <net/packetfilt.h>		 /* NIOCSETF */
#if 0
#include <net/nit_buf.h>
#endif

#define ERROR -1
#define OK 0
#define TRUE 1
#define FALSE 0
/*
 *%s3idi JPxxMI_Sun_IO TARSIS Internal Commons and Data Items
 */
#include <JPCOMDEF.h>
#include <JP_JBOODEF_Boot_Definitions.h>
#include <JPxxMI_Sun_IO_Prototypes.h>


nm_ether_print_number(addr)
struct ether_addr *addr;
{
  printf ("%02x-%02x-%02x-%02x-%02x-%02x",
	  addr->ether_addr_octet[0],
	  addr->ether_addr_octet[1],
	  addr->ether_addr_octet[2],
	  addr->ether_addr_octet[3],
	  addr->ether_addr_octet[4],
	  addr->ether_addr_octet[5]);
  return;


}




/*
 *%s3ldi JPxxCM Local Commons and Data Items
 *
 *  None.
 *
 */

/********************* JPxxMI_Open_Interface ***********************
 *%s2text JPxxMI_Open_Interface
 *
 *%s3text JPxxMI_Open_Interface Overview
 *
 *	(U) JPxxMI_Open_Interface is used to ...
 *
 *%s4text JPxxMI_Open_Interface Description
 *
 *	ROUTINE CLASSIFICATION:		UNCLASSIFIED
 *
 *	(U) JPxxMI_Open_Interface searches ...
 *
 *	(U) The proc_ptr argumument ...
 *
 *	(U) If 'thisProcess' is located, ...
 *  
 *%s4ldi JPxxMI_Open_Interface Calling Parameters
 *
 *	(U) The calling parameters for this routine are:
 *  
 *	    
 */
I_32 JPxxMI_open_interface		 /* OK or ERROR */
  (
   interface
  )

struct JBOODEF_Interface_Info * interface;
/*
 *.		(U) Interface structure which holds key information about
 *.		this interface.
 *.
 *.		Type:		 Input/Output
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

/*
 *%s4ldi JPxxMI_Open_Interface Local Data Items
 */
{
  int	socket_fd;
/*
 *.		(U) Socket for ethernet interface.
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  static struct ether_header eh;
/*
 *.		(U) Ethernet header.
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  static struct packetfilt pf;
/*
 *.		(U) packet filter for nit_pf
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  struct strioctl si;
/*
 *.		(U) structure for ioctl
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  struct timeval timeout;
/*
 *.		(U) timeout for ioctl
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  struct ifreq ifr;
/*
 *.		(U) interface request struct
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  u_long if_flags;
/*
 *.		(U) modes for interface
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  int  ret;
/*
 *.		(U) status from system services.
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  register u_short *fwp=pf.Pf_Filter;
/*
 *.		(U) pointer to walk through packet filter build.
 *.
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

  u_short offset;
/*
 *.		(U) scratch variable.
 *.

 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

/*
 *%s3text  JPxxMI_Open_Interface Design
 *%s4segment JPxxMI_Open_Interface
 */
/*
 ***********
 *  open nit interface
 *  push packet filter
 *  establish packet filter
 *  request interface
 *  get interface address
 *  flush any input
 ***********
 */


  if ((socket_fd = open("/dev/nit", O_RDWR)) < 0) 
    {
    perror("/dev/nit");
    return(ERROR);
    }

  /* arrange to get discrete messages from the STREAM */
  ioctl(socket_fd, I_SRDOPT, (char*)RMSGD);
  si.ic_timout = INFTIM;
  if ((ret = ioctl(socket_fd, I_PUSH, "pf")) < 0)
    {
    perror("pf push");
    return(ERROR);
    }

#if defined(MULITICAST_FILTER)
  /* Use packet filter based upon entire multicast address */
  offset = ((u_int) &eh.ether_dhost.ether_addr_octet[0] - 
	    (u_int) &eh.ether_dhost) /
	      sizeof(u_short);
  *fwp++ = ENF_PUSHWORD+offset;
  *fwp++ = ENF_PUSHLIT | ENF_EQ;
  *fwp++ = htons( (multicastaddr[0]<<8) + multicastaddr[1]);
  offset = ((u_int) &eh.ether_dhost.ether_addr_octet[2] - 
	    (u_int) &eh.ether_dhost) /
	      sizeof(u_short);
  *fwp++ = ENF_PUSHWORD+offset;
  *fwp++ = ENF_PUSHLIT | ENF_EQ;
  *fwp++ = htons( (multicastaddr[2]<<8) + multicastaddr[3]);
  *fwp++ = ENF_CNAND;
  offset = ((u_int) &eh.ether_dhost.ether_addr_octet[4] - 
	    (u_int) &eh.ether_dhost) /
	      sizeof(u_short);
  *fwp++ = ENF_PUSHWORD+offset;
  *fwp++ = ENF_PUSHLIT | ENF_EQ;
  *fwp++ = htons( (multicastaddr[4]<<8) + multicastaddr[5]);
#endif
#if !defined(NO_PROTOCOL_FILTER)
  /* Add packet filter passed upon protocol */
  offset = ((u_int) &eh.ether_type - (u_int) &eh.ether_dhost) /
    sizeof(u_short);
  *fwp++ = ENF_PUSHWORD+offset;
  *fwp++ = ENF_PUSHLIT | ENF_EQ;
  *fwp++ = htons(JBOODEF_ENET_PROTOCOL);
#endif
#if defined(MULITICAST_FILTER) && !defined(NO_PROTOCOL_FILTER)
  *fwp++ = ENF_AND;
#endif
  pf.Pf_FilterLen = fwp - &pf.Pf_Filter[0];
  si.ic_cmd = NIOCSETF;
  si.ic_len = sizeof(pf) ;
  si.ic_dp = (char*)&pf;
  if ((ret = ioctl(socket_fd, I_STR, (char*)&si)) < 0) 
    {
    perror("nit_ioctl_setfilter");
    return(ERROR);
    }

  /* request the interface */
  strncpy(ifr.ifr_name, interface->interface_name, sizeof(ifr.ifr_name));
  ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
  si.ic_cmd = NIOCBIND;
  si.ic_len = sizeof ifr;
  si.ic_dp = (char*)&ifr;
  if ((ret = ioctl(socket_fd, I_STR, (char*)&si)) < 0) 
    {
    perror(ifr.ifr_name);
    return(ERROR);
    }

  /* get interface address */
  si.ic_cmd = SIOCGIFADDR;
  si.ic_len = sizeof(ifr) ;
  si.ic_dp = (char*)&ifr;
  if ((ret = ioctl(socket_fd, I_STR, (char*)&si)) < 0) 
    {
    perror("nit_ioctl_gifaddr");
    return(ERROR);
    }
  memcpy (&(interface->host_enet_addr),
	  &ifr.ifr_addr.sa_data[0],
	  sizeof(struct ether_addr));

  /* Establish multicast address */
#if defined(MULITICAST_FILTER)
  memcpy (&ifr.ifr_addr.sa_data[0],multicastaddr,sizeof(multicastaddr));
  si.ic_cmd = SIOCADDMULTI;
  si.ic_len = sizeof(ifr) ;
  si.ic_dp = (char*)&ifr;
  if ((ret = ioctl(socket_fd, I_STR, (char*)&si)) < 0) 
    {
    perror("nit_ioctl_addmulti");
    return(ERROR);
    }
#endif
  
  /* Flush any input */
  ioctl(socket_fd, I_FLUSH, (char*)FLUSHR);

  interface->socket_fd = socket_fd;
  return(OK);
/*
 *%newpage
 */
}


/********************* JPxxMI_receive_request ***********************
 *%s2text JPxxMI_receive_request
 *
 *%s3text JPxxMI_receive_request Overview
 *
 *	(U) JPxxMI_receive_request receives a request from any of the
 *	active interfaces.
 *
 *%s4text JPxxMI_receive_request Description
 *
 *	ROUTINE CLASSIFICATION:		UNCLASSIFIED
 *
 *%s4ldi JPxxMI_receive_request Calling Parameters
 *
 *	(U) The calling parameters for this routine are:
 *  
 *	    
 */
I_32 JPxxMI_receive_request
  (
   boot_request,
   boot_request_size,
   interfaces,
   active_interfaces,
   received_interface_index
  )
    
struct JBOODEF_Msg * boot_request;
/*
 *.		(U) Location to store received boot request.
 *.
 *.		Type:		 Output
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

I_32 boot_request_size;
/*
 *.		(U) Size of receive buffer.
 *.
 *.		Type:		 Input
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

struct JBOODEF_Interface_Info interfaces[];
/*
 *.		(U) Table of active ethernet interfaces.
 *.
 *.		Type:		 Input
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

I_32 active_interfaces;
/*
 *.		(U) Number of active interfaces.
 *.
 *.		Type:		 Input
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

I_32 *received_interface_index;
/*
 *.		(U) returns index of interface which received message.
 *.
 *.		Type:		 Output
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

/*
 *%s4ldi JPxxMI_receive_request Local Data Items
 */
{
  static fd_set           read_fds; 
/*
 *.             (U) List of file descriptors used by a select statement
 *.                 to wait for pending input.
 *.
 *.             Units:           N/A
 *.             Accuracy:        N/A
 *.             Precision:       N/A
 *.             Range:           N/A
 *.             
 */

  static I_32 first_call = TRUE;
/*
 *.             (U) Indicates first call to routine.
 *.
 *.             Units:           BOOLEAN
 *.             Accuracy:        N/A
 *.             Precision:       N/A
 *.             Range:           TRUE or FALSE
 *.             
 */

  I_32 rc;
/*
 *.             (U) Function status.
 *.
 *.             Units:           N/A
 *.             Accuracy:        N/A
 *.             Precision:       N/A
 *.             Range:           N/A
 *.             
 */

  I_32 i;
/*
 *.             (U) Loop counter.
 *.
 *.             Units:           N/A
 *.             Accuracy:        N/A
 *.             Precision:       N/A
 *.             Range:           N/A
 *.             
 */

/*
 *%s3text  JPxxMI_receive_request Design
 *%s4segment JPxxMI_receive_request
 */
/*
 ***********
 *  if ....
 *  else .....
 *  endif
 ***********
 */
 loop_again:
  FD_ZERO(&read_fds);
  for (i=0; i<active_interfaces; i++)
    {
    FD_SET(interfaces[i].socket_fd,&read_fds);
    }
  do
    {
    rc = select(FD_SETSIZE,read_fds,NULL,NULL,NULL);
    }
  while (rc <= 0);
  for (i=0; i<active_interfaces; i++)
    {
    if (FD_ISSET(interfaces[i].socket_fd,&read_fds)) goto exit_loop;
    }
  goto loop_again;			 /* all tested; nothing up */
  
 exit_loop:
  *received_interface_index = i;
  rc = read(interfaces[i].socket_fd,boot_request,boot_request_size);
  
  return(rc);
/*
 *%newpage
 */
}



/********************* JPxxMI_write_message ***********************
 *%s2text JPxxMI_write_message
 *
 *%s3text JPxxMI_write_message Overview
 *
 *	(U) JPxxMI_write_message writes a boot response packet to the ethernet.
 *
 *%s4text JPxxMI_write_message Description
 *
 *	ROUTINE CLASSIFICATION:		UNCLASSIFIED
 *
 *%s4ldi JPxxMI_write_message Calling Parameters
 *
 *	(U) The calling parameters for this routine are:
 *  
 *	    
 */
I_32 JPxxMI_write_message
  (
   boot_response,
   response_size,
   interface
  )
    
struct JBOODEF_Msg * boot_response;
/*
 *.		(U) Boot response message
 *.
 *.		Type:		 Input
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

I_32 response_size;
/*
 *.		(U) number of byte in response message
 *.
 *.		Type:		 Input
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

struct JBOODEF_Interface_Info * interface;
/*
 *.		(U) specifies interface to write
 *.
 *.		Type:		 Input
 *.		Units:		 N/A
 *.		Accuracy:	 N/A
 *.		Precision:	 N/A
 *.		Range:		 N/A
 *.		
 */

/*
 *%s4ldi JPxxMI_write_message Local Data Items
 */
{

/*
 *%s3text  JPxxMI_write_message Design
 *%s4segment JPxxMI_write_message
 */
/*
 ***********
 *  write boot_response to ethernet
 *  if write ok
 *    return(OK)
 *  else 
 *    return(ERROR)
 *  endif
 ***********
 */
  static struct strbuf control;
  static struct strbuf data;
  static struct sockaddr dest;
  int rc;

  printf ("dst=");
  nm_ether_print_number (&(boot_response->ether_header.ether_dhost));
  printf (" src=");
  nm_ether_print_number (&(boot_response->ether_header.ether_shost));
  printf ("\n");
#if 0
  dest.sa_family = AF_UNSPEC;
  memcpy(&dest.sa_data[0],&(boot_response->ether_header.ether_dhost),14);

  control.len = sizeof(boot_response->ether_header);
  control.buf = (char *) &dest;
  data.len=response_size;
  data.buf = (char *) boot_response;
  rc = putmsg(interface->socket_fd,&control,&data,0);
  if (rc < 0)
#else
  rc = write(interface->socket_fd, boot_response, response_size);
  if (rc != response_size)
#endif
    return(ERROR);
  else
    return(OK);
/*
 *%newpage
 */
}

Newsgroups: comp.dcom.lans.ethernet,comp.sys.novell