lib, zebra: unify link layer type and hardware address handling

This removes the BSD specific usage of struct sockaddr_dl
hardware address. This unifies to use explict hw_addr member for
the address, and zebra specific enumeration for the link layer
type.

Additionally the zapi is updated to never send platform specific
structures over the wire, but the ll_type along with hw_addr_len
and hw_addr are now sent for all platforms.

Based on initial work by Paul Jakma.

Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index a71ab21..a48afd2 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -649,15 +649,6 @@
       /*
        * Get the Hardware Address
        */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-#ifndef SUNOS_5
-      if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
-        zlog_warn ("unsupported link layer");
-      else
-        memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl),
-                ETH_ALEN);
-#endif
-#else
       if (circuit->interface->hw_addr_len != ETH_ALEN)
         {
           zlog_warn ("unsupported link layer");
@@ -671,7 +662,6 @@
                   circuit->interface->ifindex, ISO_MTU (circuit),
                   snpa_print (circuit->u.bc.snpa));
 #endif /* EXTREME_DEBUG */
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
 
       circuit->u.bc.adjdb[0] = list_new ();
       circuit->u.bc.adjdb[1] = list_new ();
diff --git a/lib/if.c b/lib/if.c
index 4d4b656..3426212 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -1065,3 +1065,63 @@
   if (vrf_id == VRF_DEFAULT)
     iflist = NULL;
 }
+
+const char *
+if_link_type_str (enum zebra_link_type llt)
+{
+  switch (llt)
+    {
+#define llts(T,S) case (T): return (S)
+      llts(ZEBRA_LLT_UNKNOWN,               "Unknown");
+      llts(ZEBRA_LLT_ETHER,                 "Ethernet");
+      llts(ZEBRA_LLT_EETHER,                "Experimental Ethernet");
+      llts(ZEBRA_LLT_AX25,                  "AX.25 Level 2");
+      llts(ZEBRA_LLT_PRONET,                "PROnet token ring");
+      llts(ZEBRA_LLT_IEEE802,               "IEEE 802.2 Ethernet/TR/TB");
+      llts(ZEBRA_LLT_ARCNET,                "ARCnet");
+      llts(ZEBRA_LLT_APPLETLK,              "AppleTalk");
+      llts(ZEBRA_LLT_DLCI,                  "Frame Relay DLCI");
+      llts(ZEBRA_LLT_ATM,                   "ATM");
+      llts(ZEBRA_LLT_METRICOM,              "Metricom STRIP");
+      llts(ZEBRA_LLT_IEEE1394,              "IEEE 1394 IPv4");
+      llts(ZEBRA_LLT_EUI64,                 "EUI-64");
+      llts(ZEBRA_LLT_INFINIBAND,            "InfiniBand");
+      llts(ZEBRA_LLT_SLIP,                  "SLIP");
+      llts(ZEBRA_LLT_CSLIP,                 "Compressed SLIP");
+      llts(ZEBRA_LLT_SLIP6,                 "SLIPv6");
+      llts(ZEBRA_LLT_CSLIP6,                "Compressed SLIPv6");
+      llts(ZEBRA_LLT_ROSE,                  "ROSE packet radio");
+      llts(ZEBRA_LLT_X25,                   "CCITT X.25");
+      llts(ZEBRA_LLT_PPP,                   "PPP");
+      llts(ZEBRA_LLT_CHDLC,                 "Cisco HDLC");
+      llts(ZEBRA_LLT_RAWHDLC,               "Raw HDLC");
+      llts(ZEBRA_LLT_LAPB,                  "LAPB");
+      llts(ZEBRA_LLT_IPIP,                  "IPIP Tunnel");
+      llts(ZEBRA_LLT_IPIP6,                 "IPIP6 Tunnel");
+      llts(ZEBRA_LLT_FRAD,                  "FRAD");
+      llts(ZEBRA_LLT_SKIP,                  "SKIP vif");
+      llts(ZEBRA_LLT_LOOPBACK,              "Loopback");
+      llts(ZEBRA_LLT_LOCALTLK,              "Localtalk");
+      llts(ZEBRA_LLT_FDDI,                  "FDDI");
+      llts(ZEBRA_LLT_SIT,                   "IPv6-in-IPv4 SIT");
+      llts(ZEBRA_LLT_IPDDP,                 "IP-in-DDP tunnel");
+      llts(ZEBRA_LLT_IPGRE,                 "GRE over IP");
+      llts(ZEBRA_LLT_PIMREG,                "PIMSM registration");
+      llts(ZEBRA_LLT_HIPPI,                 "HiPPI");
+      llts(ZEBRA_LLT_IRDA,                  "IrDA");
+      llts(ZEBRA_LLT_FCPP,                  "Fibre-Channel PtP");
+      llts(ZEBRA_LLT_FCAL,                  "Fibre-Channel Arbitrated Loop");
+      llts(ZEBRA_LLT_FCPL,                  "Fibre-Channel Public Loop");
+      llts(ZEBRA_LLT_FCFABRIC,              "Fibre-Channel Fabric");
+      llts(ZEBRA_LLT_IEEE802_TR,            "IEEE 802.2 Token Ring");
+      llts(ZEBRA_LLT_IEEE80211,             "IEEE 802.11");
+      llts(ZEBRA_LLT_IEEE80211_RADIOTAP,    "IEEE 802.11 Radiotap");
+      llts(ZEBRA_LLT_IEEE802154,            "IEEE 802.15.4");
+      llts(ZEBRA_LLT_IEEE802154_PHY,        "IEEE 802.15.4 Phy");
+      default:
+        zlog_warn ("Unknown value %d", llt);
+        return "Unknown type!";
+#undef llts
+    }
+  return NULL;
+}
diff --git a/lib/if.h b/lib/if.h
index ad85dca..0cb2202 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -23,6 +23,66 @@
 
 #include "linklist.h"
 
