The raw sockets API is very similar to the traditional TCP/IP sockets API. A raw sockets application distinguishes itself from other raw sockets applications by the use of an entity number. Each application must specify an entity number (range of 0xe0 - 0xff) when opening the raw sockets for transmitting and receiving. This entity number is used by the driver to do receive demuxing so that it can deliver the receive packets to the correct user applications.
Every application using the raw sockets API should contain the following include files:
Note: This is not an inclusive list of include files. These are all of the include files needed to program using the examples listed in this section. Other applications may require additional include files to compile properly.
The following socket commands are supported under the raw sockets application interface:
The following socket commands are not supported with the raw sockets application interface:
There are a number of steps involved in opening a raw socket connection. The first step is to open a socket using the socket() command. After opening the socket, it is necessary to issue a bind() and/or a connect() command to open the driver. If the driver is being opened to transmit data, then it is necessary to issue both the bind() and the connect() commands. The structure sockaddr_ndd_fcs, found in sys/fcsdmx_user.h, should be used in place of the sockaddr structure for the bind() and connect() calls.
struct sockaddr_ndd_fcs { u_char sndd_fcs_len; u_char sndd_fcs_family; u_char sndd_fcs_nddname[NDD_MAXNAMELEN]; u_int sndd_fcs_filterlen; struct fcsdmx_filter sndd_fcs; };
The connect() system call is used to open a connection to the driver that is only capable of issuing ioctl()'s to the device. An application will not be allowed to transmit and receive data if only the connect() call has been done. However, a connect() call must be issued after the bind() call to allow an application to transmit data using the sendmsg() and send() system calls. When issuing a connect(), it is not necessary to fill in the sndd_fcs_filterlen and sndd_fcs fields of the sockaddr_ndd_fcs structure.
Following is an example of opening a raw socket connection using the connect() command:
/* * NAME: fcs_open * * DESCRIPTION: Will open a raw socket connection to an FCS * device for issuing IOCTL's only. * */ int fcs_open(devname) char *devname; / *name of the device to open */ { int fd; /* file descriptor */ struct sockaddr_ndd_fcs sa; /* FC sockaddr structure */ /* * Open a socket connection */ fd = socket(AF_NDD, SOCK_DGRAM, 0); if (fd < 0) { perror("socket"); return(1); } /* * Fill in the sockaddr_ndd_fcs structure and issue connect() * call. */ bzero((char *)&sa, sizeof(sa)); sa.sndd_fcs_len = sizeof(sa); sa.sndd_fcs_family = AF_NDD; bcopy(devname, sa.sndd_fcs_nddname, 8); sa.sndd_fcs_filterlen = 0; if (connect(fd, &sa, sizeof(sa)) < 0) { perror("connect"); return(3); } } /* End of fcs_open() */
The bind() call is used to open a connection to the driver that is a full connection to an FC device. An application will be allowed to transmit and receive data as well as issue ioctl's after issuing the bind() call. However, the connect() system call must be issued. The bind() call also allows a user to issue a receive filter. The receive filter specifies information that will allow the driver to filter the type of packets that the application will receive. There are four types of filters that can be specified:
Following is an example of opening a raw socket connection using the bind() command:
/* * NAME: fcs_open * * DESCRIPTION: Will open a raw socket connection to an FCS * device for reading, writing and issuing ioctl's. * */ int fcs_open(devname) char *devname; /*name of the device to open*/ { int fd; /* file descriptor */ struct sockaddr_ndd_fcs sa; /* FC sockaddr structure */ /* * Open a socket connection */ fd = socket(AF_NDD, SOCK_DGRAM, 0); if (fd < 0) { perror("socket"); return(1); } /* * Fill in the sockaddr_ndd_fcs structure and issue bind() * call. */ bzero((char *)&sa, sizeof(sa)); sa.sndd_fcs_len = sizeof(sa); sa.sndd_fcs_family = AF_NDD; bcopy(devname, sa.sndd_fcs_nddname, 8); sa.sndd_fcs_filterlen = sizeof(fcsdmx_filter_t); sa.sndd_fcs_filtertype = NS_8022_LLC_DSAP; sa.sndd_fcs_dsap = 0xa; sa.sndd_fcs_orgcode = ""; sa.sndd_fcs_ethertype = 0; sa.sndd_fcs_entity_number = 0xe0; sa.sndd_fcs_num_buffers1 = 30; sa.sndd_fcs_buffer_size1 = 4096; sa.sndd_fcs_num_buffers2 = 40; sa.sndd_fcs_buffer_size2 = 65536; if (bind(fd, &sa, sizeof(sa)) , 0) { perror ("bind"); return(2); } } /* End of FCS_open() */
An application can use three different system calls to transmit data: the send(), sendmsg(), or the write() system calls. The application is required to preappend the FCS MAC header and any appropriate LLC headers before the data begins passing the data buffer to these system calls. The FC MAC header is a scbndd_hdr structure, which is found in the <sys/scbndd_user.h> include file. The LLC headers necessary depend on the type of protocol specified, along with the type of receive filter that was specified in the bind() system call.
If the application specified the NS_FCTYPE type of filter in the bind() system call, then the protocol is completely application-independent and the only required header is FC MAC. All other headers are up to the application.
If the application specified the NS_8022_DSAP type of filter in the bind() system call, then the user needs to have both the FCS MAC header and an ie2_llc_hdr structure, which can be found in the <net/nd_lan.h> include file. All other headers are up to the application.
If the application specified the NS_8022_DSAP_SNAP type of filter in the bind() system call, then the user needs to have both the FC MAC header and an ie2_llc_snaphdr structure, which can be found in the <net/nd_lan.h> include file. All other headers are up to the application.
The FC MAC header is required for all packets transmitted over the raw sockets (AF_NDD) interface. The header contains the entity number, the nport_address, and any optional headers that are being used by the application. Following is a definition of the FC MAC header:
struct scbndd_hdr { uchar unit_num; /* not used for Fibre Channel */ uchar entity_num; /* source and destination entity */ ushort opt_hdr_len; /*total length of the optional hdrs*/ uchar hw_addr[SCBNDD_ADDR_LEN]; /* hw address */ };
The optional headers are placed in the scbndd_opt_hdr structure, which is found in the <sys/scbndd_user.h> include file. There are four types of supported optional headers:
Following is an example of how to build a packet, both with optional headers and without optional headers:
An example packet with no optional headers and using an ie2_llc_hdr for an application that opened the socket with a filter type of NS_8022_DSAP: Bytes Info 1 unit number (Always set to zero) 2 entity number (range 0xe0 to 0xff) 3-4 total length of optional headers 5-10 nport_address (see Note) 11-13 LLC header (if necessary, based on protocol) 14-?? data packet
An example packet with 1 to 8 byte optional header and using an ie2_llc_hdr for an application that opened the socket with a filter type of NS_8022_DSAP: Bytes Info 1 unit number (Always set to zero) 2 entity number (range 0xe0 to 0xff) 3-4 total length of optional headers 5-10 hardware address (see Note) 11 low order 3 bits indicate type of optional header 12 reserved 13-14 length of this optional header 15-22 optional header(8 bytes for this example) 23-25 LLC header (if necessary) 25-?? data packet
Note: The FC hardware address is only 3 bytes long and should be in bytes 6 to 8.
An application can read data using one of three system calls: receive(), recvmsg(), or read(). The packets that the application will receive is determined by the filter that was set up by the application with the bind() system call. The packets will contain the same headers that were sent out by the transmitting application. The only exception is that the FC MAC header will contain the source nport_address instead of the destination nport_address.
There is only one ioctl available from the FC device driver. An application can issue the NDD_GET_STATS ioctl, which is defined in the <sys/ndd.h> include file, to get a snapshot of the FC statistics and to obtain their source nport_address. The application must use the following parameters to the ioctl routine:
ioctl(fd, cmd, arg)
The application is required to create a definition of the following structure to use for the NDD_GENSTATS_T ioctl:
struct fc_stats { ndd_genstats_t ndd_stats; /*General tx and rx stats for network head*/ scbndd_specstats_t scbspecstats; /*Specific stats for network head*/ ndd_genstats_t fcsgenstats; /*General tx and rx stats for adapter driver*/ fcs_specstats_t fcsspecstats; /*Specific stats for adapter driver*/ };
The device driver will fill this structure with the statistics. The definition of the ndd_genstat_t structure can be found in the <sys/ndd.h> include file. The definition of the scbndd_specstats_t structure can be found in the <sys/scbndd_user.h> include file. The definition of the fcs_specstats_t structure can be found in the <sys/fcs_user.h> include file.