solaris x86 dlpi changes.

Joost Mulders mail at j-mulders.demon.nl
Mon Feb 26 23:17:58 UTC 2001


Hi Ted,

Here's is a diff against dlpi.c from 3.0b2pl18. There are two enhancements in 
it:

1. faster packetfilter
2. no need to use raw dlpi or hack
3. minors

1. faster packetfilter
The diff re-introduces the use of the ENF_CAND packetfilter operator. 
In the diff that is applied to pl18, the ENF_AND operator was used because I
couldn't get ENF_CAND to work consistantly on both sparc and intel. The reason
for this was just confision at my side. There is no difference in the behaviour
of ENF_CAND between sparc and intel. It just works fine on both.

The usage of ENF_CAND instead of ENF_AND makes the packetfilter a bit faster. 
With ENF_AND, each packet undergoes always two or three comparisons 
(ethertype (depending on raw), port and udp). With ENF_CAND, the packetfilter 
bails out as soon there is a mismatch.

2. no need to use raw dlpi or hack
In the previous diff it was necessary to define USE_DLPI_RAW or SOL_X86_DLPI\
_SAP_HACK in order to send packets properly on x86 over dlpi. Again, this was 
caused completely by confusion at my side. When assembling an ethernet packet,
the ethertype (ETHERTYPE_IP) must go in there in network byte order. When using 
plain dlpi, the ethertype was incorrectly assembled in hostorder which failed
on intel. When using raw dlpi, the packet was correctly assembled by
assemble_udp_ip_header (). This led me to think that there was a bug in the x86
if modules somewhere that clobbered with the ethertype field. Not true. 

3. minors
These are not enhancements but just changes in order for me to learn and 
understand the code. There were two functions that I removed: dlpi_makeaddr () 
and dlpi_parseaddr (). They were only called once and I moved their
functionality to the place where needed. They being a function made reading and
understanding the code difficult.

Also, I stored the (dlpi) sap length and the interface's broadcast address in
the structure interface_info. They were hard coded as -2 and 0xffffff.
These changes fix nothing but seemed more appropriate to me. If you don't like
it, they are easily to revert. Just ring.


I think these changes finally complete the fix for the solaris x86 dlpi problem.
When applied, solaris just works with plain- and raw dlpi, regardless of
running on sparc or intel.


I tested the diff on what was available to me:
 x86 solaris 8 with elx, cc + gcc
 x86 solaris 8 with iprb,cc + gcc
 sparc solaris 8 with le, gcc
 sparc solaris 2.6 with le, gcc
 

Regards,

Joost.

 
========================= cut here: common/dlpi.c ==========================
*** common/dlpi.c.orig  Mon Feb 26 21:37:31 2001
- common/dlpi.c Mon Feb 26 21:42:17 2001
***************
*** 130,152 ****
  #define DLPI_MAXDLBUF         8192    /* Buffer size */
  #define DLPI_MAXDLADDR                1024    /* Max address size */
  #define DLPI_DEVDIR           "/dev/" /* Device directory */
- #define DLPI_DEFAULTSAP               0x0800  /* IP protocol */
- #define DLPI_DEFAULTSAP               0x0800  /* IP protocol */
- static void dlpi_makeaddr PROTO ((unsigned char *physaddr, int physaddrlen,
-                                 unsigned char *sap, int saplen,
-                                 unsigned char *buf));
- static void dlpi_parseaddr PROTO ((unsigned char *buf,
-                                  unsigned char *physaddr,
-                                  int physaddrlen, unsigned char *sap,
-                                  int saplen));
  
- static void dlpi_makeaddr PROTO ((unsigned char *physaddr, int physaddrlen,
-                                 unsigned char *sap, int saplen,
-                                 unsigned char *buf));
- static void dlpi_parseaddr PROTO ((unsigned char *buf,
-                                  unsigned char *physaddr,
-                                  int physaddrlen, unsigned char *sap,
-                                  int saplen));
  static int dlpiopen PROTO ((char *ifname));
  static int dlpiunit PROTO ((char *ifname));
  static int dlpiinforeq PROTO ((int fd));
- 130,136 ----
***************
*** 211,219 ****
        int unit;
        long buf [DLPI_MAXDLBUF];
        union DL_primitives *dlp;
-       /*
-        * Get information about the provider.
-        */
  
        dlp = (union DL_primitives *)buf;
  
- 195,200 ----
***************
*** 222,234 ****
            log_fatal ("Can't open DLPI device for %s: %m", info -> name);
        }
  
-       /*
-        * Get information about the provider.
-        */
  
        /*
!        * Submit a DL_INFO_REQ request, to find
!        * the dl_mac_type and dl_provider_style
         */
        if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
            log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