+/* Interface link-layer type, if known. Derived from:
+ *
+ * net/if_arp.h on various platforms - Linux especially.
+ * http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
+ *
+ * Some of the more obviously defunct technologies left out.
+ */
+enum zebra_link_type {
+  ZEBRA_LLT_UNKNOWN = 0,
+  ZEBRA_LLT_ETHER,
+  ZEBRA_LLT_EETHER,
+  ZEBRA_LLT_AX25,
+  ZEBRA_LLT_PRONET,
+  ZEBRA_LLT_IEEE802,
+  ZEBRA_LLT_ARCNET,
+  ZEBRA_LLT_APPLETLK,
+  ZEBRA_LLT_DLCI,
+  ZEBRA_LLT_ATM,
+  ZEBRA_LLT_METRICOM,
+  ZEBRA_LLT_IEEE1394,
+  ZEBRA_LLT_EUI64,
+  ZEBRA_LLT_INFINIBAND,
+  ZEBRA_LLT_SLIP,
+  ZEBRA_LLT_CSLIP,
+  ZEBRA_LLT_SLIP6,
+  ZEBRA_LLT_CSLIP6,
+  ZEBRA_LLT_RSRVD,
+  ZEBRA_LLT_ADAPT,
+  ZEBRA_LLT_ROSE,
+  ZEBRA_LLT_X25,
+  ZEBRA_LLT_PPP,
+  ZEBRA_LLT_CHDLC,
+  ZEBRA_LLT_LAPB,
+  ZEBRA_LLT_RAWHDLC,
+  ZEBRA_LLT_IPIP,
+  ZEBRA_LLT_IPIP6,
+  ZEBRA_LLT_FRAD,
+  ZEBRA_LLT_SKIP,
+  ZEBRA_LLT_LOOPBACK,
+  ZEBRA_LLT_LOCALTLK,
+  ZEBRA_LLT_FDDI,
+  ZEBRA_LLT_SIT,
+  ZEBRA_LLT_IPDDP,
+  ZEBRA_LLT_IPGRE,
+  ZEBRA_LLT_IP6GRE,
+  ZEBRA_LLT_PIMREG,
+  ZEBRA_LLT_HIPPI,
+  ZEBRA_LLT_ECONET,
+  ZEBRA_LLT_IRDA,
+  ZEBRA_LLT_FCPP,
+  ZEBRA_LLT_FCAL,
+  ZEBRA_LLT_FCPL,
+  ZEBRA_LLT_FCFABRIC,
+  ZEBRA_LLT_IEEE802_TR,
+  ZEBRA_LLT_IEEE80211,
+  ZEBRA_LLT_IEEE80211_RADIOTAP,
+  ZEBRA_LLT_IEEE802154,
+  ZEBRA_LLT_IEEE802154_PHY,
+};
+
 /*
   Interface name length.
 
@@ -101,20 +161,10 @@
   unsigned int mtu;    /* IPv4 MTU */
   unsigned int mtu6;   /* IPv6 MTU - probably, but not neccessarily same as mtu */
 
