[ Previous | Next | Contents | Home | Search ]
Fibre Channel Adapter/1063 User's Guide and Reference

Raw Sockets API

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:

Supported Socket System Calls

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:

Opening a Raw Socket Connection

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() Call

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

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:

NS_FCTYPE Enables an application to filter only on a specific entity.
NS_8022_LLC_DSAP    Enables an application to filter on DSAP only, within an entity.
NS_8022_LLC_DSAP_SNAP Enables an application to filter on DSAP and SNAP, within a entity.
NS_TAP_USER Enables an application to receive ALL packets received by the driver.

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() */

Transmitting Data

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.

FC MAC Header

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:

Expiration Security header type 0x4
Network header type 0x5
Association header type 0x6
Device header type 0x7
struct scbndd_opt_hdr {
    uchar   type;     /* one of they header types mentioned above*/
    uchar   rsvd;     /* reserved */ 
    ushort  len;      /* length of this header */
};

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.

Receiving Data

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.

Issuing ioctls

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)

where:

fd Is the socket file descriptor.
cmd Is the ioctl command to be issued. For FC, the only valid command is the NDD_GEN_STATS command.
arg Is a pointer to the nddctl structure, which is found in the <sys/ndd_var.h> include file. The nddctl structure contains a pointer to the statistics structure and the length of the statistics structure.

NDD_GENSTATS_T ioctl

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.


[ Previous | Next | Contents | Home | Search ]