- 203,212 ----
            log_fatal ("Can't open DLPI device for %s: %m", info -> name);
        }
  
  
        /*
!        * Submit a DL_INFO_REQ request, to find the dl_mac_type and 
!          * dl_provider_style
         */
        if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) {
            log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name);
***************
*** 246,256 ****
                info -> hw_address.hbuf [0] = HTYPE_FDDI;
                break;
              default:
!               log_fatal ("%s: unknown DLPI MAC type %ld",
!                      info -> name,
!                      dlp -> info_ack.dl_mac_type);
                break;
            }
        }
  
        if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
- 224,244 ----
                info -> hw_address.hbuf [0] = HTYPE_FDDI;
                break;
              default:
!               log_fatal ("%s: unsupported DLPI MAC type %ld",
!                      info -> name, dlp -> info_ack.dl_mac_type);
                break;
            }
+             /*
+              * copy the sap length and broadcast address of this interface
+              * to interface_info. This fixes nothing but seemed nicer than to
+              * assume -2 and ffffff.
+              */
+             info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length;
+             info -> dlpi_broadcast_addr.hlen = 
+              dlp -> info_ack.dl_brdcst_addr_length;
+             memcpy (info -> dlpi_broadcast_addr.hbuf, 
+              (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, 
+              dlp -> info_ack.dl_brdcst_addr_length);
        }
  
        if (dlp -> info_ack.dl_provider_style == DL_STYLE2) {
***************
*** 269,275 ****
        /*
         * Bind to the IP service access point (SAP), connectionless (CLDLS).
         */
!       if (dlpibindreq (sock, DLPI_DEFAULTSAP, 0, DL_CLDLS, 0, 0) < 0
            || dlpibindack (sock, (char *)buf) < 0) {
            log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
        }
- 257,263 ----
        /*
         * Bind to the IP service access point (SAP), connectionless (CLDLS).
         */
!       if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0
            || dlpibindack (sock, (char *)buf) < 0) {
            log_fatal ("Can't bind DLPI device for %s: %m", info -> name);
        }
***************
*** 415,422 ****
  {
  #ifdef USE_DLPI_PFMOD
        struct packetfilt pf;
!       struct ip iphdr;
!       u_short offset;
  #endif
  
        /* Open a DLPI device and hang it on this interface... */
- 403,410 ----
  {
  #ifdef USE_DLPI_PFMOD
        struct packetfilt pf;
!         struct ip iphdr;
!         u_int16_t offset;
  #endif
  
        /* Open a DLPI device and hang it on this interface... */
***************
*** 432,448 ****
  
  #if defined (USE_DLPI_RAW)
  # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
!       /*
!        * ethertype == ETHERTYPE_IP
!        */
!       offset = 12;
!       pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
!       pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_EQ;
!       pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
  # else
  # define ETHER_H_PREFIX (0)
! # endif /* USE_DLPI_RAW */
! 
        /*
         * The packets that will be received on this file descriptor
         * will be IP packets (due to the SAP that was specified in
- 420,435 ----
  
  #if defined (USE_DLPI_RAW)
  # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */
!     /*
!      * ethertype == ETHERTYPE_IP
!      */
!     offset = 12;
!     pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
!     pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
!     pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
  # else
  # define ETHER_H_PREFIX (0)
! # endif / * USE_DLPI_RAW */
        /*
         * The packets that will be received on this file descriptor
         * will be IP packets (due to the SAP that was specified in
***************
*** 456,484 ****
          /*
           * BOOTPS destination port
           */
!         offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_short);
          pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
!         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_EQ;
!         /* local_port is already in network byte order */
          pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
! # if defined (USE_DLPI_RAW)
!         /* AND this result with the result of ETHERTYPE_IP */
!         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_AND;
! # endif
          /*
           * protocol should be udp. this is a byte compare, test for
           * endianess.
           */
!         offset = ETHER_H_PREFIX + ((u_char *)&(iphdr.ip_p) - (u_char *) &iphdr);
          pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
          pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
          pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
!         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_EQ;
!         pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
!         /* AND this result with the result of local_port */
!         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_AND;
  
- 
        /* Install the filter... */
        if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
                      sizeof (pf), (char *)&pf) < 0) {
- 443,464 ----
          /*
           * BOOTPS destination port
           */
!         offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t);
          pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
!         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
          pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
! 
          /*
           * protocol should be udp. this is a byte compare, test for
           * endianess.
           */
!         offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *) &iphdr);
          pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2);
          pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND;
          pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF);