-  /* Hardware address. */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  union {
-    /* note that sdl_storage is never accessed, it only exists to make space.
-     * all actual uses refer to sdl - but use sizeof(sdl_storage)!  this fits
-     * best with C aliasing rules. */
-    struct sockaddr_dl sdl;
-    struct sockaddr_storage sdl_storage;
-  };
-#else
-  unsigned short hw_type;
+  /* Link-layer information and hardware address */
+  enum zebra_link_type ll_type;
   u_char hw_addr[INTERFACE_HWADDR_MAX];
   int hw_addr_len;
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
 
   /* interface bandwidth, kbits */
   unsigned int bandwidth;
@@ -304,6 +354,7 @@
 extern void if_terminate (vrf_id_t, struct list **);
 extern void if_dump_all (void);
 extern const char *if_flag_dump(unsigned long);
+extern const char *if_link_type_str (enum zebra_link_type);
 
 /* Please use ifindex2ifname instead of if_indextoname where possible;
    ifindex2ifname uses internal interface info, whereas if_indextoname must
diff --git a/lib/zclient.c b/lib/zclient.c
index ca6a4c7..bd93d06 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -791,13 +791,10 @@
   ifp->mtu = stream_getl (s);
   ifp->mtu6 = stream_getl (s);
   ifp->bandwidth = stream_getl (s);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage));
-#else
+  ifp->ll_type = stream_getl (s);
   ifp->hw_addr_len = stream_getl (s);
   if (ifp->hw_addr_len)
     stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
 }
 
 static int
diff --git a/zebra/interface.c b/zebra/interface.c
index 411712d..8a9225a 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -705,9 +705,6 @@
 static void
 if_dump_vty (struct vty *vty, struct interface *ifp)
 {
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  struct sockaddr_dl *sdl;
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
   struct connected *connected;
   struct listnode *node;
   struct route_node *rn;
@@ -759,19 +756,7 @@
            if_flag_dump (ifp->flags), VTY_NEWLINE);
   
   /* Hardware address. */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  sdl = &ifp->sdl;
-  if (sdl != NULL && sdl->sdl_alen != 0)
-    {
-      int i;
-      u_char *ptr;
-
-      vty_out (vty, "  HWaddr: ");
-      for (i = 0, ptr = (u_char *)LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++)
-        vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr);
-      vty_out (vty, "%s", VTY_NEWLINE);
-    }
-#else
+  vty_out (vty, "  Type: %s%s", if_link_type_str (ifp->ll_type), VTY_NEWLINE);
   if (ifp->hw_addr_len != 0)
     {
       int i;
@@ -781,7 +766,6 @@
 	vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]);
       vty_out (vty, "%s", VTY_NEWLINE);
     }
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
   
   /* Bandwidth in kbps */
   if (ifp->bandwidth != 0)
diff --git a/zebra/interface.h b/zebra/interface.h
index 936156e..dbb33c5 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -196,6 +196,16 @@
   struct irdp_interface irdp;
 #endif
 
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+  union {
+    /* note that sdl_storage is never accessed, it only exists to make space.
+     * all actual uses refer to sdl - but use sizeof(sdl_storage)!  this fits
+     * best with C aliasing rules. */
+    struct sockaddr_dl sdl;
+    struct sockaddr_storage sdl_storage;
+  };
+#endif
+
 #ifdef SUNOS_5
   /* the real IFF_UP state of the primary interface.
    * need this to differentiate between all interfaces being
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index ba03498..10cc48c 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -20,6 +20,7 @@
  */
 
 #include <zebra.h>
+#include <net/if_types.h>
 
 #include "if.h"
 #include "prefix.h"
@@ -378,6 +379,29 @@
 }
 #endif /* HAVE_BSD_IFI_LINK_STATE */
 