!         pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND;
!       pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
  
        /* Install the filter... */
        if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM,
                      sizeof (pf), (char *)&pf) < 0) {
***************
*** 543,552 ****
        double ih [1536 / sizeof (double)];
        unsigned char *dbuf = (unsigned char *)ih;
        unsigned dbuflen;
-       unsigned char sap [2];
        unsigned char dstaddr [DLPI_MAXDLADDR];
        unsigned addrlen;
-       int saplen;
        int result;
        int fudge;
  
- 523,530 ----
***************
*** 559,566 ****
        /* Assemble the headers... */
  #ifdef USE_DLPI_RAW
        assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
!       if (dbuflen > sizeof hh) /* hh is too small! */
!               abort ();
        fudge = dbuflen % 4; /* IP header must be word-aligned. */
        memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
        dbuflen += fudge;
- 537,544 ----
        /* Assemble the headers... */
  #ifdef USE_DLPI_RAW
        assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto);
!       if (dbuflen > sizeof hh)
!               log_fatal ("send_packet: hh buffer too small.\n");
        fudge = dbuflen % 4; /* IP header must be word-aligned. */
        memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen);
        dbuflen += fudge;
***************
*** 578,623 ****
  #ifdef USE_DLPI_RAW
        result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
  #else
        /*
!        * a bug on intel causes a sap type of 0x0800 to appear on the wire as 0x0000.
!        * a bug on intel causes a sap type of 0x0000 to appear on the wire as 0x0800.
!        * .uhhmmm..
!        *
!        * at least the elxl (3com) and iprb (intel) drivers `need' this hack on 2.8.
!        */
! #if defined (SOL_X86_DLPI_SAP_HACK)
!       sap [0] = 0x00;
!       sap [1] = 0x00;
! #else                   /* sparc and others, as it should be. */
!       sap [0] = 0x08;
!       sap [1] = 0x00;
! #endif
  
!       saplen = -2;            /* -2 indicates a two byte SAP at the end
!                                  of the address */
  
!       /* Setup the destination address */
!       if (hto && hto -> hlen == interface -> hw_address.hlen) {
!               dlpi_makeaddr (&hto -> hbuf [1],
!                              hto -> hlen - 1, sap, saplen, dstaddr);
!       } else {
!           /* XXX: Assumes broadcast addr is all ones */
!           /* Really should get the broadcast address as part of the
!            * dlpiinforeq, and store it somewhere in the interface structure.
!            */
!           unsigned char bcast_ether [DLPI_MAXDLADDR];
  
-           memset ((char *)bcast_ether, 0xFF,
-                   interface -> hw_address.hlen - 1);
-           dlpi_makeaddr (bcast_ether, interface -> hw_address.hlen - 1,
-                          sap, saplen, dstaddr);
-       }
-       addrlen = interface -> hw_address.hlen - 1 + ABS (saplen);
- 
-       /* Send the packet down the wire... */
        result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
                                  0, 0, dbuf, dbuflen);
! #endif
        if (result < 0)
                log_error ("send_packet: %m");
        return result;
- 556,607 ----
  #ifdef USE_DLPI_RAW
        result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge);
  #else
+ 
        /*
!          * Setup the destination address (DLSAP) in dstaddr 
!          *
!          * If sap_length < 0 we must deliver the DLSAP as phys+sap. 
!          * If sap_length > 0 we must deliver the DLSAP as sap+phys.
!          *
!          * sap = Service Access Point == ETHERTYPE_IP
!          * sap + datalink address is called DLSAP in dlpi speak.
!          */
!         { /* ENCODE DLSAP */
!           unsigned char phys [DLPI_MAXDLADDR];
!           unsigned char sap [4];
!           int sap_len = interface -> dlpi_sap_length;
!           int phys_len = interface -> hw_address.hlen - 1;
  
!           /* sap = htons (ETHERTYPE_IP) kludge */
!           memset (sap, 0, sizeof (sap));
! # if (BYTE_ORDER == LITTLE_ENDIAN)
!           sap [0] = 0x00;
!           sap [1] = 0x08;
! # else
!           sap [0] = 0x08;
!           sap [1] = 0x00;
! # endif
  
!         if (hto && hto -> hlen == interface -> hw_address.hlen)
!              memcpy ( phys, (char *) &hto -> hbuf [1], phys_len);
!           else 
!              memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, 
!               interface -> dlpi_broadcast_addr.hlen);
!            
!           if (sap_len < 0) { 
!              memcpy ( dstaddr, phys, phys_len);
!              memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len));
!           }
!           else {
!              memcpy ( dstaddr, (void *) sap, sap_len);
!              memcpy ( (char *) &dstaddr [sap_len], phys, phys_len);
!           }
!         addrlen = phys_len + ABS (sap_len);
!       } /* ENCODE DLSAP */
  
        result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen,
                                  0, 0, dbuf, dbuflen);
! #endif /* USE_DLPI_RAW */
        if (result < 0)
                log_error ("send_packet: %m");
        return result;