+static enum zebra_link_type
+sdl_to_zebra_link_type (unsigned int sdlt)
+{
+  switch (sdlt)
+  {
+    case IFT_ETHER: return ZEBRA_LLT_ETHER;
+    case IFT_X25: return ZEBRA_LLT_X25;
+    case IFT_FDDI: return ZEBRA_LLT_FDDI;
+    case IFT_PPP: return ZEBRA_LLT_PPP;
+    case IFT_LOOP: return ZEBRA_LLT_LOOPBACK;
+    case IFT_SLIP: return ZEBRA_LLT_SLIP;
+    case IFT_ARCNET: return ZEBRA_LLT_ARCNET;
+    case IFT_ATM: return ZEBRA_LLT_ATM;
+    case IFT_LOCALTALK: return ZEBRA_LLT_LOCALTLK;
+    case IFT_HIPPI: return ZEBRA_LLT_HIPPI;
+#ifdef IFT_IEEE1394
+    case IFT_IEEE1394: return ZEBRA_LLT_IEEE1394;
+#endif
+
+    default: return ZEBRA_LLT_UNKNOWN;
+  }
+}
+
 /*
  * Handle struct if_msghdr obtained from reading routing socket or
  * sysctl (from interface_list).  There may or may not be sockaddrs
@@ -534,14 +558,23 @@
        *    is fine here.
        * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid
        */
+      ifp->ll_type = ZEBRA_LLT_UNKNOWN;
+      ifp->hw_addr_len = 0;
       if (ifnlen)
-      {
+        {
 #ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN
-	memcpy (&ifp->sdl, sdl, sdl->sdl_len);
+          memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sdl->sdl_len);
 #else
-	memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
+          memcpy (&((struct zebra_if *)ifp->info)->sdl, sdl, sizeof (struct sockaddr_dl));
 #endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */
-      }
+
+          ifp->ll_type = sdl_to_zebra_link_type (sdl->sdl_type);
+          if (sdl->sdl_alen <= sizeof(ifp->hw_addr))
+            {
+              memcpy (ifp->hw_addr, LLADDR(sdl), sdl->sdl_alen);
+              ifp->hw_addr_len = sdl->sdl_alen;
+            }
+        }
 
       if_add_update (ifp);
     }
@@ -1099,7 +1132,7 @@
             __func__, dest_buf, mask_buf, index);
           return -1;
         }
-      gate = (union sockunion *) & ifp->sdl;
+      gate = (union sockunion *) &((struct zebra_if *)ifp->info)->sdl;
     }
 
   if (mask)
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 930271d..b164c7a 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -20,6 +20,7 @@
  */
 
 #include <zebra.h>
+#include <net/if_arp.h>
 
 /* Hack for GNU libc version 2. */
 #ifndef MSG_TRUNC
@@ -462,6 +463,68 @@
     }
 }
 