***************
*** 633,642 ****
        struct hardware *hfrom;
  {
        unsigned char dbuf [1536];
-       unsigned char sap [2];
        unsigned char srcaddr [DLPI_MAXDLADDR];
        unsigned long srcaddrlen;
-       int saplen;
        int flags = 0;
        int length = 0;
        int offset = 0;
- 617,624 ----
***************
*** 655,675 ****
            return length;
        }
  
! #ifndef USE_DLPI_RAW
!       /* Copy sender info */
!       /* XXX: Assumes ethernet, where SAP comes at end of haddr */
!       saplen = -2;
!       if (hfrom && (srcaddrlen ==
!                     ABS (saplen) + interface -> hw_address.hlen - 1)) {
!               hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
!               hfrom -> hlen = interface -> hw_address.hlen;
!               dlpi_parseaddr (srcaddr, &hfrom -> hbuf [1],
!                               interface -> hw_address.hlen - 1, sap, saplen);
!       } else if (hfrom) {
!               memset (hfrom, '\0', sizeof *hfrom);
!       }
! #endif
  
        /* Decode the IP and UDP headers... */
        bufix = 0;
  #ifdef USE_DLPI_RAW
- 637,673 ----
            return length;
        }
  
! # if !defined (USE_DLPI_RAW)
!         /*
!          * Copy the sender's hw address into hfrom
!          * If sap_len < 0 the DLSAP is as phys+sap.
!          * If sap_len > 0 the DLSAP is as sap+phys.
!          *
!          * sap is discarded here.
!          */
!         { /* DECODE DLSAP */
!           int sap_len = interface -> dlpi_sap_length;
!           int phys_len = interface -> hw_address.hlen - 1;
  
+           if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) {
+             hfrom -> hbuf [0] = interface -> hw_address.hbuf [0];
+             hfrom -> hlen = interface -> hw_address.hlen;
+             
+             if (sap_len < 0) {
+               memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len);
+             }
+             else {
+               memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len],
+                 phys_len);
+             }
+           } 
+           else if (hfrom) {
+             memset (hfrom, '\0', sizeof *hfrom);
+           }
+         } /* DECODE_DLSAP */
+ 
+ # endif /* !defined (USE_DLPI_RAW) */
+ 
        /* Decode the IP and UDP headers... */
        bufix = 0;
  #ifdef USE_DLPI_RAW
***************
*** 722,767 ****
  
  #define DLPI_MAXWAIT          15      /* Max timeout */
  
- static void dlpi_makeaddr (physaddr, physaddrlen, sap, saplen, buf)
-       unsigned char *physaddr;
-       int physaddrlen;
-       unsigned char *sap;
-       int saplen;
-       unsigned char *buf;
- {
-       /*
-        * If the saplen is negative, the SAP goes at the end of the address,
-        * otherwise it goes at the beginning.
-        */
-       if (saplen >= 0) {
-               memcpy ((char *)buf, (char *)sap, saplen);
-               memcpy ((char *)&buf [saplen], (char *)physaddr, physaddrlen);
-       } else {
-               memcpy ((char *)buf, (char *)physaddr, physaddrlen);
-               memcpy ((char *)&buf [physaddrlen], (char *)sap, 0 - saplen);
-       }
- }
  
- static void dlpi_parseaddr (buf, physaddr, physaddrlen, sap, saplen)
-       unsigned char *buf;
-       unsigned char *physaddr;
-       int physaddrlen;
-       unsigned char *sap;
-       int saplen;
- {
-       /*
-        * If the saplen is negative, the SAP is at the end of the address,
-        * otherwise it is at the beginning.
-        */
-       if (saplen >= 0) {
-               memcpy ((char *)sap, (char *)buf, saplen);
-               memcpy ((char *)physaddr, (char *)&buf [saplen], physaddrlen);
-       } else {
-               memcpy ((char *)physaddr, (char *)buf, physaddrlen);
-               memcpy ((char *)sap, (char *)&buf [physaddrlen], 0 - saplen);
-       }
- }
- 
  /*
   * Parse an interface name and extract the unit number
   */
- 720,726 ----
========================= cut here: common/dlpi.c ==========================


========================= cut here: includes/dhcpd.h ==========================
*** includes/dhcpd.h    Sat Feb 24 01:14:12 2001
- includes/dhcpd.h.orig Mon Feb 26 22:08:35 2001
***************
*** 756,765 ****
  
        /* Only used by DHCP client code. */
        struct client_state *client;
- # if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE)
-       int dlpi_sap_length;
-       struct hardware dlpi_broadcast_addr;
- # endif /* DLPI_SEND || DLPI_RECEIVE */  
  };
  
  struct hardware_link {
- 756,761 ----
========================= cut here: includes/dhcpd.h ==========================


More information about the dhcp-hackers mailing list