+static enum zebra_link_type
+netlink_to_zebra_link_type (unsigned int hwt)
+{
+  switch (hwt)
+  {
+    case ARPHRD_ETHER: return ZEBRA_LLT_ETHER;
+    case ARPHRD_EETHER: return ZEBRA_LLT_EETHER;
+    case ARPHRD_AX25: return ZEBRA_LLT_AX25;
+    case ARPHRD_PRONET: return ZEBRA_LLT_PRONET;
+    case ARPHRD_IEEE802: return ZEBRA_LLT_IEEE802;
+    case ARPHRD_ARCNET: return ZEBRA_LLT_ARCNET;
+    case ARPHRD_APPLETLK: return ZEBRA_LLT_APPLETLK;
+    case ARPHRD_DLCI: return ZEBRA_LLT_DLCI;
+    case ARPHRD_ATM: return ZEBRA_LLT_ATM;
+    case ARPHRD_METRICOM: return ZEBRA_LLT_METRICOM;
+    case ARPHRD_IEEE1394: return ZEBRA_LLT_IEEE1394;
+    case ARPHRD_EUI64: return ZEBRA_LLT_EUI64;
+    case ARPHRD_INFINIBAND: return ZEBRA_LLT_INFINIBAND;
+    case ARPHRD_SLIP: return ZEBRA_LLT_SLIP;
+    case ARPHRD_CSLIP: return ZEBRA_LLT_CSLIP;
+    case ARPHRD_SLIP6: return ZEBRA_LLT_SLIP6;
+    case ARPHRD_CSLIP6: return ZEBRA_LLT_CSLIP6;
+    case ARPHRD_RSRVD: return ZEBRA_LLT_RSRVD;
+    case ARPHRD_ADAPT: return ZEBRA_LLT_ADAPT;
+    case ARPHRD_ROSE: return ZEBRA_LLT_ROSE;
+    case ARPHRD_X25: return ZEBRA_LLT_X25;
+    case ARPHRD_PPP: return ZEBRA_LLT_PPP;
+    case ARPHRD_CISCO: return ZEBRA_LLT_CHDLC;
+    case ARPHRD_LAPB: return ZEBRA_LLT_LAPB;
+    case ARPHRD_RAWHDLC: return ZEBRA_LLT_RAWHDLC;
+    case ARPHRD_TUNNEL: return ZEBRA_LLT_IPIP;
+    case ARPHRD_TUNNEL6: return ZEBRA_LLT_IPIP6;
+    case ARPHRD_FRAD: return ZEBRA_LLT_FRAD;
+    case ARPHRD_SKIP: return ZEBRA_LLT_SKIP;
+    case ARPHRD_LOOPBACK: return ZEBRA_LLT_LOOPBACK;
+    case ARPHRD_LOCALTLK: return ZEBRA_LLT_LOCALTLK;
+    case ARPHRD_FDDI: return ZEBRA_LLT_FDDI;
+    case ARPHRD_SIT: return ZEBRA_LLT_SIT;
+    case ARPHRD_IPDDP: return ZEBRA_LLT_IPDDP;
+    case ARPHRD_IPGRE: return ZEBRA_LLT_IPGRE;
+    case ARPHRD_PIMREG: return ZEBRA_LLT_PIMREG;
+    case ARPHRD_HIPPI: return ZEBRA_LLT_HIPPI;
+    case ARPHRD_ECONET: return ZEBRA_LLT_ECONET;
+    case ARPHRD_IRDA: return ZEBRA_LLT_IRDA;
+    case ARPHRD_FCPP: return ZEBRA_LLT_FCPP;
+    case ARPHRD_FCAL: return ZEBRA_LLT_FCAL;
+    case ARPHRD_FCPL: return ZEBRA_LLT_FCPL;
+    case ARPHRD_FCFABRIC: return ZEBRA_LLT_FCFABRIC;
+    case ARPHRD_IEEE802_TR: return ZEBRA_LLT_IEEE802_TR;
+    case ARPHRD_IEEE80211: return ZEBRA_LLT_IEEE80211;
+    case ARPHRD_IEEE802154: return ZEBRA_LLT_IEEE802154;
+#ifdef ARPHRD_IP6GRE
+    case ARPHRD_IP6GRE: return ZEBRA_LLT_IP6GRE;
+#endif
+#ifdef ARPHRD_IEEE802154_PHY
+    case ARPHRD_IEEE802154_PHY: return ZEBRA_LLT_IEEE802154_PHY;
+#endif
+
+    default: return ZEBRA_LLT_UNKNOWN;
+  }
+}
+
 /* Called from interface_lookup_netlink().  This function is only used
    during bootstrap. */
 static int
@@ -509,7 +572,7 @@
   ifp->metric = 0;
 
   /* Hardware type and address. */
-  ifp->hw_type = ifi->ifi_type;
+  ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type);
   netlink_interface_update_hw_addr (tb, ifp);
 
   if_add_update (ifp);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 6b49cf6..7bb9305 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -294,24 +294,6 @@
     }
 
   /* Hardware address. */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  sdl = &ifp->sdl;
-  if (sdl != NULL && sdl->sdl_alen != 0)
-    {
-      buf[len++] = ND_OPT_SOURCE_LINKADDR;
-
-      /* Option length should be rounded up to next octet if
-         the link address does not end on an octet boundary. */
-      buf[len++] = (sdl->sdl_alen + 9) >> 3;
-
-      memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
-      len += sdl->sdl_alen;
-
-      /* Pad option to end on an octet boundary. */
-      memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7);
-      len += -(sdl->sdl_alen + 2) & 0x7;
-    }
-#else
   if (ifp->hw_addr_len != 0)
     {
       buf[len++] = ND_OPT_SOURCE_LINKADDR;
@@ -327,7 +309,6 @@
       memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
       len += -(ifp->hw_addr_len + 2) & 0x7;
     }
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
 
   /* MTU */
   if (zif->rtadv.AdvLinkMTU)
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 600b0e5..2fd10d9 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -154,13 +154,10 @@
   stream_putl (s, ifp->mtu);
   stream_putl (s, ifp->mtu6);
   stream_putl (s, ifp->bandwidth);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-  stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage));
-#else
+  stream_putl (s, ifp->ll_type);
   stream_putl (s, ifp->hw_addr_len);
   if (ifp->hw_addr_len)
     stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
 
   /* Write packet size. */
   stream_putw_at (s, 0, stream_get_endp (s));