]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '48e5f32db676645640f84ab3d630cce975aa6b20' into integrated
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 2 May 2014 15:05:23 +0000 (17:05 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 2 May 2014 15:05:23 +0000 (17:05 +0200)
21 files changed:
1  2 
lib/socket.h
proto/ospf/config.Y
proto/ospf/dbdes.c
proto/ospf/iface.c
proto/ospf/iface.h
proto/ospf/lsack.c
proto/ospf/lsreq.c
proto/ospf/lsupd.c
proto/ospf/neighbor.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/packet.c
proto/ospf/packet.h
proto/ospf/rt.c
proto/ospf/topology.c
proto/radv/packets.c
proto/rip/rip.c
proto/static/static.c
sysdep/bsd/sysio.h
sysdep/linux/sysio.h
sysdep/unix/io.c

diff --cc lib/socket.h
index a1d8611bd66ad8826e012bd5e121bdb317674bf1,894d5561316203f1fedf832bd2f5b5ad5f3c7576..290fc56b54df898b5f5a387d548b99383f5baefd
@@@ -72,31 -73,32 +75,33 @@@ int sk_setup_multicast(sock *s)
  int sk_join_group(sock *s, ip_addr maddr);
  int sk_leave_group(sock *s, ip_addr maddr);
  
 -#ifdef IPV6
  int sk_set_ipv6_checksum(sock *s, int offset);
 -int sk_set_icmp_filter(sock *s, int p1, int p2);
 -#endif
 -
 +int sk_set_icmp6_filter(sock *s, int p1, int p2);
  int sk_set_broadcast(sock *s, int enable);
  
 -static inline int
 -sk_send_buffer_empty(sock *sk)
 -{
 -      return sk->tbuf == sk->tpos;
 -}
 +static inline int sk_send_buffer_empty(sock *sk)
 +{ return sk->tbuf == sk->tpos; }
 +
 +static inline int sk_is_ipv4(sock *sk)
 +{ return sk->af == AF_INET; }
 +
 +static inline int sk_is_ipv6(sock *sk)
 +{ return sk->af == AF_INET6; }
  
  extern int sk_priority_control;       /* Suggested priority for control traffic, should be sysdep define */
  
  /* Socket flags */
  
 -#define SKF_V6ONLY    1       /* Use IPV6_V6ONLY socket option */
 -#define SKF_LADDR_RX  2       /* Report local address for RX packets */
 -#define SKF_TTL_RX    4       /* Report TTL / Hop Limit for RX packets */
 -#define SKF_BIND      8       /* Bind datagram socket to given source address */
 +#define SKF_V4ONLY    0x01    /* Use IPv4 for IP sockets */
 +#define SKF_V6ONLY    0x02    /* Use IPV6_V6ONLY socket option */
 +#define SKF_LADDR_RX  0x04    /* Report local address for RX packets */
- #define SKF_LADDR_TX  0x08    /* Allow to specify local address for TX packets */
- #define SKF_TTL_RX    0x10    /* Report TTL / Hop Limit for RX packets */
++#define SKF_TTL_RX    0x08    /* Report TTL / Hop Limit for RX packets */
++#define SKF_BIND      0x10    /* Bind datagram socket to given source address */
  
  #define SKF_THREAD    0x100   /* Socked used in thread, Do not add to main loop */
+ #define SKF_TRUNCATED 0x200   /* Received packet was truncated, set by IO layer */
+ #define SKF_HDRINCL   0x400   /* Used internally */
+ #define SKF_PKTINFO   0x800   /* Used internally */
  
  /*
   *    Socket types                 SA SP DA DP IF  TTL SendTo (?=may, -=must not, *=must)
index e7a5c006a4570b6dcac998a61662a888168f0b0a,f894f134fa5cccfc640b2001ab9e4f948d72b990..40b14c4fa9674845148dfc25789f58afff34be02
@@@ -289,18 -300,20 +290,20 @@@ ospf_iface_item
   | CHECK LINK bool { OSPF_PATT->check_link = $3; }
   | ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
   | NEIGHBORS '{' nbma_list '}'
 - | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
 - | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
 - | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
 + | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
 + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
 + | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
-  | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; } 
-  | RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } 
-  | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } 
+  | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; } 
+  | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; } 
+  | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
   | TX tos { OSPF_PATT->tx_tos = $2; }
   | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
+  | TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("TX length must be in range 256-65535"); }
   | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
   | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
   | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
 - | password_list
+  | SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
 + | password_list { ospf_check_auth(); }
   ;
  
  pref_list:
index d0d8e306c5fbb678f78a1bb8df9a1ab6c3cf0baf,6b291344945405289bc8325ec3cf38a0460b60f0..53a93332457b409d38a79669a5b7f1a104169207
@@@ -92,76 -63,6 +92,84 @@@ static void ospf_dbdes_dump(struct prot
  }
  
  
- ospf_dbdes_prepare(struct ospf_neighbor *n, struct ospf_packet *pkt, int lsdb)
 +static void
-   int i = 0;
++ospf_dbdes_prepare(struct ospf_neighbor *n, int lsdb)
 +{
 +  struct ospf_iface *ifa = n->ifa;
 +  struct proto_ospf *po = ifa->oa->po;
-     unsigned lsa_max;
++  struct ospf_packet *pkt;
++
++  if (n->ldd_bsize != ifa->tx_length)
++  {
++    mb_free(n->ldd_buffer);
++    n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
++    n->ldd_bsize = ifa->tx_length;
++  }
 +
++  pkt = n->ldd_buffer;
 +  ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
 +
 +  if (lsdb && (n->myimms & DBDES_M))
 +  {
 +    struct ospf_lsa_header *lsas;
++    unsigned i = 0, lsa_max;
 +    snode *sn;
 +
 +    ospf_dbdes_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max);
 +    sn = s_get(&(n->dbsi));
 +
 +    while (i < lsa_max)
 +    {
 +      struct top_hash_entry *en = (struct top_hash_entry *) sn;
 +
 +      if (lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
 +      {
 +      lsa_hton_hdr(&(en->lsa), lsas + i);
 +      i++;
 +      }
 +
 +      if (sn == STAIL(po->lsal))
 +      {
 +      n->myimms &= ~DBDES_M;  /* Unset more bit */
 +      break;
 +      }
 +
 +      sn = sn->next;
 +    }
 +
 +    s_put(&(n->dbsi), sn);
 +  }
 +
 +  u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
 +  unsigned length;
 +
 +  if (ospf_is_v2(po))
 +  {
 +    struct ospf_dbdes2_packet *ps = (void *) pkt;
 +
 +    ps->iface_mtu = htons(iface_mtu);
 +    ps->options = ifa->oa->options;
 +    ps->imms = n->myimms;
 +    ps->ddseq = htonl(n->dds);
 +
 +    length = sizeof(struct ospf_dbdes2_packet);
 +  }
 +  else /* OSPFv3 */
 +  {
 +    struct ospf_dbdes3_packet *ps = (void *) pkt;
 +
 +    ps->options = htonl(ifa->oa->options);
 +    ps->iface_mtu = htons(iface_mtu);
 +    ps->imms = n->myimms;
 +    ps->ddseq = htonl(n->dds);
 +
 +    length = sizeof(struct ospf_dbdes3_packet);
 +  }
 +
 +  length += i * sizeof(struct ospf_lsa_header);
 +  pkt->length = htons(length);
 +}
 +
  /**
   * ospf_dbdes_send - transmit database description packet
   * @n: neighbor
@@@ -179,8 -80,10 +187,7 @@@ ospf_dbdes_send(struct ospf_neighbor *n
    struct ospf_iface *ifa = n->ifa;
    struct ospf_area *oa = ifa->oa;
    struct proto_ospf *po = oa->po;
-   struct ospf_packet *pkt;
 -  struct proto *p = &po->proto;
 -  u16 length, i, j;
 +  unsigned length;
  
    /* FIXME ??? */
    if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
  
    switch (n->state)
    {
 -  case NEIGHBOR_EXSTART:      /* Send empty packets */
 -    n->myimms.bit.i = 1;
 -    pkt = ospf_tx_buffer(ifa);
 -    op = &pkt->ospf_packet;
 -    ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
 -    pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
 -    pkt->options = hton_opt(oa->options);
 -    pkt->imms = n->myimms;
 -    pkt->ddseq = htonl(n->dds);
 -    length = sizeof(struct ospf_dbdes_packet);
 -    op->length = htons(length);
 -
 -    OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
 +  case NEIGHBOR_EXSTART:
 +    n->myimms |= DBDES_I;
 +
 +    /* Send empty packets */
-     pkt = ospf_tx_buffer(ifa);
-     ospf_dbdes_prepare(n, pkt, 0);
-     OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
++    ospf_dbdes_prepare(n, 0);
++    OSPF_PACKET(ospf_dbdes_dump, n->ldd_buffer,
++              "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
++
++    sk_set_tbuf(ifa->sk, n->ldd_buffer);
      ospf_send_to(ifa, n->ip);
++    sk_set_tbuf(ifa->sk, NULL);
      break;
  
    case NEIGHBOR_EXCHANGE:
 -    n->myimms.bit.i = 0;
 +    n->myimms &= ~DBDES_I;
  
      if (next)
-       ospf_dbdes_prepare(n, n->ldbdes, 1);
 -    {
 -      snode *sn;
 -      struct ospf_lsa_header *lsa;
 -
 -      if (n->ldd_bsize != ifa->tx_length)
 -      {
 -      mb_free(n->ldd_buffer);
 -      n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
 -      n->ldd_bsize = ifa->tx_length;
 -      }
 -
 -      pkt = n->ldd_buffer;
 -      op = (struct ospf_packet *) pkt;
 -
 -      ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
 -      pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
 -      pkt->ddseq = htonl(n->dds);
 -      pkt->options = hton_opt(oa->options);
 -
 -      j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header);    /* Number of possible lsaheaders to send */
 -      lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet));
 -
 -      if (n->myimms.bit.m)
 -      {
 -      sn = s_get(&(n->dbsi));
 -
 -      DBG("Number of LSA: %d\n", j);
 -      for (; i > 0; i--)
 -      {
 -        struct top_hash_entry *en= (struct top_hash_entry *) sn;
 -
 -          if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
 -          {
 -          htonlsah(&(en->lsa), lsa);
 -          DBG("Working on: %d\n", i);
 -          DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
 -
 -          lsa++;
 -          }
 -          else i++;   /* No lsa added */
 -
 -        if (sn == STAIL(po->lsal))
 -          {
 -            i--;
 -          break;
 -          }
 -
 -        sn = sn->next;
 -      }
 -
 -      if (sn == STAIL(po->lsal))
 -      {
 -        DBG("Number of LSA NOT sent: %d\n", i);
 -        DBG("M bit unset.\n");
 -        n->myimms.bit.m = 0;  /* Unset more bit */
 -      }
 -
 -      s_put(&(n->dbsi), sn);
 -      }
 -
 -      pkt->imms.byte = n->myimms.byte;
 -
 -      length = (j - i) * sizeof(struct ospf_lsa_header) +
 -      sizeof(struct ospf_dbdes_packet);
 -      op->length = htons(length);
 -
 -      DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
 -    }
++      ospf_dbdes_prepare(n, 1);
  
    case NEIGHBOR_LOADING:
    case NEIGHBOR_FULL:
 -    length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
  
-     length = ntohs(((struct ospf_packet *) n->ldbdes)->length);
++    length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
      if (!length)
      {
        OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
        return;
      }
  
-     /* Copy last sent packet again */
-     pkt = ospf_tx_buffer(ifa);
-     memcpy(pkt, n->ldbdes, length);
+     /* Send last packet from ldd buffer */
 -
 -    OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
++ 
++    OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
++              "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
  
-     OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name);
+     sk_set_tbuf(ifa->sk, n->ldd_buffer);
      ospf_send_to(ifa, n->ip);
+     sk_set_tbuf(ifa->sk, NULL);
  
 -    if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint);            /* Restart timer */
 +    /* XXXX remove this? */
 +    if (n->myimms & DBDES_MS)
 +      tm_start(n->rxmt_timer, n->ifa->rxmtint);               /* Restart timer */
  
 -    if (!n->myimms.bit.ms)
 -    {
 -      if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) &&
 +    if (!(n->myimms & DBDES_MS))
 +      if (!(n->myimms & DBDES_M) && 
 +        !(n->imms & DBDES_M) &&
          (n->state == NEIGHBOR_EXCHANGE))
 -      {
        ospf_neigh_sm(n, INM_EXDONE);
 -      }
 -    }
 +
      break;
  
    default:                    /* Ignore it */
@@@ -290,7 -265,12 +302,7 @@@ ospf_dbdes_receive(struct ospf_packet *
      return;
    }
  
-   OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->iface->name);
 -  struct ospf_dbdes_packet *ps = (void *) ps_i;
 -  u32 ps_ddseq = ntohl(ps->ddseq);
 -  u32 ps_options = ntoh_opt(ps->options);
 -  u16 ps_iface_mtu = ntohs(ps->iface_mtu);
 -  
 -  OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
++  OSPF_PACKET(ospf_dbdes_dump, pkt, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
  
    ospf_neigh_sm(n, INM_HELLOREC);
  
      ospf_neigh_sm(n, INM_2WAYREC);
      if (n->state != NEIGHBOR_EXSTART)
        return;
 -  case NEIGHBOR_EXSTART:
 -
 -    if ((ifa->type != OSPF_IT_VLINK) && (ps_iface_mtu != ifa->iface->mtu)
 -      && (ps_iface_mtu != 0) && (ifa->iface->mtu != 0))
 -      log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
 -        n->ip, ifa->ifname, ps_iface_mtu, ifa->iface->mtu);
  
 -    if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
 -      && (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
 +  case NEIGHBOR_EXSTART:
-     if ((rcv_iface_mtu != ifa->iface->mtu) &&
++    if ((ifa->type != OSPF_IT_VLINK) &&
++      (rcv_iface_mtu != ifa->iface->mtu) &&
 +      (rcv_iface_mtu != 0) &&
-       (ifa->iface->mtu != 0) && 
-       (ifa->type != OSPF_IT_VLINK))
++      (ifa->iface->mtu != 0))
 +      log(L_WARN "OSPF: MTU mismatch with neighbor %I on interface %s (remote %d, local %d)",
-         n->ip, ifa->iface->name, rcv_iface_mtu, ifa->iface->mtu);
++        n->ip, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
 +
 +    if ((rcv_imms == DBDES_IMMS) &&
 +      (n->rid > po->router_id) &&
 +      (plen == ospf_dbdes_hdrlen(po)))
      {
        /* I'm slave! */
 -      n->dds = ps_ddseq;
 -      n->ddr = ps_ddseq;
 -      n->options = ps_options;
 -      n->myimms.bit.ms = 0;
 -      n->imms.byte = ps->imms.byte;
 -      OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
 +      n->dds = rcv_ddseq;
 +      n->ddr = rcv_ddseq;
 +      n->options = rcv_options;
 +      n->myimms &= ~DBDES_MS;
 +      n->imms = rcv_imms;
 +      OSPF_TRACE(D_PACKETS, "I'm slave to %I", n->ip);
        ospf_neigh_sm(n, INM_NEGDONE);
        ospf_dbdes_send(n, 1);
        break;
index 6a52c6ae1c2e6f97ae70f56744ca0239e395a58c,f4d9be55082393ec3500a10444a0cb851df3c588..3aaf5cd0cb15546b46de58a11ae46947f0c94814
@@@ -34,9 -34,9 +34,9 @@@ static voi
  wait_timer_hook(timer * timer)
  {
    struct ospf_iface *ifa = (struct ospf_iface *) timer->data;
 -  struct proto *p = &ifa->oa->po->proto;
 +  struct proto_ospf *po = ifa->oa->po;
  
-   OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->iface->name);
 -  OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.", ifa->ifname);
++  OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s", ifa->ifname);
    ospf_iface_sm(ifa, ISM_WAITF);
  }
  
@@@ -82,45 -99,22 +101,21 @@@ ospf_sk_open(struct ospf_iface *ifa
    sk->tos = ifa->cf->tx_tos;
    sk->priority = ifa->cf->tx_priority;
    sk->rx_hook = ospf_rx_hook;
-   sk->tx_hook = ospf_tx_hook;
+   // sk->tx_hook = ospf_tx_hook;
    sk->err_hook = ospf_err_hook;
-   sk->iface = ifa->iface;
-   sk->rbsize = rxbufsize(ifa);
-   sk->tbsize = rxbufsize(ifa);
+   sk->rbsize = sk->tbsize = ifa_bufsize(ifa);
    sk->data = (void *) ifa;
    sk->flags = SKF_LADDR_RX | (ifa->check_ttl ? SKF_TTL_RX : 0);
-   sk->ttl = ifa->cf->ttl_security ? 255 : -1;
+   sk->ttl = ifa->cf->ttl_security ? 255 : 1;
  
-   if (sk_open(sk) != 0)
+   if (sk_open(sk) < 0)
      goto err;
  
 -#ifdef OSPFv3
 -  /* 12 is an offset of the checksum in an OSPF packet */
 -  if (sk_set_ipv6_checksum(sk, 12) < 0)
 -    goto err;
 -#endif
 +  /* 12 is an offset of the checksum in an OSPFv3 packet */
 +  if (ospf_is_v3(po))
 +    if (sk_set_ipv6_checksum(sk, 12) < 0)
 +      goto err;
  
-   /*
-    * For OSPFv2: When sending a packet, it is important to have a
-    * proper source address. We expect that when we send one-hop
-    * unicast packets, OS chooses a source address according to the
-    * destination address (to be in the same prefix). We also expect
-    * that when we send multicast packets, OS uses the source address
-    * from sk->saddr registered to OS by sk_setup_multicast(). This
-    * behavior is needed to implement multiple virtual ifaces (struct
-    * ospf_iface) on one physical iface and is signalized by
-    * CONFIG_MC_PROPER_SRC.
-    *
-    * If this behavior is not available (for example on BSD), we create
-    * non-stub iface just for the primary IP address (see
-    * ospf_iface_stubby()) and we expect OS to use primary IP address
-    * as a source address for both unicast and multicast packets.
-    *
-    * FIXME: the primary IP address is currently just the
-    * lexicographically smallest address on an interface, it should be
-    * signalized by sysdep code which one is really the primary.
-    */
-   sk->saddr = ifa->addr->ip;
    if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
    {
      if (ifa->cf->real_bcast)
      }
      else
      {
 -      ifa->all_routers = AllSPFRouters;
 +      ifa->all_routers = ospf_is_v2(po) ? IP4_OSPF_ALL_ROUTERS : IP6_OSPF_ALL_ROUTERS;
 +      ifa->des_routers = ospf_is_v2(po) ? IP4_OSPF_DES_ROUTERS : IP6_OSPF_DES_ROUTERS;
-       sk->ttl = ifa->cf->ttl_security ? 255 : 1;
  
        if (sk_setup_multicast(sk) < 0)
          goto err;
@@@ -174,6 -165,42 +168,40 @@@ ospf_sk_leave_dr(struct ospf_iface *ifa
    ifa->sk_dr = 0;
  }
  
 -  struct proto *p = &po->proto;
 -
+ void
+ ospf_open_vlink_sk(struct proto_ospf *po)
+ {
 -  log(L_ERR "%s: Cannot open virtual link socket", p->name);
+   sock *sk = sk_new(po->proto.pool);
+   sk->type = SK_IP;
+   sk->dport = OSPF_PROTO;
+   /* FIXME: configurable tos/priority ? */
+   sk->tos = IP_PREC_INTERNET_CONTROL;
+   sk->priority = sk_priority_control;
+   sk->err_hook = ospf_verr_hook;
+   sk->rbsize = 0;
+   sk->tbsize = OSPF_VLINK_MTU;
+   sk->data = (void *) po;
+   sk->flags = 0;
+   if (sk_open(sk) < 0)
+     goto err;
+ #ifdef OSPFv3
+   /* 12 is an offset of the checksum in an OSPF packet */
+   if (sk_set_ipv6_checksum(sk, 12) < 0)
+     goto err;
+ #endif
+   po->vlink_sk = sk;
+   return;
+  err:
+   rfree(sk);
++  log(L_ERR "%s: Cannot open virtual link socket", po->proto.name);
+ }
  static void
  ospf_iface_down(struct ospf_iface *ifa)
  {
  
    if (ifa->type != OSPF_IT_VLINK)
    {
 -#ifdef OSPFv2
 -    OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
 -             ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
 -#else
 -    OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
 -             ifa->ifname, ifa->instance_id, ifa->oa->areaid);
 -#endif
 +    if (ospf_is_v3(ifa->oa->po))
 +      OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
-                ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
++               ifa->ifname, ifa->instance_id, ifa->oa->areaid);
 +    else if (ifa->addr->flags & IA_PEER)
 +      OSPF_TRACE(D_EVENTS, "Removing interface %s (peer %I) from area %R",
-                ifa->iface->name, ifa->addr->opposite, ifa->oa->areaid);
++               ifa->ifname, ifa->addr->opposite, ifa->oa->areaid);
 +    else
 +      OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
-                ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
++               ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
  
      /* First of all kill all the related vlinks */
      WALK_LIST(iff, po->iface_list)
@@@ -273,14 -299,14 +299,10 @@@ ospf_iface_chstate(struct ospf_iface *i
  
    ifa->state = state;
  
--  if (ifa->type == OSPF_IT_VLINK)
--    OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
--             ifa->vid, ospf_is[oldstate], ospf_is[state]);
--  else
--    OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
-              ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
 -             ifa->ifname, ospf_is[oldstate], ospf_is[state]);
++  OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
++           ifa->ifname, ospf_is[oldstate], ospf_is[state]);
  
 -  if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
 +  if ((ifa->type == OSPF_IT_BCAST) && ipa_nonzero(ifa->des_routers) && ifa->sk)
    {
      if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
        ospf_sk_join_dr(ifa);
  void
  ospf_iface_sm(struct ospf_iface *ifa, int event)
  {
-   DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface",
-     ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]);
 -  DBG("SM on iface %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
++  DBG("SM on %s. Event is '%s'\n", ifa->ifname, ospf_ism[event]);
  
    switch (event)
    {
@@@ -498,27 -519,20 +515,22 @@@ ospf_iface_stubby(struct ospf_iface_pat
  void
  ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
  {
 -  struct proto *p = &oa->po->proto;
 +  struct proto_ospf *po = oa->po;
-   struct iface *iface = addr ? addr->iface : NULL;
-   struct pool *pool;
+   struct iface *iface = addr->iface;
    struct ospf_iface *ifa;
-   struct nbma_node *nb;
-   struct object_lock *lock;
+   struct pool *pool;
  
-   if (ip->type == OSPF_IT_VLINK)
-     OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
-   else if (ospf_is_v3(po))
 -#ifdef OSPFv2
 -  OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
 -           iface->name, addr->prefix, addr->pxlen, oa->areaid);
 -#else
 -  OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
 -           iface->name, ip->instance_id, oa->areaid);
 -#endif
++  if (ospf_is_v3(po))
 +    OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
 +             iface->name, ip->instance_id, oa->areaid);
 +  else if (addr->flags & IA_PEER)
 +    OSPF_TRACE(D_EVENTS, "Adding interface %s (peer %I) to area %R",
 +             iface->name, addr->opposite, oa->areaid);
 +  else
 +    OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
 +             iface->name, addr->prefix, addr->pxlen, oa->areaid);
  
 -  pool = rp_new(p->pool, "OSPF Interface");
 +  pool = rp_new(po->proto.pool, "OSPF Interface");
    ifa = mb_allocz(pool, sizeof(struct ospf_iface));
    ifa->iface = iface;
    ifa->addr = addr;
    ifa->deadint = ip->deadint;
    ifa->stub = ospf_iface_stubby(ip, addr);
    ifa->ioprob = OSPF_I_OK;
-   ifa->rxbuf = ip->rxbuf;
 -
+   ifa->tx_length = ifa_tx_length(ifa);
    ifa->check_link = ip->check_link;
    ifa->ecmp_weight = ip->ecmp_weight;
    ifa->check_ttl = (ip->ttl_security == 1);
    ifa->bfd = ip->bfd;
 -
 -#ifdef OSPFv2
    ifa->autype = ip->autype;
    ifa->passwords = ip->passwords;
-   ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0;
 +  ifa->instance_id = ip->instance_id;
 +
+   ifa->ptp_netmask = !(addr->flags & IA_PEER);
    if (ip->ptp_netmask < 2)
      ifa->ptp_netmask = ip->ptp_netmask;
 -#endif
 -
 -#ifdef OSPFv3
 -  ifa->instance_id = ip->instance_id;
 -#endif
  
    ifa->type = ospf_iface_classify(ip->type, addr);
  
    /* Check validity of interface type */
  
    if (ifa->type != old_type)
      log(L_WARN "%s: Cannot use interface %s as %s, forcing %s",
 -      p->name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
 +      po->proto.name, iface->name, ospf_it[old_type], ospf_it[ifa->type]);
  
-   /* Assign iface ID, for vlinks, this is ugly hack */
-   ifa->iface_id = (ifa->type != OSPF_IT_VLINK) ? iface->index : oa->po->last_vlink_id++;
  
+   ifa->state = OSPF_IS_DOWN;
    init_list(&ifa->neigh_list);
    init_list(&ifa->nbma_list);
  
     * Therefore, we store such info to lock->addr field.
     */
  
-   lock = olock_new(pool);
+   struct object_lock *lock = olock_new(pool);
 -#ifdef OSPFv2
 -  lock->addr = ifa->addr->prefix;
 -#else /* OSPFv3 */
 -  lock->addr = _MI(0,0,0,ifa->instance_id);
 -#endif
 +  lock->addr = ospf_is_v2(po) ? ifa->addr->prefix : _MI6(0,0,0,ifa->instance_id);
    lock->type = OBJLOCK_IP;
    lock->port = OSPF_PROTO;
    lock->iface = iface;
@@@ -640,13 -718,13 +702,13 @@@ ospf_iface_change_timer(timer *tm, unsi
  int
  ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
  {
 -  struct proto *p = &ifa->oa->po->proto;
 +  struct proto_ospf *po = ifa->oa->po;
-   struct nbma_node *nb, *nbx;
-   char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";
+   struct ospf_iface_patt *old = ifa->cf;
+   char *ifname = ifa->ifname;
  
    /* Type could be changed in ospf_iface_new(),
       but if config values are same then also results are same */
-   int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr);
 -  int old_type = ospf_iface_classify(old->type, ifa->addr);
++  int old_type = ospf_iface_classify(old->type, ifa->addr);  
    int new_type = ospf_iface_classify(new->type, ifa->addr);
    if (old_type != new_type)
      return 0;
@@@ -1009,50 -1142,21 +1096,54 @@@ ospf_ifa_notify3(struct proto *p, unsig
    }
  }
  
 -static struct ospf_iface *
 -ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
 +
 +static void
 +ospf_ifaces_reconfigure2(struct ospf_area *oa, struct ospf_area_config *nac)
  {
 -  struct ospf_iface *ifa;
 -  WALK_LIST(ifa, oa->po->iface_list)
 -    if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
 -      return ifa;
++  struct proto_ospf *po = oa->po;
 +  struct ospf_iface_patt *ip;
 +  struct iface *iface;
 +  struct ifa *a;
  
 -  return NULL;
 +  WALK_LIST(iface, iface_list)
 +  {
 +    if (! (iface->flags & IF_UP))
 +      continue;
 +
 +    WALK_LIST(a, iface->addrs)
 +    {
 +      if (a->flags & IA_SECONDARY)
 +      continue;
 +
 +      if (a->scope <= SCOPE_LINK)
 +      continue;
 +
 +      if (ip = ospf_iface_patt_find2(oa->ac, a))
 +      {
 +      /* Main inner loop */
 +      struct ospf_iface *ifa = ospf_iface_find_by_key2(oa, a);
 +      if (ifa)
 +      {
 +        if (ospf_iface_reconfigure(ifa, ip))
 +          continue;
 +
 +        /* Hard restart */
++        log(L_INFO "%s: Restarting interface %s (%I/%d) in area %R",
++            po->proto.name, ifa->ifname, a->prefix, a->pxlen, oa->areaid);
 +        ospf_iface_shutdown(ifa);
 +        ospf_iface_remove(ifa);
 +      }
 +      
 +      ospf_iface_new(oa, a, ip);
 +      }
 +    }
 +  }
  }
  
 -void
 -ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
 +static void
 +ospf_ifaces_reconfigure3(struct ospf_area *oa, struct ospf_area_config *nac)
  {
 -  struct proto *p = &oa->po->proto;
++  struct proto_ospf *po = oa->po;
    struct ospf_iface_patt *ip;
    struct iface *iface;
    struct ifa *a;
            continue;
  
          /* Hard restart */
 -            p->name, ifa->ifname, ifa->instance_id, oa->areaid);
+         log(L_INFO "%s: Restarting interface %s (IID %d) in area %R",
++            po->proto.name, ifa->ifname, ifa->instance_id, oa->areaid);
          ospf_iface_shutdown(ifa);
          ospf_iface_remove(ifa);
        }
@@@ -1106,27 -1204,23 +1199,21 @@@ ospf_ifaces_reconfigure(struct ospf_are
  static void
  ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
  {
-   struct ospf_packet *op;
-   struct ospf_neighbor *n;
-   OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
 -  struct proto *p = &po->proto;
 -
+   /* ifa is not vlink */
  
-   if (ifa->sk)
-   {
-     ifa->sk->rbsize = rxbufsize(ifa);
-     ifa->sk->tbsize = rxbufsize(ifa);
-     sk_reallocate(ifa->sk);
-   }
+   OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->ifname);
  
-   WALK_LIST(n, ifa->neigh_list)
-   {
-     op = (struct ospf_packet *) n->ldbdes;
-     n->ldbdes = mb_allocz(n->pool, ifa->iface->mtu);
+   ifa->tx_length = ifa_tx_length(ifa);
  
-     if (ntohs(op->length) <= ifa->iface->mtu) /* If the packet in old buffer is bigger, let it filled by zeros */
-       memcpy(n->ldbdes, op, ifa->iface->mtu); /* If the packet is old is same or smaller, copy it */
+   if (!ifa->sk)
+     return;
  
-     mb_free(op);
-   }
+   /* We do not shrink dynamic buffers */
+   uint bsize = ifa_bufsize(ifa);
+   if (bsize > ifa->sk->rbsize)
+     sk_set_rbsize(ifa->sk, bsize);
+   if (bsize > ifa->sk->tbsize)
+     sk_set_tbsize(ifa->sk, bsize);
  }
  
  static void
@@@ -1193,13 -1286,14 +1279,13 @@@ ospf_iface_info(struct ospf_iface *ifa
    }
    else
    {
 -#ifdef OSPFv2
 -    if (ifa->addr->flags & IA_PEER)
 +    if (ospf_is_v3(ifa->oa->po))
-       cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
++      cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
 +    else if (ifa->addr->flags & IA_PEER)
-       cli_msg(-1015, "Interface %s (peer %I)", ifa->iface->name, ifa->addr->opposite);
+       cli_msg(-1015, "Interface %s (peer %I)", ifa->ifname, ifa->addr->opposite);
      else
-       cli_msg(-1015, "Interface %s (%I/%d)", ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen);
+       cli_msg(-1015, "Interface %s (%I/%d)", ifa->ifname, ifa->addr->prefix, ifa->addr->pxlen);
 -#else /* OSPFv3 */
 -    cli_msg(-1015, "Interface %s (IID %d)", ifa->ifname, ifa->instance_id);
 -#endif
 +
      cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
      cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
    }
index 751105ff2bc9c067a543a81450275a1ad538db00,5a250e0a0a9346d9fdc25fbe8746439d961ba687..eceb9fce4e73e581a8b6913d77d2120b5b4b9b4c
@@@ -14,10 -14,10 +14,11 @@@ void ospf_iface_chstate(struct ospf_ifa
  void ospf_iface_sm(struct ospf_iface *ifa, int event);
  struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
  void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
 -void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
 +void ospf_ifa_notify2(struct proto *p, unsigned flags, struct ifa *a);
 +void ospf_ifa_notify3(struct proto *p, unsigned flags, struct ifa *a);
  void ospf_iface_info(struct ospf_iface *ifa);
  void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
+ void ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip);
  void ospf_iface_remove(struct ospf_iface *ifa);
  void ospf_iface_shutdown(struct ospf_iface *ifa);
  int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
index 35ddfec6387abf79fa6c52b643257e904952ebe8,fd8ead01084133e243b62444d752ca044bcac8cd..8d8e03035ce42e3963c094331d9bab0d7f85b112
@@@ -61,37 -52,77 +61,37 @@@ ospf_lsack_enqueue(struct ospf_neighbo
        n->rid, ntohl(h->id), ntohl(h->rt), h->type);
  }
  
 -void
 -ospf_lsack_send(struct ospf_neighbor *n, int queue)
 +static inline void
 +ospf_lsack_send_one(struct ospf_neighbor *n, int queue)
  {
 -  struct ospf_packet *op;
 -  struct ospf_lsack_packet *pk;
 -  u16 len, i = 0;
 -  struct ospf_lsa_header *h;
 -  struct lsah_n *no;
    struct ospf_iface *ifa = n->ifa;
 -  struct proto *p = &n->ifa->oa->po->proto;
 -
 -  if (EMPTY_LIST(n->ackl[queue]))
 -    return;
 +  struct proto_ospf *po = ifa->oa->po;
 +  struct ospf_lsa_header *lsas;
 +  struct ospf_packet *pkt;
 +  struct lsah_n *no;
 +  unsigned i, lsa_max, length;
  
 -  pk = ospf_tx_buffer(ifa);
 -  op = &pk->ospf_packet;
  
 -  ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
 -  h = pk->lsh;
 +  pkt = ospf_tx_buffer(ifa);
 +  ospf_pkt_fill_hdr(ifa, pkt, LSACK_P);
 +  ospf_lsack_body(po, pkt, ospf_pkt_maxsize(ifa), &lsas, &lsa_max);
  
 -  while (!EMPTY_LIST(n->ackl[queue]))
 +  for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++)
    {
      no = (struct lsah_n *) HEAD(n->ackl[queue]);
 -    memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header));
 -    DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id),
 -      ntohl((h + i)->rt), (h + i)->type);
 -    i++;
 +    memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header));
 +    DBG("Iter %u ID: %R, RT: %R, Type: %04x\n",
 +      i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type);
      rem_node(NODE no);
      mb_free(no);
 -    if ((i * sizeof(struct ospf_lsa_header) +
 -       sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa))
 -    {
 -      if (!EMPTY_LIST(n->ackl[queue]))
 -      {
 -      len =
 -        sizeof(struct ospf_lsack_packet) +
 -        i * sizeof(struct ospf_lsa_header);
 -      op->length = htons(len);
 -      DBG("Sending and continuing! Len=%u\n", len);
 -
 -      OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
 -
 -      if (ifa->type == OSPF_IT_BCAST)
 -      {
 -        if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
 -          ospf_send_to_all(ifa);
 -        else if (ifa->cf->real_bcast)
 -          ospf_send_to_bdr(ifa);
 -        else
 -          ospf_send_to(ifa, AllDRouters);
 -      }
 -      else
 -      {
 -        if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
 -          ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
 -        else
 -          ospf_send_to_bdr(ifa);
 -      }
 -
 -      ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
 -      i = 0;
 -      }
 -    }
    }
  
 -  len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
 -  op->length = htons(len);
 -  DBG("Sending! Len=%u\n", len);
 +  length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsa_header);
 +  pkt->length = htons(length);
  
-   OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->iface->name);
 -  OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
++  OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet sent via %s", ifa->ifname);
  
 +  /* XXXX this is very strange */
    if (ifa->type == OSPF_IT_BCAST)
    {
      if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
  }
  
  void
 -ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 +ospf_lsack_send(struct ospf_neighbor *n, int queue)
 +{
 +  while (!EMPTY_LIST(n->ackl[queue]))
 +    ospf_lsack_send_one(n, queue);
 +}
 +
 +void
 +ospf_lsack_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n)
  {
 -  struct proto *p = &ifa->oa->po->proto;
 -  struct ospf_lsa_header lsa;
 +  struct proto_ospf *po = ifa->oa->po;
 +  struct ospf_lsa_header lsa, *lsas;
    struct top_hash_entry *en;
 -  unsigned int i, lsano;
 +  unsigned i, lsa_count;
 +  u32 lsa_dom, lsa_type;
  
 -  unsigned int size = ntohs(ps_i->length);
 -  if (size < sizeof(struct ospf_lsack_packet))
 -  {
 -    log(L_ERR "Bad OSPF LSACK packet from %I -  too short (%u B)", n->ip, size);
 -    return;
 -  }
  
 -  struct ospf_lsack_packet *ps = (void *) ps_i;
 -  OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
 +  /* No need to check length, lsack has only basic header */
  
-   OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s",
-             n->ip, ifa->iface->name);
 -  ospf_neigh_sm(n, INM_HELLOREC);
++  OSPF_PACKET(ospf_lsack_dump, pkt, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
  
    if (n->state < NEIGHBOR_EXCHANGE)
      return;
index e0270b9ff256deb479026a20d1a839a7a1d394c5,15854ce7b569b2c737bf2c39ec89686ba4cb8b0d..93cc121f891818ff3f0896fb67c078ff81897acc
@@@ -82,28 -74,40 +82,26 @@@ ospf_lsreq_send(struct ospf_neighbor *n
        break;
      sn = sn->next;
    }
 -  if (i != 0)
 -    i--;
  
 -  length =
 -    sizeof(struct ospf_lsreq_packet) + (j -
 -                                      i) * sizeof(struct ospf_lsreq_header);
 -  op->length = htons(length);
 +  length = ospf_pkt_hdrlen(po) + i * sizeof(struct ospf_lsreq_header);
 +  pkt->length = htons(length);
  
-   OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s",
-             n->ip, ifa->iface->name);
 -  OSPF_PACKET(ospf_dump_lsreq, pk, "LSREQ packet sent to %I via %s", n->ip, n->ifa->ifname);
 -  ospf_send_to(n->ifa, n->ip);
++  OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet sent to %I via %s", n->ip, ifa->ifname);
 +  ospf_send_to(ifa, n->ip);
  }
  
 +
  void
 -ospf_lsreq_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 +ospf_lsreq_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n)
  {
 -  struct ospf_area *oa = ifa->oa;
 -  struct proto_ospf *po = oa->po;
 -  struct proto *p = &po->proto;
 -  struct ospf_lsreq_header *lsh;
 -  struct l_lsr_head *llsh;
 -  list uplist;
 -  slab *upslab;
 -  int i, lsano;
 -
 -  unsigned int size = ntohs(ps_i->length);
 -  if (size < sizeof(struct ospf_lsreq_packet))
 -  {
 -    log(L_ERR "Bad OSPF LSREQ packet from %I -  too short (%u B)", n->ip, size);
 -    return;
 -  }
 +  struct proto_ospf *po = ifa->oa->po;
 +  struct ospf_lsreq_header *lsrs;
 +  unsigned i, lsr_count;
 +
 +  /* No need to check length, lsreq has only basic header */
  
-   OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s",
-             n->ip, ifa->iface->name);
 -  struct ospf_lsreq_packet *ps = (void *) ps_i;
 -  OSPF_PACKET(ospf_dump_lsreq, ps, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
++  OSPF_PACKET(ospf_lsreq_dump, pkt, "LSREQ packet received from %I via %s", n->ip, ifa->ifname);
  
    if (n->state < NEIGHBOR_EXCHANGE)
      return;
index ad7d332374ee8cb3299c24e69a3ce8e1946716c2,1859867ba1567e943eba6e249bc728d7b188662c..e8069b793055bdb962a0e8fe5a3bcad0120e09c1
@@@ -22,67 -17,36 +22,67 @@@ struct ospf_lsupd_packe
  
  
  /* Beware of unaligned access */
 -void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n)
 +void ospf_dump_lsahdr(struct proto_ospf *po, struct ospf_lsa_header *lsa_n)
  {
    struct ospf_lsa_header lsa;
 -  ntohlsah(lsa_n, &lsa);
 +  u32 lsa_type;
 +
 +  lsa_ntoh_hdr(lsa_n, &lsa);
 +  lsa_type = lsa_get_type(po, lsa.type_raw);
  
    log(L_TRACE "%s:     LSA      Type: %04x, Id: %R, Rt: %R, Age: %u, Seq: %08x, Sum: %04x",
 -      p->name, lsa.type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
 +      po->proto.name, lsa_type, lsa.id, lsa.rt, lsa.age, lsa.sn, lsa.checksum);
 +}
 +
 +void ospf_dump_common(struct proto_ospf *po, struct ospf_packet *pkt)
 +{
 +  struct proto *p = &po->proto;
 +  log(L_TRACE "%s:     length   %d", p->name, ntohs(pkt->length));
 +  log(L_TRACE "%s:     router   %R", p->name, ntohl(pkt->routerid));
 +}
 +
- static inline unsigned
++static inline uint
 +ospf_lsupd_hdrlen(struct proto_ospf *po)
 +{
 +  return ospf_pkt_hdrlen(po) + 4; /* + u32 lsa count field */
  }
  
 -void ospf_dump_common(struct proto *p, struct ospf_packet *op)
 +static inline u32
- ospf_lsupd_get_lsa_count(struct ospf_packet *pkt, unsigned hdrlen)
++ospf_lsupd_get_lsa_count(struct ospf_packet *pkt, uint hdrlen)
  {
 -  log(L_TRACE "%s:     length   %d", p->name, ntohs(op->length));
 -  log(L_TRACE "%s:     router   %R", p->name, ntohl(op->routerid));
 +  u32 *c = ((void *) pkt) + hdrlen - 4;
 +  return ntohl(*c);
  }
  
 -static void ospf_dump_lsupd(struct proto *p, struct ospf_lsupd_packet *pkt)
 +static inline void
- ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, unsigned hdrlen, u32 val)
++ospf_lsupd_set_lsa_count(struct ospf_packet *pkt, uint hdrlen, u32 val)
  {
 -  struct ospf_packet *op = &pkt->ospf_packet;
 +  u32 *c = ((void *) pkt) + hdrlen - 4;
 +  *c = htonl(val);
 +}
 +
 +static inline void
 +ospf_lsupd_body(struct proto_ospf *po, struct ospf_packet *pkt,
-               unsigned *offset, unsigned *bound, unsigned *lsa_count)
++              uint *offset, uint *bound, uint *lsa_count)
 +{
-   unsigned hlen = ospf_lsupd_hdrlen(po);
++  uint hlen = ospf_lsupd_hdrlen(po);
 +  *offset = hlen;
 +  *bound = ntohs(pkt->length) - sizeof(struct ospf_lsa_header);
 +  *lsa_count = ospf_lsupd_get_lsa_count(pkt, hlen);
 +}
 +
 +static void ospf_lsupd_dump(struct proto_ospf *po, struct ospf_packet *pkt)
 +{
 +  struct proto *p = &po->proto;
  
 -  ASSERT(op->type == LSUPD_P);
 -  ospf_dump_common(p, op);
 +  ASSERT(pkt->type == LSUPD_P);
 +  ospf_dump_common(po, pkt);
  
 -  /* We know that ntohs(op->length) >= sizeof(struct ospf_lsa_header) */
 -  u8 *pbuf= (u8 *) pkt;
 -  unsigned int offset = sizeof(struct ospf_lsupd_packet);
 -  unsigned int bound = ntohs(op->length) - sizeof(struct ospf_lsa_header);
 -  unsigned int i, j, lsalen;
 +  /* We know that ntohs(pkt->length) >= sizeof(struct ospf_lsa_header) */
-   unsigned offset, bound, i, lsa_count, lsalen;
++  uint offset, bound, i, lsa_count, lsalen;
 +  ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
  
 -  j = ntohl(pkt->lsano);
 -  for (i = 0; i < j; i++)
 +  for (i = 0; i < lsa_count; i++)
      {
        if (offset > bound)
        {
@@@ -189,22 -442,24 +189,22 @@@ ospf_lsupd_handle_self_originated_lsa(
  }
  
  void
 -ospf_lsupd_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 +ospf_lsupd_receive(struct ospf_packet *pkt, struct ospf_iface *ifa,
                   struct ospf_neighbor *n)
  {
 -
 -  struct ospf_neighbor *ntmp;
    struct proto_ospf *po = ifa->oa->po;
    struct proto *p = &po->proto;
 -  unsigned int i, max, sendreq = 1;
  
-   unsigned sendreq = 1; /* XXXX ?? */
 -  unsigned int size = ntohs(ps_i->length);
 -  if (size < (sizeof(struct ospf_lsupd_packet) + sizeof(struct ospf_lsa_header)))
++  uint sendreq = 1; /* XXXX ?? */
 +
-   unsigned plen = ntohs(pkt->length);
++  uint plen = ntohs(pkt->length);
 +  if (plen < (ospf_lsupd_hdrlen(po) + sizeof(struct ospf_lsa_header)))
    {
 -    log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, size);
 +    log(L_ERR "OSPF: Bad LSUPD packet from %I - too short (%u B)", n->ip, plen);
      return;
    }
  
-   OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->iface->name);
 -  struct ospf_lsupd_packet *ps = (void *) ps_i;
 -  OSPF_PACKET(ospf_dump_lsupd, ps, "LSUPD packet received from %I via %s", n->ip, ifa->ifname);
++  OSPF_PACKET(ospf_lsupd_dump, pkt, "LSUPD packet received from %I via %s", n->ip, ifa->ifname);
  
    if (n->state < NEIGHBOR_EXCHANGE)
    {
  
    ospf_neigh_sm(n, INM_HELLOREC);     /* Questionable */
  
-   unsigned offset, bound, i, lsa_count;
 -  unsigned int offset = sizeof(struct ospf_lsupd_packet);
 -  unsigned int bound = size - sizeof(struct ospf_lsa_header);
++  uint offset, bound, i, lsa_count;
 +  ospf_lsupd_body(po, pkt, &offset, &bound, &lsa_count);
  
 -  max = ntohl(ps->lsano);
 -  for (i = 0; i < max; i++)
 +  for (i = 0; i < lsa_count; i++)
    {
 -    struct ospf_lsa_header lsatmp;
 -    struct top_hash_entry *lsadb;
 +    struct ospf_lsa_header lsa, *lsa_n;
 +    struct top_hash_entry *en;
 +    u32 lsa_len, lsa_type, lsa_domain;
  
      if (offset > bound)
      {
    }
  }
  
-                  struct top_hash_entry **lsa_list, unsigned lsa_count)
 +
 +/**
 + * ospf_lsupd_flood - send received or generated LSA to the neighbors
 + * @po: OSPF protocol
 + * @en: LSA entry
 + * @from: neighbor than sent this LSA (or NULL if LSA is local)
 + *
 + * return value - was the LSA flooded back?
 + */
 +
 +int
 +ospf_lsupd_flood(struct proto_ospf *po, struct top_hash_entry *en, struct ospf_neighbor *from)
 +{
 +  struct ospf_iface *ifa;
 +  struct ospf_neighbor *n;
 +
 +  int back = 0;
 +  WALK_LIST(ifa, po->iface_list)
 +  {
 +    if (ifa->stub)
 +      continue;
 +
 +    if (! lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
 +      continue;
 +
 +    DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
 +      hh->type, hh->id, hh->rt, hh->sn, hh->age);
 +
 +    int used = 0;
 +    WALK_LIST(n, ifa->neigh_list)
 +    {
 +      /* 13.3 (1a) */
 +      if (n->state < NEIGHBOR_EXCHANGE)
 +      continue;
 +
 +      /* 13.3 (1b) */
 +      if (n->state < NEIGHBOR_FULL)
 +      {
 +      struct top_hash_entry *req = ospf_hash_find_entry(n->lsrqh, en);
 +      if (req != NULL)
 +      {
 +        int cmp = lsa_comp(&en->lsa, &req->lsa);
 +
 +        /* If same or newer, remove LSA from the link state request list */
 +        if (cmp > CMP_OLDER)
 +        {
 +          s_rem_node(SNODE req);
 +          ospf_hash_delete(n->lsrqh, req);
 +          if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING))
 +            ospf_neigh_sm(n, INM_LOADDONE);
 +        }
 +
 +        /* If older or same, skip processing of this LSA */
 +        if (cmp < CMP_NEWER)
 +          continue;
 +      }
 +      }
 +
 +      /* 13.3 (1c) */
 +      if (n == from)
 +      continue;
 +
 +      /* In OSPFv3, there should be check whether receiving router understand
 +       that type of LSA (for LSA types with U-bit == 0). But as we do not support
 +       any optional LSA types, this is not needed yet */
 +
 +      /* 13.3 (1d) - add LSA to the link state retransmission list */
 +      ospf_lsa_lsrt_up(en, n);
 +
 +      used = 1;
 +    }
 +
 +    /* 13.3 (2) */
 +    if (!used)
 +      continue;
 +
 +    if (from && (from->ifa == ifa))
 +    {
 +      /* 13.3 (3) */
 +      if ((from->rid == ifa->drid) || from->rid == ifa->bdrid)
 +      continue;
 +
 +      /* 13.3 (4) */
 +      if (ifa->state == OSPF_IS_BACKUP)
 +      continue;
 +
 +      back = 1;
 +    }
 +
 +    /* 13.3 (5) - finally flood the packet */
 +    ospf_lsupd_flood_ifa(po, ifa, en);
 +  }
 +
 +  return back;
 +}
 +
 +static int
 +ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa,
-   unsigned hlen, pos, i, maxsize;
++                 struct top_hash_entry **lsa_list, uint lsa_count)
 +{
 +  struct ospf_packet *pkt;
-     unsigned len = en->lsa.length;
++  uint hlen, pos, i, maxsize;
 +
 +  pkt = ospf_tx_buffer(ifa);
 +  hlen = ospf_lsupd_hdrlen(po);
 +  maxsize = ospf_pkt_maxsize(ifa);
 +
 +  ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P);
 +  pos = hlen;
 +
 +  for (i = 0; i < lsa_count; i++)
 +  {
 +    struct top_hash_entry *en = lsa_list[i];
-       if ((pos + len) > ospf_pkt_bufsize(ifa))
++    uint len = en->lsa.length;
 +
 +    if ((pos + len) > maxsize)
 +    {
 +      /* The packet if full, stop adding LSAs and sent it */
 +      if (i > 0)
 +      break;
 +
 +      /* LSA is larger than MTU, check buffer size */
-       log(L_ERR "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", 
-           en->lsa_type, en->lsa.id, en->lsa.rt);
-       XXXX();
++      if (ospf_iface_assure_bufsize(ifa, pos + len) < 0)
 +      {
 +      /* Cannot fit in a tx buffer, skip that */
-             "LSUPD packet flooded via %s", ifa->iface->name);
++      log(L_ERR "OSPF: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)", 
++          ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt);
++      XXXX(); /* XXXX: handle packets with no LSA */
 +      continue;
 +      }
++
++      /* TX buffer could be reallocated */
++      pkt = ospf_tx_buffer(ifa);
 +    }
 +
 +    struct ospf_lsa_header *buf = ((void *) pkt) + pos;
 +    lsa_hton_hdr(&en->lsa, buf);
 +    lsa_hton_body(en->lsa_body, ((void *) buf) + sizeof(struct ospf_lsa_header),
 +                len - sizeof(struct ospf_lsa_header));
 +    buf->age = htons(MIN(en->lsa.age + ifa->inftransdelay, LSA_MAXAGE));
 +
 +    pos += len;
 +  }
 +   
 +  ospf_lsupd_set_lsa_count(pkt, hlen, i);
 +  pkt->length = htons(pos);
 +
 +  return i;
 +}
 +
 +
 +static void
 +ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_hash_entry *en)
 +{
 +  ospf_lsupd_prepare(po, ifa, &en, 1);
 +
 +  OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa),
- ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, unsigned lsa_count)
++            "LSUPD packet flooded via %s", ifa->ifname);
 +
 +  switch (ifa->type)
 +  {
 +  case OSPF_IT_BCAST:
 +    if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
 +      ospf_send_to_all(ifa);
 +    else
 +      ospf_send_to_des(ifa);
 +    break;
 +
 +  case OSPF_IT_NBMA:
 +    if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
 +      ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
 +    else
 +      ospf_send_to_bdr(ifa);
 +    break;
 +
 +  case OSPF_IT_PTP:
 +    ospf_send_to_all(ifa);
 +    break;
 +
 +  case OSPF_IT_PTMP:
 +    ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
 +    break;
 +
 +  case OSPF_IT_VLINK:
 +    ospf_send_to(ifa, ifa->vip);
 +    break;
 +
 +  default:
 +    bug("Bug in ospf_lsupd_flood()");
 +  }
 +}
 +
 +int
-   unsigned i, c;
++ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, uint lsa_count)
 +{
 +  struct ospf_iface *ifa = n->ifa;
 +  struct proto_ospf *po = ifa->oa->po;
-               "LSUPD packet sent to %I via %s", n->ip, ifa->iface->name);
++  uint i, c;
 +
 +  for (i = 0; i < lsa_count; i += c)
 +  {
 +    c = ospf_lsupd_prepare(po, ifa, lsa_list + i, lsa_count - i);
 +
 +    OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa),
++              "LSUPD packet sent to %I via %s", n->ip, ifa->ifname);
 +
 +    ospf_send_to(ifa, n->ip);
 +  }
 +
 +  return lsa_count;
 +}
 +
  void
 -ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
 +ospf_lsupd_rxmt(struct ospf_neighbor *n)
  {
 -  struct ospf_lsa_header *lsa = &en->lsa;
 -  struct proto *p = &po->proto;
 +  struct proto_ospf *po = n->ifa->oa->po;
 +
-   const unsigned max = 128;
++  const uint max = 128;
 +  struct top_hash_entry *entries[max];
 +  struct top_hash_entry *ret, *en;
-   unsigned i = 0;
++  uint i = 0;
 +
 +  WALK_SLIST(ret, n->lsrtl)
 +  {
 +    en = ospf_hash_find_entry(po->gr, ret);
 +    if (!en)
 +    {
 +      /* Probably flushed LSA, this should not happen */
 +      log(L_WARN "%s: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
 +        po->proto.name, ret->lsa_type, ret->lsa.id, ret->lsa.rt);
 +
 +      XXXX(); /* remove entry */
 +      continue;
 +    }
 +
 +    entries[i] = en;
 +    i++;
 +
 +    if (i == max)
 +      break;
 +  }
  
 -  lsa->age = LSA_MAXAGE;
 -  lsa->sn = LSA_MAXSEQNO;
 -  lsasum_calculate(lsa, en->lsa_body);
 -  OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
 -  OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
 -  ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
 +  ospf_lsupd_send(n, entries, i);
  }
index fad2ce73f94e24e74b46c58d55d1637efc5827ad,faaaf232573a99124d2549682c5b298ea78c6cfa..987de1faff79b24fda9d1a6045e8415ab1bbeb57
@@@ -531,11 -553,10 +530,10 @@@ neighbor_timer_hook(timer * timer
  {
    struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
    struct ospf_iface *ifa = n->ifa;
 -  struct proto *p = &ifa->oa->po->proto;
 +  struct proto_ospf *po = ifa->oa->po;
  
-   OSPF_TRACE(D_EVENTS,
-            "Inactivity timer fired on interface %s for neighbor %I.",
-            ifa->iface->name, n->ip);
 -  OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I.",
++  OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I",
+            ifa->ifname, n->ip);
    ospf_neigh_remove(n);
  }
  
@@@ -568,9 -588,9 +566,7 @@@ ospf_neigh_bfd_hook(struct bfd_request 
  
    if (req->down)
    {
--    OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s",
-              n->ip, n->ifa->iface->name);
 -             n->ip, n->ifa->ifname);
--
++    OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname);
      ospf_neigh_remove(n);
    }
  }
@@@ -630,30 -649,49 +625,30 @@@ rxmt_timer_hook(timer * timer
    // struct proto *p = &n->ifa->oa->po->proto;
    struct top_hash_entry *en;
  
 -  DBG("%s: RXMT timer fired on interface %s for neigh: %I.\n",
 +  DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
-       p->name, n->ifa->iface->name, n->ip);
+       p->name, n->ifa->ifname, n->ip);
  
 -  if(n->state < NEIGHBOR_EXSTART) return;
 -
 -  if (n->state == NEIGHBOR_EXSTART)
 +  switch (n->state)
    {
 +  case NEIGHBOR_EXSTART:
      ospf_dbdes_send(n, 1);
      return;
 -  }
  
 -  if ((n->state == NEIGHBOR_EXCHANGE) && n->myimms.bit.ms)    /* I'm master */
 +  case NEIGHBOR_EXCHANGE:
 +  if (n->myimms & DBDES_MS)
      ospf_dbdes_send(n, 0);
 +  case NEIGHBOR_LOADING:
 +    ospf_lsreq_send(n);
 +    return;
  
 +  case NEIGHBOR_FULL:
 +    /* LSA retransmissions */
 +    if (!EMPTY_SLIST(n->lsrtl))
 +      ospf_lsupd_rxmt(n);
 +    return;
  
 -  if (n->state < NEIGHBOR_FULL)       
 -    ospf_lsreq_send(n);       /* EXCHANGE or LOADING */
 -  else
 -  {
 -    if (!EMPTY_SLIST(n->lsrtl))       /* FULL */
 -    {
 -      list uplist;
 -      slab *upslab;
 -      struct l_lsr_head *llsh;
 -
 -      init_list(&uplist);
 -      upslab = sl_new(n->pool, sizeof(struct l_lsr_head));
 -
 -      WALK_SLIST(en, n->lsrtl)
 -      {
 -      if ((SNODE en)->next == (SNODE en))
 -        bug("RTList is cycled");
 -      llsh = sl_alloc(upslab);
 -      llsh->lsh.id = en->lsa.id;
 -      llsh->lsh.rt = en->lsa.rt;
 -      llsh->lsh.type = en->lsa.type;
 -      DBG("Working on ID: %R, RT: %R, Type: %u\n",
 -          en->lsa.id, en->lsa.rt, en->lsa.type);
 -      add_tail(&uplist, NODE llsh);
 -      }
 -      ospf_lsupd_send_list(n, &uplist);
 -      rfree(upslab);
 -    }
 +  default:
 +    return;
    }
  }
  
index ad027403c6a46937181ff29a2d4ca8b1717e8457,cf520401e4a985e8475f748585ac295cfe5e8713..eaa452d1c2a4593a6a1995442168734f4255c571
@@@ -379,20 -381,22 +381,20 @@@ ospf_build_attrs(ea_list * next, struc
  void
  schedule_net_lsa(struct ospf_iface *ifa)
  {
 -  struct proto *p = &ifa->oa->po->proto;
 +  struct proto_ospf *po = ifa->oa->po;
  
-   OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->iface->name);
+   OSPF_TRACE(D_EVENTS, "Scheduling network-LSA origination for iface %s", ifa->ifname);
    ifa->orignet = 1;
  }
  
  void
  schedule_link_lsa(struct ospf_iface *ifa)
  {
 -  struct proto *p = &ifa->oa->po->proto;
 +  struct proto_ospf *po = ifa->oa->po;
  
-   OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->iface->name);
+   OSPF_TRACE(D_EVENTS, "Scheduling link-LSA origination for iface %s", ifa->ifname);
    ifa->origlink = 1;
  }
 -#endif
  
  void
  schedule_rt_lsa(struct ospf_area *oa)
index 89e8fcf3083293b35a395b758b1a9823900b29db,66719e306b2a9a783d8ffd0756fcfd9edebb343d..f5b5e40e4a67b8034e2b9ecd45afcd99f426b320
@@@ -618,29 -687,22 +618,28 @@@ struct ospf_neighbo
    u8 adj;                     /* built adjacency? */
    u32 options;                        /* Options received */
  
 -  /* dr and bdr store IP address in OSPFv2 and router ID in OSPFv3,
 -     we use the same type to simplify handling */
 +  /* Entries dr and bdr store IP addresses in OSPFv2 and router IDs in
 +     OSPFv3, we use the same type to simplify handling */
    u32 dr;                     /* Neigbour's idea of DR */
    u32 bdr;                    /* Neigbour's idea of BDR */
 -
 -#ifdef OSPFv3
    u32 iface_id;                       /* ID of Neighbour's iface connected to common network */
 -#endif
  
 -  siterator dbsi;             /* Database summary list iterator */
 -  slist lsrql;                        /* Link state request */
 -  struct top_graph *lsrqh;    /* LSA graph */
 -  siterator lsrqi;
 -  slist lsrtl;                        /* Link state retransmission list */
 -  siterator lsrti;
 +  /* Database summary list iterator, controls initial dbdes exchange.
 +   * Advances in the LSA list as dbdes packets are sent.
 +   */
 +  siterator dbsi;             /* iterator of po->lsal */
 +
 +  /* Link state request list, controls initial LSA exchange.
 +   * Entries added when received in dbdes packets, removed as sent in lsreq packets.
 +   */
 +  slist lsrql;                        /* slist of struct top_hash_entry from n->lsrqh */
 +  struct top_graph *lsrqh;
 +
 +  /* Link state retransmission list, controls LSA retransmission during flood.
 +   * Entries added as sent in lsupd packets, removed when received in lsack packets.
 +   */
 +  slist lsrtl;                        /* slist of struct top_hash_entry from n->lsrth */
    struct top_graph *lsrth;
    timer *rxmt_timer;          /* RXMT timer */
    list ackl[2];
  #define ACKL_DIRECT 0
index c673c8b2f72019665c0a1b14b3e2a1506acdf46a,cd4b8a9750548dfeb4680f03593b01a211661453..5fca4d90fe104fc6fc659e776d04d0098a19cdfa
@@@ -37,18 -39,18 +37,17 @@@ ospf_pkt_fill_hdr(struct ospf_iface *if
  unsigned
  ospf_pkt_maxsize(struct ospf_iface *ifa)
  {
-   unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
    unsigned headers = SIZE_OF_IP_HEADER;
  
 -#ifdef OSPFv2
 +  /* For OSPFv2 */
    if (ifa->autype == OSPF_AUTH_CRYPT)
      headers += OSPF_AUTH_CRYPT_SIZE;
 -#endif
  
-   return mtu - headers;
+   return ifa->tx_length - headers;
  }
  
 -#ifdef OSPFv2
  
 +/* We assume OSPFv2 in ospf_pkt_finalize() */
  static void
  ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
  {
@@@ -323,10 -320,10 +322,10 @@@ ospf_rx_hook(sock *sk, int size
      return 1;
    }
  
-   unsigned plen = ntohs(pkt->length);
-   if (plen < sizeof(struct ospf_packet))
 -  uint plen = ntohs(ps->length);
++  uint plen = ntohs(pkt->length);
+   if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
    {
-     log(L_ERR "%s%I - too low value in size field (%u bytes)", mesg, sk->faddr, plen);
+     log(L_ERR "%s%I - invalid length (%u)", mesg, sk->faddr, plen);
      return 1;
    }
  
      return 1;
    }
  
 -#ifdef OSPFv2
 -  if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
 -      (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
 -                   plen - sizeof(struct ospf_packet), NULL)))
 +  if (ospf_is_v2(po) && ospf_pkt_get_autype(pkt) != OSPF_AUTH_CRYPT)
    {
-     unsigned hlen = sizeof(struct ospf_packet) - sizeof(union ospf_auth);
-     unsigned blen = plen - hlen;
 -    log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
 -    return 1;
 -  }
 -#endif
++    uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
++    uint blen = plen - hlen;
 +    void *body = ((void *) pkt) + hlen;
  
 +    if (! ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
 +    {
 +      log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
 +      return 1;
 +    }
 +  }
  
    /* Third, we resolve associated iface and handle vlinks. */
  
      n = find_neigh_by_ip(ifa, sk->faddr);
    else
      n = find_neigh(ifa, rid);
 -#else
 -  struct ospf_neighbor *n = find_neigh(ifa, rid);
 -#endif
  
 -  if(!n && (ps->type != HELLO_P))
 +  if (!n && (pkt->type != HELLO_P))
    {
      log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
-       sk->faddr, ifa->iface->name);
+       sk->faddr, ifa->ifname);
      return 1;
    }
  
@@@ -502,31 -517,18 +512,38 @@@ voi
  ospf_err_hook(sock * sk, int err)
  {
    struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
- //  struct proto *p = (struct proto *) (ifa->oa->po);
-   log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err);
+   struct proto *p = &(ifa->oa->po->proto);
+   log(L_ERR "%s: Socket error on %s: %M", p->name, ifa->ifname, err);
+ }
+ void
+ ospf_verr_hook(sock *sk, int err)
+ {
+   struct proto_ospf *po = (struct proto_ospf *) (sk->data);
+   struct proto *p =  &po->proto;
+   log(L_ERR "%s: Vlink socket error: %M", p->name, err);
  }
  
-   if (sk->tbuf != sk->tpos)
-     log(L_ERR "Aiee, old packet was overwritten in TX buffer");
 +void
 +ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
 +{
 +  sock *sk = ifa->sk;
 +  struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
 +  int plen = ntohs(pkt->length);
 +
-   sk_send_to(sk, plen, dst, 0);
 +  if (ospf_is_v2(ifa->oa->po))
 +  {
 +    if (ifa->autype == OSPF_AUTH_CRYPT)
 +      plen += OSPF_AUTH_CRYPT_SIZE;
 +
 +    ospf_pkt_finalize(ifa, pkt);
 +  }
 +
++  int done = sk_send_to(sk, plen, dst, 0);
++  if (!done)
++    log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
 +}
 +
  void
  ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
  {
index 5cd7bcc482f27f9e7f3c861ccb5c708198f93d8f,4ba1f08c922df49a1cd1bda2063452b22736b8d9..cd9e162a70541018e1c1119ab7e3cdc420d37a10
  #define _BIRD_OSPF_PACKET_H_
  
  void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type);
- unsigned ospf_pkt_maxsize(struct ospf_iface *ifa);
+ uint ospf_pkt_maxsize(struct ospf_iface *ifa);
  int ospf_rx_hook(sock * sk, int size);
- void ospf_tx_hook(sock * sk);
// void ospf_tx_hook(sock * sk);
  void ospf_err_hook(sock * sk, int err);
+ void ospf_verr_hook(sock *sk, int err);
 +void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
 +
  void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
  void ospf_send_to_bdr(struct ospf_iface *ifa);
 -void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
  
 -static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); }
 +static inline void ospf_send_to_all(struct ospf_iface *ifa)
 +{ ospf_send_to(ifa, ifa->all_routers); }
 +
 +static inline void ospf_send_to_des(struct ospf_iface *ifa)
 +{
 +  if (ipa_nonzero(ifa->des_routers))
 +    ospf_send_to(ifa, ifa->des_routers);
 +  else
 +    ospf_send_to_bdr(ifa);
 +}
 +
 +static inline unsigned ospf_pkt_hdrlen(struct proto_ospf *po)
 +{
 +  return ospf_is_v2(po) ?
 +    (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) :
 +    sizeof(struct ospf_packet);
 +}
 +
  
 -static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
 +static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
 +{ return ifa->sk->tbuf; }
  
- static inline unsigned ospf_pkt_bufsize(struct ospf_iface *ifa)
- {
-   /* Reserve buffer space for authentication footer */
-   unsigned res_size = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
-   return ifa->sk->tbsize - res_size;
- }
  
  #endif /* _BIRD_OSPF_PACKET_H_ */
diff --cc proto/ospf/rt.c
index b8f41f8d09a334455d2cd1f13c33594a1ab86bea,1b39bda092c8866c42e39b33d827866192734ddd..4dc7a5fcf950d2fc9f3c713c24d50025d584d795
@@@ -986,13 -1077,15 +986,13 @@@ check_nssa_lsa(struct proto_ospf *po, o
  static void
  ospf_check_vlinks(struct proto_ospf *po)
  {
-   struct ospf_iface *iface;
-   WALK_LIST(iface, po->iface_list)
 -  struct proto *p = &po->proto;
 -
+   struct ospf_iface *ifa;
+   WALK_LIST(ifa, po->iface_list)
    {
-     if (iface->type == OSPF_IT_VLINK)
+     if (ifa->type == OSPF_IT_VLINK)
      {
        struct top_hash_entry *tmp;
-       tmp = ospf_hash_find_rt(po->gr, iface->voa->areaid, iface->vid);
+       tmp = ospf_hash_find_rt(po->gr, ifa->voa->areaid, ifa->vid);
  
        if (tmp && (tmp->color == INSPF) && ipa_nonzero(tmp->lb) && tmp->nhs)
        {
index 341a771d9e01de2428fc3427be29476f407fe27c,4af5afa51451cd642acbc7c98e83ffed2e8ec9d5..ba4209b935ca59c2f4302db842ed527963429166
@@@ -840,23 -1201,33 +840,26 @@@ prepare_link_lsa_body(struct proto_osp
  }
  
  void
 -originate_link_lsa(struct ospf_iface *ifa)
 +ospf_originate_link_lsa(struct ospf_iface *ifa)
  {
 -  struct ospf_lsa_header lsa;
    struct proto_ospf *po = ifa->oa->po;
 -  struct proto *p = &po->proto;
 -  void *body;
  
-   /* FIXME check for vlink and skip that? */
+   /* Vlinks do not have link-LSAs */
+   if (ifa->type == OSPF_IT_VLINK)
+     return;
 -  OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname);
 +  struct ospf_lsa_new lsa = {
 +    .type = LSA_T_LINK,
 +    .dom  = ifa->iface_id,
 +    .id   = ifa->iface_id,
 +    .ifa  = ifa
 +  };
  
 -  lsa.age = 0;
 -  lsa.type = LSA_T_LINK;
 -  lsa.id = ifa->iface_id;
 -  lsa.rt = po->router_id;
 -  lsa.sn = get_seqnum(ifa->link_lsa);
 -  u32 dom = ifa->iface_id;
 +  prepare_link_lsa_body(po, ifa);
  
 -  body = originate_link_lsa_body(ifa, &lsa.length);
 -  lsasum_calculate(&lsa, body);
 -  ifa->link_lsa = lsa_install_new(po, &lsa, dom, body);
 -  ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
 +  ospf_originate_lsa(po, &lsa);
  
 +  // XXXX: review
    /* Just to be sure to not forget on our link LSA */
    if (ifa->state == OSPF_IS_DR)
      schedule_net_lsa(ifa);
@@@ -1438,529 -1911,3 +1441,527 @@@ can_flush_lsa(struct proto_ospf *po
  
    return 1;
  }
-   OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s",
-            ifa->iface->name);
 +
 +
 +/**
 + * ospf_install_lsa - install new LSA into database
 + * @po: OSPF protocol
 + * @lsa: LSA header
 + * @domain: domain of LSA
 + * @body: pointer to LSA body
 + *
 + * This function ensures installing new LSA into LSA database. Old instance is
 + * replaced. Several actions are taken to detect if new routing table
 + * calculation is necessary. This is described in 13.2 of RFC 2328.
 + */
 +struct top_hash_entry *
 +ospf_install_lsa(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body)
 +{
 +  /* LSA can be temporary, but body must be mb_allocated. */
 +  int change = 0;
 +  struct top_hash_entry *en;
 +
 +  en = ospf_hash_get(po->gr, domain, lsa->id, lsa->rt, lsa_type);
 +  if ((en = ospf_hash_find_header(po->gr, domain, lsa)) == NULL)
 +  {
 +    en = ospf_hash_get_header(po->gr, domain, lsa);
 +    change = 1;
 +  }
 +  else
 +  {
 +    if ((en->lsa.length != lsa->length) ||
 +      (en->lsa.type_raw != lsa->type_raw) ||  /* check for OSPFv2 options */
 +      (en->lsa.age == LSA_MAXAGE) ||
 +      (lsa->age == LSA_MAXAGE) ||
 +      memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header)))
 +      change = 1;
 +
 +    s_rem_node(SNODE en);
 +  }
 +
 +  DBG("Inst lsa: Id: %R, Rt: %R, Type: %u, Age: %u, Sum: %u, Sn: 0x%x\n",
 +      lsa->id, lsa->rt, lsa->type, lsa->age, lsa->checksum, lsa->sn);
 +
 +  s_add_tail(&po->lsal, SNODE en);
 +  en->inst_t = now;
 +  if (en->lsa_body != NULL)
 +    mb_free(en->lsa_body);
 +  en->lsa_body = body;
 +  memcpy(&en->lsa, lsa, sizeof(struct ospf_lsa_header));
 +  en->ini_age = en->lsa.age;
 +
 +  if (change)
 +    schedule_rtcalc(po);
 +
 +  return en;
 +}
 +
 +struct top_hash_entry *
 +ospf_originate_lsa(struct proto_ospf *po, struct ospf_lsa_new *lsa)
 +{
 +  struct top_hash_entry *en;
 +  u32 lsa_rt = po->router_id;
 +  u16 lsa_blen = po->lsab_used;
 +  u16 lsa_length = sizeof(struct ospf_lsa_header) + lsa_len1;
 +  void *lsa_body = po->lsab;
 +
 +  en = ospf_hash_get(po->gr, lsa->dom, lsa->id, lsa_rt, lsa->type);
 +
 +  if (en->lsa_next_body)
 +  {
 +    /* The scheduled LSA is the same as the new one */
 +    if ((lsa_blen == en->lsa_next_blen) && !memcmp(lsa_body, en->lsa_next_body, lsa_blen))
 +      goto drop;
 +
 +    // XXXX logmessage
 +
 +    /* Replace the scheduled LSA by the new one */
 +    mb_free(en->lsa_next_body);
 +    goto schedule;
 +  }
 +
 +  if (en->lsa_body && (en->lsa.age != LSA_MAXAGE))
 +  {
 +    /*
 +      casy:
 +        aktualni valid a stejne -> vyskocit
 +      aktualni valid, ale koliduje LSA ID -> error
 +      plati MINLSINTERVAL -> odlozit
 +      aktualni MAXSEQNUM -> odlozit
 +     */
 +    aa;
 +  }
 +
 +  if (en->lsa_body && (en->lsa.sn == LSA_MAXSEQNO))
 +  {
 +    if (en->lsa.age != LSA_MAXAGE)
 +    {
 +    }
 +
 +    goto schedule;
 +  }
 +
 +  if (en->inst_t && ((en->inst_t + MINLSINTERVAL) > now))
 +  {
 +    // XXXX logmessage
 +
 +    goto schedule;
 +  }
 + 
 +  if (ospf_is_v2(po))
 +    lsa_set_options(&hdr, options);
 +
 +  s_add_tail(&po->lsal, SNODE en);
 +  en->inst_t = now;
 +  if (en->lsa_body != NULL)
 +    mb_free(en->lsa_body);
 +  en->lsa_body = lsab_flush(po);
 +  en->ini_age = en->lsa.age;
 +
 +
 +  lsasum_calculate(&hdr, body);
 +  ospf_lsupd_flood(po, en, NULL);
 +  return en;
 +
 + schedule:
 +  en->lsa_next_body = lsab_flush(po);
 +  en->lsa_next_blen = blen;
 +  return en;
 +
 + drop:
 +  lsab_reset(po);
 +  return en;
 +}
 +
 +void
 +ospf_flush_lsa(struct proto_ospf *po, struct top_hash_entry *en)
 +{
 +  OSPF_TRACE(D_EVENTS, "Flushing LSA: Type: %04x, Id: %R, Rt: %R",
 +           en->lsa_type, en->lsa.id, en->lsa.rt);
 +
 +  en->lsa.age = LSA_MAXAGE;
 +  ospf_lsupd_flood(po, en, NULL);
 +}
 +
 +void
 +ospf_remove_lsa(struct proto_ospf *po, struct top_hash_entry *en)
 +{
 +  // XXXX: more cleanup
 +  s_rem_node(SNODE en);
 +  mb_free(en->lsa_body);
 +  en->lsa_body = NULL;
 +
 +  // ospf_hash_delete(po->gr, en);
 +}
 +
 +static void
 +ospf_refresh_lsa(struct proto_ospf *po, struct top_hash_entry *en)
 +{
 +  OSPF_TRACE(D_EVENTS, "Refreshing LSA: Type: %u, Id: %R, Rt: %R",
 +           en->lsa_type, en->lsa.id, en->lsa.rt);
 +
 +  en->lsa.sn++;
 +  en->lsa.age = 0;
 +  en->ini_age = 0;
 +  en->inst_t = now;
 +  lsasum_calculate(&en->lsa, en->lsa_body);
 +  ospf_lsupd_flood(po, en, NULL);
 +}
 +
 +
 +
 +
 +/* KILL */
 +
 +
 +
 +
 +void
 +update_rt_lsa(struct ospf_area *oa)
 +{
 +  struct proto_ospf *po = oa->po;
 +
 +  if ((oa->rt) && ((oa->rt->inst_t + MINLSINTERVAL)) > now)
 +    return;
 +  /*
 +   * Tick is probably set to very low value. We cannot
 +   * originate new LSA before MINLSINTERVAL. We will
 +   * try to do it next tick.
 +   */
 +
 +  originate_rt_lsa(oa);
 +  if (ospf_is_v3(po))
 +    originate_prefix_rt_lsa(oa);
 +
 +  schedule_rtcalc(po);
 +  oa->origrt = 0;
 +}
 +
 +
 +void
 +update_net_lsa(struct ospf_iface *ifa)
 +{
 +  struct proto_ospf *po = ifa->oa->po;
 + 
 +  if (ifa->net_lsa && ((ifa->net_lsa->inst_t + MINLSINTERVAL) > now))
 +    return;
 +  /*
 +   * It's too early to originate new network LSA. We will
 +   * try to do it next tick
 +   */
 +
 +  if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0))
 +    {
 +      flush_net_lsa(ifa);
 +      if (ospf_is_v3(po))
 +      flush_prefix_net_lsa(ifa);
 +    }
 +  else
 +    {
 +      originate_net_lsa(ifa);
 +      if (ospf_is_v3(po))
 +      originate_prefix_net_lsa(ifa);
 +    }
 +
 +  schedule_rtcalc(po);
 +  ifa->orignet = 0;
 +}
 +
 +
 +void
 +flush_net_lsa(struct ospf_iface *ifa)
 +{
 +  struct proto_ospf *po = ifa->oa->po;
 +  u32 dom = ifa->oa->areaid;
 +
 +  if (ifa->net_lsa == NULL)
 +    return;
 +
-   OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s",
-            ifa->iface->name);
++  OSPF_TRACE(D_EVENTS, "Flushing network-LSA for iface %s", ifa->ifname);
 +
 +  ifa->net_lsa->lsa.sn += 1;
 +  ifa->net_lsa->lsa.age = LSA_MAXAGE;
 +  lsasum_calculate(&ifa->net_lsa->lsa, ifa->net_lsa->lsa_body);
 +  ospf_lsupd_flood(po, NULL, NULL, &ifa->net_lsa->lsa, dom, 0);
 +  flush_lsa(ifa->net_lsa, po);
 +  ifa->net_lsa = NULL;
 +}
 +
 +
 +
 +static inline int
 +check_sum2_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric)
 +{
 +  struct ospf_lsa_sum2 *sum = en->lsa_body;
 +
 +  /* LSAID collision */
 +  if (fn->pxlen != ip4_masklen(sum->netmask))
 +    return -1;
 +
 +  return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
 +}
 +
 +static inline int
 +check_sum3_net_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric)
 +{
 +  struct ospf_lsa_sum3_net *sum = en->lsa_body;
 +  ip6_addr prefix;
 +  int pxlen;
 +  u8 pxopts;
 +  u16 rest;
 +  lsa_get_ipv6_prefix(sum->prefix, &prefix, &pxlen, &pxopts, &rest);
 +
 +  /* LSAID collision */
 +  if ((fn->pxlen != pxlen) || !ip6_equal(fn->prefix, prefix))
 +    return -1;
 +
 +  return (en->lsa.sn != LSA_MAXSEQNO) && (sum->metric == metric);
 +}
 +
 +
 +static int
 +check_sum_net_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn, u32 metric)
 +{
 +  int rv = ospf_is_v2(po) ?
 +    check_sum2_net_lsa(en, fn, metric) :
 +    check_sum3_net_lsa(en, fn, metric);
 +
 +  if (rv < 0)
 +    log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen);
 +
 +  return rv;
 +}
 +
 +static int
 +check_sum_rt_lsa(struct proto_ospf *po, struct top_hash_entry *en, u32 drid, u32 metric, u32 options)
 +{
 +  if (en->lsa.sn == LSA_MAXSEQNO)
 +    return 0;
 +
 +  if (ospf_is_v2(po))
 +  {
 +    struct ospf_lsa_sum2 *sum = en->lsa_body;
 +    return (sum->metric == metric);
 +  }
 +  else
 +  {
 +    struct ospf_lsa_sum3_rt *sum = en->lsa_body;
 +    return (sum->options == options) && (sum->metric == metric) && (sum->drid == drid);
 +  }
 +}
 +
 +
 +void
 +flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type)
 +{
 +  struct proto_ospf *po = oa->po;
 +  struct top_hash_entry *en;
 +  u32 dom, lsid, type;
 +
 +  if (type == ORT_NET)
 +  {
 +    dom  = oa->areaid;
 +    type = LSA_T_SUM_NET;
 +    lsid = fibnode_to_lsaid(po, fn);
 +  }
 +  else
 +  {
 +    /* In OSPFv3, LSA ID is meaningless, but we still use Router ID of ASBR */
 +    dom  = oa->areaid;
 +    type = LSA_T_SUM_RT;
 +    lsid = ipa_to_rid(fn->prefix);
 +  }
 +
 +  en = ospf_hash_find(po->gr, dom, lsid, po->router_id, type);
 +  if (en)
 +    {
 +      OSPF_TRACE(D_EVENTS, "Flushing summary-LSA (id=%R, type=%x)", lsid, type);
 +
 +      if ((type == ORT_NET) && (check_sum_net_lsa(po, en, fn, 0) < 0))
 +      return;
 +
 +      struct ospf_lsa_sum *sum = en->lsa_body;
 +      en->lsa.age = LSA_MAXAGE;
 +      en->lsa.sn = LSA_MAXSEQNO;
 +      lsasum_calculate(&en->lsa, sum);
 +      ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 1);
 +      if (can_flush_lsa(po)) flush_lsa(en, po);
 +    }
 +}
 +
 +
 +
 +/*
 + * check_ext_lsa() combines functions of check_*_lsaid_collision() and
 + * check_*_lsa_same(). 'en' is existing ext LSA, and rest parameters
 + * are parameters of new ext route.  Function returns -1 if there is
 + * LSAID collision, returns 1 if the existing LSA is the same and
 + * returns 0 otherwise (in that case, we need to originate a new LSA).
 + *
 + * Really, checking for the same parameters is not as important as in
 + * summary LSA origination, because in most cases the duplicate
 + * external route propagation would be stopped by the nest. But there
 + * are still some cases (route reload, the same route propagated through
 + * different protocol) so it is also done here.
 + */
 +
 +static inline int
 +check_ext2_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
 +{
 +  struct ospf_lsa_ext2 *ext = en->lsa_body;
 +
 +  /* LSAID collision */
 +  if  (fn->pxlen != ip4_masklen(ext->netmask))
 +    return -1;
 +
 +  return (en->lsa.sn != LSA_MAXSEQNO) && (ext->metric == metric) &&
 +    (ext->tag == tag) && ip4_equal(ext->fwaddr, ipa_to_ip4(fwaddr));
 +}
 +
 +static inline int
 +check_ext3_lsa(struct top_hash_entry *en, struct fib_node *fn, u32 metric, ip_addr fwaddr, u32 tag)
 +{
 +  struct ospf_lsa_ext3 *ext = en->lsa_body;
 +  ip_addr prefix;
 +  int pxlen;
 +  u8 pxopts;
 +  u16 rest;
 +
 +  u32 *buf = lsa_get_ipv6_prefix(ext->rest, &prefix, &pxlen, &pxopts, &rest);
 +
 +  /* LSAID collision */
 +  if ((fn->pxlen != pxlen) || !ipa_equal(fn->prefix, prefix))
 +    return -1;
 +
 +  if (en->lsa.sn == LSA_MAXSEQNO)
 +    return 0;
 +
 +  u32 rt_metric = ext->metric & METRIC_MASK;
 +  ip_addr rt_fwaddr = IPA_NONE;
 +  u32 rt_tag = 0;
 +
 +  if (ext->metric & LSA_EXT3_FBIT)
 +    buf = lsa_get_ipv6_addr(buf, &rt_fwaddr);
 +
 +  if (ext->metric & LSA_EXT3_TBIT)
 +    rt_tag = *buf++;
 +
 +  return (rt_metric == metric) && ipa_equal(rt_fwaddr, fwaddr) && (rt_tag == tag);
 +}
 +
 +static int
 +check_ext_lsa(struct proto_ospf *po, struct top_hash_entry *en, struct fib_node *fn,
 +            u32 metric, ip_addr fwaddr, u32 tag)
 +{
 +  int rv = ospf_is_v2(po) ?
 +    check_ext2_lsa(en, fn, metric, fwaddr, tag) :
 +    check_ext3_lsa(en, fn, metric, fwaddr, tag);
 +
 +  if (rv < 0)
 +    log(L_ERR "%s: LSAID collision for %I/%d", po->proto.name, fn->prefix, fn->pxlen);
 +
 +  return rv;
 +}
 +
 +
 +void
 +flush_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src, int nssa)
 +{
 +  struct proto_ospf *po = oa->po;
 +  struct proto *p = &po->proto;
 +  struct top_hash_entry *en;
 +
 +  u32 dom = nssa ? oa->areaid : 0;
 +  u32 type = nssa ? LSA_T_NSSA : LSA_T_EXT;
 +  u32 lsid = fibnode_to_lsaid(po, fn);
 +
 +  en = ospf_hash_find(po->gr, dom, lsid, po->router_id, type);
 +  if (en)
 +    {
 +      OSPF_TRACE(D_EVENTS, "Flushing %s-LSA for %I/%d",
 +               nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
 +
 +      if (check_ext_lsa(po, en, fn, 0, IPA_NONE, 0) < 0)
 +      return;
 +
 +      /* Clean up source bits */
 +      if (src) // XXXX ???
 +      fn->flags &= ~OSPF_RT_SRC;
 +      ospf_lsupd_flush_nlsa(po, en);
 +    }
 +}
 +
 +
 +void
 +update_link_lsa(struct ospf_iface *ifa)
 +{
 +  if (ifa->link_lsa && ((ifa->link_lsa->inst_t + MINLSINTERVAL) > now))
 +    return;
 +  /*
 +   * It's too early to originate new link LSA. We will
 +   * try to do it next tick
 +   */
 +  originate_link_lsa(ifa);
 +  ifa->origlink = 0;
 +}
 +
 +
 +void
 +flush_prefix_net_lsa(struct ospf_iface *ifa)
 +{
 +  struct proto_ospf *po = ifa->oa->po;
 +  struct top_hash_entry *en = ifa->pxn_lsa;
 +  u32 dom = ifa->oa->areaid;
 +
 +  if (en == NULL)
 +    return;
 +
-   OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->iface->name);
++  OSPF_TRACE(D_EVENTS, "Flushing network prefix-LSA for iface %s", ifa->ifname);
 +
 +  en->lsa.sn += 1;
 +  en->lsa.age = LSA_MAXAGE;
 +  lsasum_calculate(&en->lsa, en->lsa_body);
 +  ospf_lsupd_flood(po, NULL, NULL, &en->lsa, dom, 0);
 +  flush_lsa(en, po);
 +  ifa->pxn_lsa = NULL;
 +}
 +
 +
 +static s32
 +get_seqnum(struct top_hash_entry *en)
 +{
 +  if (!en)
 +    return LSA_INITSEQNO;
 +
 +  if (en->lsa.sn == LSA_MAXSEQNO)
 +  {
 +    log(L_WARN "OSPF: Premature origination of LSA (Type: %04x, Id: %R, Rt: %R)",
 +      en->lsa_type, en->lsa.id, en->lsa.rt);
 +    return LSA_INITSEQNO;
 +  }
 +
 +  return en->lsa.sn + 1;
 +}
 +
 +
 +
 +  OSPF_TRACE(D_EVENTS, "Originating router-LSA for area %R", oa->areaid);
-   OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->iface->name);
++  OSPF_TRACE(D_EVENTS, "Originating network-LSA for iface %s", ifa->ifname);
 +  OSPF_TRACE(D_EVENTS, "Originating net-summary-LSA for %I/%d (metric %d)", fn->prefix, fn->pxlen, metric);
 +  OSPF_TRACE(D_EVENTS, "Originating rt-summary-LSA for %R (metric %d)", rid, metric);
 +  OSPF_TRACE(D_EVENTS, "Originating %s-LSA for %I/%d",
 +           nssa ? "NSSA" : "AS-external", fn->prefix, fn->pxlen);
-   OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->iface->name);
++  OSPF_TRACE(D_EVENTS, "Originating link-LSA for iface %s", ifa->ifname);
 +  OSPF_TRACE(D_EVENTS, "Originating router prefix-LSA for area %R", oa->areaid);
++  OSPF_TRACE(D_EVENTS, "Originating network prefix-LSA for iface %s", ifa->ifname);
 +
 +
 +  en = ospf_hash_find(po->gr, lsa.dom, lsa.id, po->router_id, lsa.type);
 +  if (en && check_ext_lsa(po, en, fn, metric, fwaddr, tag))
 +    return;
 +
 +  *length = sizeof(struct ospf_lsa_header) + po->lsab_used;
 +  return lsab_flush(po);
 +
 +  *length = po->lsab_used + sizeof(struct ospf_lsa_header);
 +  return lsab_flush(po);
index b0af926633df8c51ebc42bf2314ea146ea9c07b1,997fda3de33ac793cc094b18f9524ca2d5ebfe10..dd4eacbe6f5760385303ddc60bb1c159d0454c46
@@@ -419,10 -419,8 +419,8 @@@ radv_sk_open(struct radv_iface *ifa
    if (sk_open(sk) != 0)
      goto err;
  
-   sk->saddr = ifa->addr->ip;
    /* We want listen just to ICMPv6 messages of type RS and RA */
 -  if (sk_set_icmp_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0)
 +  if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0)
      goto err;
  
    if (sk_setup_multicast(sk) < 0)
diff --cc proto/rip/rip.c
index bc93dc7e68993adeb89ac937e2d87c41cec4bc5f,9730df77692fae9c774a9a9ef84d496b94c361f6..f697cb483448f8355a712455fb6a3ffbfe80e34e
@@@ -719,9 -717,12 +719,8 @@@ new_iface(struct proto *p, struct ifac
    if (new) {
      if (new->addr->flags & IA_PEER)
        log( L_WARN "%s: rip is not defined over unnumbered links", p->name );
-     rif->sock->saddr = IPA_NONE;
      if (rif->multicast) {
 -#ifndef IPV6
 -      rif->sock->daddr = ipa_from_u32(0xe0000009);
 -#else
 -      rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9);
 -#endif
 +      rif->sock->daddr = rip_is_old(p) ? IP4_ALL_RIP_ROUTERS : IP6_ALL_RIP_ROUTERS;
      } else {
        rif->sock->daddr = new->addr->brd;
      }
index d84cbb89deea70d23f36a2e79d3f215b7cad0290,9b115acd2c2f6b54adafade975e47157f9930649..7aa94f6c4530df00118791c6966b5a9ca901e785
@@@ -62,16 -66,14 +62,16 @@@ static_install(struct proto *p, struct 
      return;
  
    DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest);
 -  bzero(&a, sizeof(a));
 -  a.src = p->main_source;
 -  a.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC;
 -  a.scope = SCOPE_UNIVERSE;
 -  a.cast = RTC_UNICAST;
 -  a.dest = r->dest;
 -  a.gw = r->via;
 -  a.iface = ifa;
 +
 +  rta a = {
-     .src = p->main_source;
++    .src = p->main_source,
 +    .source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC,
 +    .scope = SCOPE_UNIVERSE,
 +    .cast = RTC_UNICAST,
 +    .dest = r->dest,
 +    .gw = r->via,
 +    .iface = ifa
 +  };
  
    if (r->dest == RTD_MULTIPATH)
      {
index 6de329198f34f6a5626424cad40f9c90c7e0fb1c,e45deb6f76b0bb4e546819518435c34d6f2d527f..f2131e5f52ffabf2e589bba6a03e9659e461acb9
  #define TCP_MD5SIG    TCP_SIGNATURE_ENABLE
  #endif
  
- static inline char *
- sk_bind_to_iface(sock *s)
 -#ifdef IPV6
 -
 -static inline void
 -set_inaddr(struct in6_addr * ia, ip_addr a)
--{
-   /* Unfortunately not available */
-   return NULL;
 -  ipa_hton(a);
 -  memcpy(ia, &a, sizeof(a));
 -}
 -
 -static inline void
 -get_inaddr(ip_addr *a, struct in6_addr *ia)
 -{
 -  memcpy(a, ia, sizeof(*a));
 -  ipa_ntoh(*a);
--}
 -
--
 -#else
  
  #include <net/if.h>
  #include <net/if_dl.h>
 -static inline void
 -set_inaddr(struct in_addr * ia, ip_addr a)
 -{
 -  ipa_hton(a);
 -  memcpy(&ia->s_addr, &a, sizeof(a));
 -}
 -
 -static inline void
 -get_inaddr(ip_addr *a, struct in_addr *ia)
 -{
 -  memcpy(a, &ia->s_addr, sizeof(*a));
 -  ipa_ntoh(*a);
 -}
 -
+ #include <netinet/in_systm.h> // Workaround for some BSDs
+ #include <netinet/ip.h>
  
  /* BSD Multicast handling for IPv4 */
  
@@@ -58,13 -86,13 +54,13 @@@ sk_setup_multicast4(sock *s
  
  
  static inline char *
 -sysio_join_group(sock *s, ip_addr maddr)
 +sk_join_group4(sock *s, ip_addr maddr)
  {
-       struct ip_mreq  mreq;
+       struct ip_mreq mreq;
  
        bzero(&mreq, sizeof(mreq));
 -      set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
 -      set_inaddr(&mreq.imr_multiaddr, maddr);
 +      ipa_put_in4(&mreq.imr_interface, s->iface->addr->ip);
 +      ipa_put_in4(&mreq.imr_multiaddr, maddr);
  
        /* And this one sets interface for _receiving_ multicasts from */
        if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
@@@ -116,39 -148,48 +112,39 @@@ sk_request_cmsg4_pktinfo(sock *s
  }
  
  static inline void
 -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
 +sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm)
  {
 -  struct cmsghdr *cm;
 -  struct in_addr *ra = NULL;
 -  struct sockaddr_dl *ri = NULL;
 -  unsigned char *ttl = NULL;
 +  if ((cm->cmsg_type == IP_RECVDSTADDR) && (s->flags & SKF_LADDR_RX))
 +    s->laddr = ipa_get_in4((struct in_addr *) CMSG_DATA(cm));
  
 -  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
 -  {
 -    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
 -      ra = (struct in_addr *) CMSG_DATA(cm);
 -
 -    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
 -      ri = (struct sockaddr_dl *) CMSG_DATA(cm);
 -
 -    if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVTTL)
 -      ttl = (unsigned char *) CMSG_DATA(cm);
 -  }
 +  if ((cm->cmsg_type == IP_RECVIF) && (s->flags & SKF_LADDR_RX))
 +    s->lifindex = ((struct sockaddr_dl *) CMSG_DATA(cm))->sdl_index;
 +}
  
 -  if (s->flags & SKF_LADDR_RX)
 -  {
 -    s->laddr = IPA_NONE;
 -    s->lifindex = 0;
 +static inline char *
 +sk_request_cmsg4_ttl(sock *s)
 +{
 +  int ok = 1;
  
 -    if (ra)
 -      get_inaddr(&s->laddr, ra);
 -    if (ri)
 -      s->lifindex = ri->sdl_index;
 -  }
 +  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0)
 +    return "IP_RECVTTL";
  
 -  if (s->flags & SKF_TTL_RX)
 -    s->ttl = ttl ? *ttl : -1;
 +  return NULL;
 +}
  
 -  // log(L_WARN "RX %I %d", s->laddr, s->lifindex);
 +static inline void
 +sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
 +{
 +  if ((cm->cmsg_type == IP_RECVTTL) && (s->flags & SKF_TTL_RX))
 +    s->ttl = * (unsigned char *) CMSG_DATA(cm);
  }
  
  /* Unfortunately, IP_SENDSRCADDR does not work for raw IP sockets on BSD kernels */
- /*
- static void
- sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
+ static inline void
 -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
++sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
  {
+ #ifdef IP_SENDSRCADDR
    struct cmsghdr *cm;
    struct in_addr *sa;
  
    cm->cmsg_len = CMSG_LEN(sizeof(*sa));
  
    sa = (struct in_addr *) CMSG_DATA(cm);
--  set_inaddr(sa, s->saddr);
++  ipa_put_in4(&sa, s->saddr);
  
    msg->msg_controllen = cm->cmsg_len;
 -fill_ip_header(sock *s, void *hdr, int dlen)
+ #endif
+ }
+ static void
 -  set_inaddr(&ip->ip_src, s->saddr);
 -  set_inaddr(&ip->ip_dst, s->daddr);
++sk_prepare_ip_header(sock *s, void *hdr, int dlen)
+ {
+   struct ip *ip = hdr;
+   bzero(ip, 20);
+   ip->ip_v = 4;
+   ip->ip_hl = 5;
+   ip->ip_tos = (s->tos < 0) ? 0 : s->tos;
+   ip->ip_len = 20 + dlen;
+   ip->ip_ttl = (s->ttl < 0) ? 64 : s->ttl;
+   ip->ip_p = s->dport;
++  ipa_put_in4(&ip->ip_src, s->saddr);
++  ipa_put_in4(&ip->ip_dst, s->daddr);
+ #ifdef __OpenBSD__
+   /* OpenBSD expects ip_len in network order, other BSDs expect host order */
+   ip->ip_len = htons(ip->ip_len);
+ #endif
  }
- */
  
 -#endif
 -
  
  #include <netinet/tcp.h>
  #ifndef TCP_KEYLEN_MAX
index 8c52d8681c4c69479a443fb1f7deb11e4703b42a,56c3387d145c83bd0631e1381e70e0a36c0f5c24..433f3a9a72964fd6010b5f1a9143f872d15f8fd5
@@@ -6,11 -6,9 +6,8 @@@
   *    Can be freely distributed and used under the terms of the GNU GPL.
   */
  
- #include <linux/socket.h>
- #include <linux/tcp.h>
  #include <net/if.h>
  
 -#ifdef IPV6
  
  #ifndef IPV6_UNICAST_HOPS
  /* Needed on glibc 2.0 systems */
  #define CONFIG_IPV6_GLIBC_20
  #endif
  
 -static inline void
 -set_inaddr(struct in6_addr *ia, ip_addr a)
 -{
 -  ipa_hton(a);
 -  memcpy(ia, &a, sizeof(a));
 -}
 -
 -static inline void
 -get_inaddr(ip_addr *a, struct in6_addr *ia)
 -{
 -  memcpy(a, ia, sizeof(*a));
 -  ipa_ntoh(*a);
 -}
 -
 -#else
 -
 -static inline void
 -set_inaddr(struct in_addr *ia, ip_addr a)
 -{
 -  ipa_hton(a);
 -  memcpy(&ia->s_addr, &a, sizeof(a));
 -}
 -
 -static inline void
 -get_inaddr(ip_addr *a, struct in_addr *ia)
 -{
 -  memcpy(a, &ia->s_addr, sizeof(*a));
 -  ipa_ntoh(*a);
 -}
 -
  
- static inline char *
- sk_bind_to_iface(sock *s)
- {
-   struct ifreq ifr;
-   strcpy(ifr.ifr_name, s->iface->name);
-   if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
-     return "SO_BINDTODEVICE";
-   return NULL;
- }
  #ifndef HAVE_STRUCT_IP_MREQN
  /* Several versions of glibc don't define this structure, so we have to do it ourselves */
  struct ip_mreqn
@@@ -47,8 -62,7 +31,7 @@@ static inline void fill_mreqn(struct ip
  {
    bzero(m, sizeof(*m));
    m->imr_ifindex = ifa->index;
-   ipa_put_in4(&m->imr_address, saddr);
 -  set_inaddr(&m->imr_multiaddr, maddr);
 +  ipa_put_in4(&m->imr_multiaddr, maddr);
  }
  
  static inline char *
@@@ -77,8 -90,8 +59,7 @@@ sk_join_group4(sock *s, ip_addr maddr
  {
    struct ip_mreqn m;
  
--  /* And this one sets interface for _receiving_ multicasts from */
-   fill_mreqn(&m, s->iface, s->saddr, maddr);
+   fill_mreqn(&m, maddr, s->iface);
    if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0)
      return "IP_ADD_MEMBERSHIP";
  
@@@ -90,17 -103,18 +71,15 @@@ sk_leave_group4(sock *s, ip_addr maddr
  {
    struct ip_mreqn m;
  
--  /* And this one sets interface for _receiving_ multicasts from */
-   fill_mreqn(&m, s->iface, s->saddr, maddr);
+   fill_mreqn(&m, maddr, s->iface);
    if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0)
      return "IP_DROP_MEMBERSHIP";
  
    return NULL;
  }
  
 -#endif
 -
  
- /* For the case that we have older kernel headers */
+ /* For the case that we have older libc headers */
  /* Copied from Linux kernel file include/linux/tcp.h */
  
  #ifndef TCP_MD5SIG
@@@ -164,48 -181,55 +143,47 @@@ sk_request_cmsg4_pktinfo(sock *s
  {
    int ok = 1;
  
-   if (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
 -  if ((s->flags & SKF_LADDR_RX) &&
 -      (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
++  if (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
      return "IP_PKTINFO";
  
 -  if ((s->flags & SKF_TTL_RX) &&
 -      (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
 -    return "IP_RECVTTL";
 -
    return NULL;
  }
  
 -static void
 -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
 +static inline void
 +sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm)
  {
 -  struct cmsghdr *cm;
 -  struct in_pktinfo *pi = NULL;
 -  int *ttl = NULL;
 -
 -  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
 +  if ((cm->cmsg_type == IP_PKTINFO) && (s->flags & SKF_LADDR_RX))
    {
 -    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO)
 -      pi = (struct in_pktinfo *) CMSG_DATA(cm);
 -
 -    if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_TTL)
 -      ttl = (int *) CMSG_DATA(cm);
 +    struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm);
 +    s->laddr = ipa_get_in4(&pi->ipi_addr);
 +    s->lifindex = pi->ipi_ifindex;
    }
 +}
  
 -  if (s->flags & SKF_LADDR_RX)
 -  {
 -    if (pi)
 -    {
 -      get_inaddr(&s->laddr, &pi->ipi_addr);
 -      s->lifindex = pi->ipi_ifindex;
 -    }
 -    else
 -    {
 -      s->laddr = IPA_NONE;
 -      s->lifindex = 0;
 -    }
 -  }
  
 -  if (s->flags & SKF_TTL_RX)
 -    s->ttl = ttl ? *ttl : -1;
 +#define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(int))
  
 -  return;
 +static inline char *
 +sk_request_cmsg4_ttl(sock *s)
 +{
 +  int ok = 1;
 +
-   if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0)
++  if (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0)
 +    return "IP_RECVTTL";
 +
 +  return NULL;
 +}
 +
 +static inline void
 +sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
 +{
 +  if ((cm->cmsg_type == IP_TTL) && (s->flags & SKF_TTL_RX))
 +    s->ttl = * (int *) CMSG_DATA(cm);
  }
  
 -static void
 -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
 +
- /*
- static void
- sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
++static inline void
++sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
  {
    struct cmsghdr *cm;
    struct in_pktinfo *pi;
    cm->cmsg_len = CMSG_LEN(sizeof(*pi));
  
    pi = (struct in_pktinfo *) CMSG_DATA(cm);
-   set_inaddr(&pi->ipi_spec_dst, s->saddr);
    pi->ipi_ifindex = s->iface ? s->iface->index : 0;
 -  set_inaddr(&pi->ipi_spec_dst, s->saddr);
 -  set_inaddr(&pi->ipi_addr, IPA_NONE);
++  ipa_put_in4(&pi->ipi_spec_dst, s->saddr);
++  ipa_put_in4(&pi->ipi_addr, IPA_NONE);
  
    msg->msg_controllen = cm->cmsg_len;
  }
- */
  
 -#endif
 -
  
  #ifndef IP_MINTTL
  #define IP_MINTTL 21
  #define IPV6_MINHOPCOUNT 73
  #endif
  
 -
 -#ifndef IPV6
 -
 -static int
 +static inline char *
  sk_set_min_ttl4(sock *s, int ttl)
  {
-   if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
+   if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
 -  {
 -    if (errno == ENOPROTOOPT)
 -      log(L_ERR "Kernel does not support IPv4 TTL security");
 -    else
 -      log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
 +    return "IP_MINTTL";
  
 -    return -1;
 -  }
 -
 -  return 0;
 +  return NULL;
  }
  
 -#else
 -
 -static int
 +static inline char *
  sk_set_min_ttl6(sock *s, int ttl)
  {
-   if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
+   if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0)
 -  {
 -    if (errno == ENOPROTOOPT)
 -      log(L_ERR "Kernel does not support IPv6 TTL security");
 -    else
 -      log(L_ERR "sk_set_min_ttl6: setsockopt: %m");
 +    return "IPV6_MINHOPCOUNT";
  
 -    return -1;
 -  }
 -
 -  return 0;
 +  return NULL;
  }
  
 -#endif
 -
  
  #ifndef IPV6_TCLASS
  #define IPV6_TCLASS 67
index 63b8dce30810761406ae60fe0693310c98d2e91d,428f24ccee883bbb982f253172c7a57dd6edc579..a903c20a7e94f82bff1ad0f63f04b76d0d14cd90
@@@ -720,84 -746,55 +764,83 @@@ sk_request_cmsg6_pktinfo(sock *s
  {
    int ok = 1;
  
-   if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
 -  if ((s->flags & SKF_LADDR_RX) &&
 -      (setsockopt(s->fd, SOL_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0))
++  if (setsockopt(s->fd, SOL_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
      return "IPV6_RECVPKTINFO";
  
 -  if ((s->flags & SKF_TTL_RX) &&
 -      (setsockopt(s->fd, SOL_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0))
 +  return NULL;
 +}
 +
 +static inline void
 +sk_process_cmsg6_pktinfo(sock *s, struct cmsghdr *cm)
 +{
 +  if ((cm->cmsg_type == IPV6_PKTINFO) && (s->flags & SKF_LADDR_RX))
 +  {
 +    struct in6_pktinfo *pi = (struct in6_pktinfo *) CMSG_DATA(cm);
 +    s->laddr = ipa_get_in6(&pi->ipi6_addr);
 +    s->lifindex = pi->ipi6_ifindex;
 +  }
 +}
 +
 +
 +#define CMSG6_SPACE_TTL CMSG_SPACE(sizeof(int))
 +
 +static inline char *
 +sk_request_cmsg6_ttl(sock *s)
 +{
 +  int ok = 1;
 +
-   if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0)
++  if (setsockopt(s->fd, SOL_IPV6, IPV6_RECVHOPLIMIT, &ok, sizeof(ok)) < 0)
      return "IPV6_RECVHOPLIMIT";
  
    return NULL;
  }
  
 +static inline void
 +sk_process_cmsg6_ttl(sock *s, struct cmsghdr *cm)
 +{
 +  if ((cm->cmsg_type == IPV6_HOPLIMIT) && (s->flags & SKF_TTL_RX))
 +    s->ttl = * (int *) CMSG_DATA(cm);
 +}
 +
 +
 +#define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
 +                        CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL)
 +#define CMSG_TX_SPACE MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO)
 +
 +
  static void
 -sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
 +sk_process_cmsgs(sock *s, struct msghdr *msg)
  {
    struct cmsghdr *cm;
 -  struct in6_pktinfo *pi = NULL;
 -  int *hlim = NULL;
  
 -  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
 +  if (s->flags & SKF_LADDR_RX)
    {
 -    if (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
 -      pi = (struct in6_pktinfo *) CMSG_DATA(cm);
 -
 -    if (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT)
 -      hlim = (int *) CMSG_DATA(cm);
 +    s->laddr = IPA_NONE;
 +    s->lifindex = 0;
    }
  
 -  if (s->flags & SKF_LADDR_RX)
 +  if (s->flags & SKF_TTL_RX)
 +    s->ttl = -1;
 +
 +  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
    {
-     if ((cm->cmsg_level == IPPROTO_IP) && sk_is_ipv4(s))
 -    if (pi)
++    if ((cm->cmsg_level == SOL_IP) && sk_is_ipv4(s))
      {
 -      get_inaddr(&s->laddr, &pi->ipi6_addr);
 -      s->lifindex = pi->ipi6_ifindex;
 +      sk_process_cmsg4_pktinfo(s, cm);
 +      sk_process_cmsg4_ttl(s, cm);
      }
 -    else
 +
-     if ((cm->cmsg_level == IPPROTO_IPV6) && sk_is_ipv6(s))
++    if ((cm->cmsg_level == SOL_IPV6) && sk_is_ipv6(s))
      {
 -      s->laddr = IPA_NONE;
 -      s->lifindex = 0;
 +      sk_process_cmsg6_pktinfo(s, cm);
 +      sk_process_cmsg6_ttl(s, cm);
      }
    }
 -
 -  if (s->flags & SKF_TTL_RX)
 -    s->ttl = hlim ? *hlim : -1;
 -
 -  return;
  }
  
 -static void
 -sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
 +
- /*
- static void
- sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
++static inline void
++sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
  {
    struct cmsghdr *cm;
    struct in6_pktinfo *pi;
    cm->cmsg_len = CMSG_LEN(sizeof(*pi));
  
    pi = (struct in6_pktinfo *) CMSG_DATA(cm);
-   set_inaddr(&pi->ipi6_addr, s->saddr);
    pi->ipi6_ifindex = s->iface ? s->iface->index : 0;
 -  set_inaddr(&pi->ipi6_addr, s->saddr);
++  ipa_put_in6(&pi->ipi6_addr, s->saddr);
  
    msg->msg_controllen = cm->cmsg_len;
-   return;
  }
- */
 -#endif
 -
 -static char *
 -sk_set_ttl_int(sock *s)
 -{
 -#ifdef IPV6
 -  if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
 -    return "IPV6_UNICAST_HOPS";
 -#else
 -  if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
 -    return "IP_TTL";
 -#endif
 -  return NULL;
++static void
++sk_prepare_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
++{
++  if (sk_is_ipv4(s))
++    sk_prepare_cmsgs4(s, msg, cbuf, cbuflen);
++  else
++    sk_prepare_cmsgs6(s, msg, cbuf, cbuflen);
+ }
 +
  #define ERR(x) do { err = x; goto bad; } while(0)
  #define WARN(x) log(L_WARN "sk_setup: %s: %m", x)
  
@@@ -834,51 -841,59 +882,80 @@@ sk_setup(sock *s
  
    if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
      ERR("fcntl(O_NONBLOCK)");
 -  if (s->type == SK_UNIX)
 +
 +  if (!s->af)
      return NULL;
  
-   if (sk_is_ipv4(s) && (s->tos >= 0))
-     if (setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
-       WARN("IP_TOS");
+   if (ipa_nonzero(s->saddr) && !(s->flags & SKF_BIND))
+     s->flags |= SKF_PKTINFO;
  
-   if (sk_is_ipv6(s) && (s->tos >= 0))
-     if (setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0)
-       WARN("IPV6_TCLASS");
+ #ifdef CONFIG_USE_HDRINCL
 -  if ((s->type == SK_IP) && (s->flags & SKF_PKTINFO))
++  if (sk_is_ipv4(s) && (s->type == SK_IP) && (s->flags & SKF_PKTINFO))
+   {
+     s->flags &= ~SKF_PKTINFO;
+     s->flags |= SKF_HDRINCL;
+     if (setsockopt(fd, SOL_IP, IP_HDRINCL, &one, sizeof(one)) < 0)
+       ERR("IP_HDRINCL");
+   }
+ #endif
  
-   if (sk_is_ipv6(s) && (s->flags & SKF_V6ONLY))
-     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
-       WARN("IPV6_V6ONLY");
+   if (s->iface)
+   {
+ #ifdef SO_BINDTODEVICE
+     struct ifreq ifr;
+     strcpy(ifr.ifr_name, s->iface->name);
+     if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
+       ERR("SO_BINDTODEVICE");
+ #endif
  
-   if (s->priority >= 0)
-     sk_set_priority(s, s->priority);
+ #ifdef CONFIG_UNIX_DONTROUTE
+     if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
+       ERR("SO_DONTROUTE");
+ #endif
+   }
  
 -  if ((s->ttl >= 0) && (err = sk_set_ttl_int(s)))
 -    goto bad;
 +  if (s->ttl >= 0)
 +    if (sk_set_ttl(s, s->ttl) < 0)
 +      ERR("sk_set_ttl");
  
 -  if (err = sysio_register_cmsgs(s))
 -    goto bad;
 +  if (sk_is_ipv4(s))
 +  {
 +    if (s->flags & SKF_LADDR_RX)
 +      if (err = sk_request_cmsg4_pktinfo(s))
 +      goto bad;
  
 +    if (s->flags & SKF_TTL_RX)
 +      if (err = sk_request_cmsg4_ttl(s))
 +      goto bad;
 +  }
  
 -#ifdef IPV6
 -  if ((s->tos >= 0) && setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0)
 -    WARN("IPV6_TCLASS");
 -#else
 -  if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
 -    WARN("IP_TOS");
 -#endif
 +  if (sk_is_ipv6(s))
 +  {
 +    if (s->flags & SKF_LADDR_RX)
 +      if (err = sk_request_cmsg6_pktinfo(s))
 +      goto bad;
 +
 +    if (s->flags & SKF_TTL_RX)
-       if (err = sk_request_cmsg6_ttl(s));
++      if (err = sk_request_cmsg6_ttl(s))
++      goto bad;
 +  }
 +
++  if (sk_is_ipv4(s) && (s->tos >= 0))
++    if (setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
++      WARN("IP_TOS");
++
++  if (sk_is_ipv6(s) && (s->tos >= 0))
++    if (setsockopt(fd, SOL_IPV6, IPV6_TCLASS, &s->tos, sizeof(s->tos)) < 0)
++      WARN("IPV6_TCLASS");
++
++  if (sk_is_ipv6(s) && (s->flags & SKF_V6ONLY))
++    if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
++      WARN("IPV6_V6ONLY");
+   if (s->priority >= 0)
+     sk_set_priority(s, s->priority);
 -#ifdef IPV6
 -  if ((s->flags & SKF_V6ONLY) && setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
 -    WARN("IPV6_V6ONLY");
 -#endif
 +  return NULL;
  
  bad:
    return err;
@@@ -901,30 -916,11 +978,23 @@@ sk_set_ttl(sock *s, int ttl
  {
    char *err;
  
- #ifdef CONFIG_UNIX_DONTROUTE
-       int one = 1;
-       if (ttl == 1)
-       if (setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
-         ERR("SO_DONTROUTE");
- #endif
 +  if (sk_is_ipv4(s))
 +    {
 +      if (setsockopt(s->fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
 +      ERR("IP_TTL");
 +    }
 +  else
 +    {
 +      if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0)
 +      ERR("IPV6_UNICAST_HOPS");
 +    }
 +
    s->ttl = ttl;
 -  if (err = sk_set_ttl_int(s))
 -    log(L_ERR "sk_set_ttl: %s: %m", err);
 +  return 0;
  
 -  return (err ? -1 : 0);
 + bad:
 +  log(L_ERR "sk_set_ttl: %s: %m", err);
 +  return -1;
  }
  
  /**
@@@ -1022,62 -1010,54 +1092,59 @@@ sk_set_icmp6_filter(sock *s, int p1, in
    ICMP6_FILTER_SETPASS(p1, &f);
    ICMP6_FILTER_SETPASS(p2, &f);
  
-   if (setsockopt(s->fd, IPPROTO_ICMPV6, ICMP6_FILTER, &f, sizeof(f)) < 0)
+   if (setsockopt(s->fd, SOL_ICMPV6, ICMP6_FILTER, &f, sizeof(f)) < 0)
      {
 -      log(L_ERR "sk_setup_icmp_filter: ICMP6_FILTER: %m");
 +      log(L_ERR "sk_set_icmp6_filter: ICMP6_FILTER: %m");
        return -1;
      }
  
    return 0;
  }
  
 -int
 -sk_setup_multicast(sock *s)
++#ifdef CONFIG_IPV6_GLIBC_20
++#define ipv6mr_interface ipv6mr_ifindex
++#endif
 +
 +static inline void
 +fill_mreq6(struct ipv6_mreq *m, struct iface *ifa, ip_addr maddr)
  {
 -  char *err;
 -  int zero = 0;
 -  int index;
 +  bzero(m, sizeof(*m));
  
- #ifdef CONFIG_IPV6_GLIBC_20
-   m->ipv6mr_ifindex = ifa->index;
- #else
 -  ASSERT(s->iface);
 +  m->ipv6mr_interface = ifa->index;
- #endif
 +  ipa_put_in6(&m->ipv6mr_multiaddr, maddr);
 +}
 +
 +static inline char *
 +sk_setup_multicast6(sock *s)
 +{
 +  int zero = 0;
 +  int index = s->iface->index;
  
 -  index = s->iface->index;
    if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
 -    ERR("IPV6_MULTICAST_HOPS");
 +    return "IPV6_MULTICAST_HOPS";
    if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
 -    ERR("IPV6_MULTICAST_LOOP");
 +    return "IPV6_MULTICAST_LOOP";
    if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0)
 -    ERR("IPV6_MULTICAST_IF");
 +    return "IPV6_MULTICAST_IF";
  
-   /* Is this necessary? */
-   return sk_bind_to_iface(s);
 -  return 0;
 -
 -bad:
 -  log(L_ERR "sk_setup_multicast: %s: %m", err);
 -  return -1;
++  return NULL;
  }
  
 -#ifdef CONFIG_IPV6_GLIBC_20
 -#define ipv6mr_interface ipv6mr_ifindex
 -#endif
 -
  int
 -sk_join_group(sock *s, ip_addr maddr)
 +sk_setup_multicast(sock *s)
  {
 -  struct ipv6_mreq mreq;
 +  char *err;
  
-   ASSERT(s->iface && s->iface->addr);
 -  set_inaddr(&mreq.ipv6mr_multiaddr, maddr);
 -  mreq.ipv6mr_interface = s->iface->index;
++  ASSERT(s->iface);
 +
 +  if (sk_is_ipv4(s))
 +    err = sk_setup_multicast4(s);
 +  else
 +    err = sk_setup_multicast6(s);
  
 -  if (setsockopt(s->fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
 +  if (err)
      {
 -      log(L_ERR "sk_join_group: IPV6_JOIN_GROUP: %m");
 +      log(L_ERR "sk_setup_multicast: %s: %m", err);
        return -1;
      }
  
@@@ -1215,62 -1197,64 +1282,71 @@@ sk_passive_connected(sock *s, struct so
  int
  sk_open(sock *s)
  {
-   int type = s->type;
-   int has_src = ipa_nonzero(s->saddr) || s->sport;
 -  int fd;
 -  int one = 1;
+   int do_bind = 0;
+   int bind_port = 0;
+   ip_addr bind_addr = IPA_NONE;
 -  sockaddr sa;
    char *err;
  
-   switch (type)
+   switch (s->type)
      {
      case SK_TCP_ACTIVE:
        s->ttx = "";                    /* Force s->ttx != s->tpos */
        /* Fall thru */
      case SK_TCP_PASSIVE:
 -      fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
 +      s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6;
 +      s->fd = socket(s->af, SOCK_STREAM, IPPROTO_TCP);
+       bind_port = s->sport;
+       bind_addr = s->saddr;
+       do_bind = bind_port || ipa_nonzero(bind_addr);
        break;
 -
--    case SK_UDP:
 -      fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
++  
++  case SK_UDP:
 +      s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6;
 +      s->fd = socket(s->af, SOCK_DGRAM, IPPROTO_UDP);
+       bind_port = s->sport;
+       bind_addr = (s->flags & SKF_BIND) ? s->saddr : IPA_NONE;
+       do_bind = 1;
        break;
      case SK_IP:
 -      fd = socket(BIRD_PF, SOCK_RAW, s->dport);
 +      s->af = (s->flags & SKF_V4ONLY) ? AF_INET : AF_INET6;
 +      s->fd = socket(s->af, SOCK_RAW, s->dport);
+       bind_port = 0;
+       bind_addr = (s->flags & SKF_BIND) ? s->saddr : IPA_NONE;
+       do_bind = ipa_nonzero(bind_addr);
        break;
      case SK_MAGIC:
 -      fd = s->fd;
 -      break;
 +      if (err = sk_setup(s))
 +      goto bad;
 +      sk_insert(s);
 +      return 0;
      default:
-       bug("sk_open() called for invalid sock type %d", type);
+       bug("sk_open() called for invalid sock type %d", s->type);
      }
 +
 +  int fd = s->fd;
    if (fd < 0)
 -    die("sk_open: socket: %m");
 -  s->fd = fd;
 +    ERR("socket");
  
    if (err = sk_setup(s))
      goto bad;
  
-   if (has_src)
 +  SOCKADDR_DEFINE(sa, sa_len, s->af);
 +
+   if (do_bind)
      {
-       int port;
-       if (type == SK_IP)
-       port = 0;
-       else
+       if (bind_port)
        {
-         port = s->sport;
 +        int one = 1;
++
          if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
            ERR("SO_REUSEADDR");
-       
  #ifdef CONFIG_NO_IFACE_BIND
          /* Workaround missing ability to bind to an iface */
-         if ((type == SK_UDP) && s->iface && ipa_zero(s->saddr))
+         if ((s->type == SK_UDP) && s->iface && ipa_zero(bind_addr))
          {
            if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
              ERR("SO_REUSEPORT");
  #endif
        }
  
-       sockaddr_fill(sa, s->saddr, s->iface, port);
 -      fill_in_sockaddr(&sa, bind_addr, s->iface, bind_port);
 -      if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
++      sockaddr_fill(sa, bind_addr, s->iface, bind_port);
 +      if (bind(fd, sa, sa_len) < 0)
        ERR("bind");
      }
 -  fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport);
 +  sockaddr_fill(sa, s->daddr, s->iface, s->dport);
  
    if (s->password)
 -    {
 -      int rv = sk_set_md5_auth_int(s, &sa, s->password);
 -      if (rv < 0)
 -      goto bad_no_log;
 -    }
 +    if (sk_set_md5_auth_int(s, sa, sa_len, s->password) < 0)
 +      goto bad_no_log;
  
-   switch (type)
+   switch (s->type)
      {
      case SK_TCP_ACTIVE:
 -      if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
 +      if (connect(fd, sa, sa_len) >= 0)
        sk_tcp_connected(s);
        else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS &&
               errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH)
@@@ -1366,6 -1354,79 +1443,80 @@@ sk_open_unix(sock *s, char *name
    die("Unable to create control socket %s", name);
  }
  
 -  sockaddr dst;
+ static inline int
+ sk_sendmsg(sock *s)
+ {
+   struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
+   byte cmsg_buf[CMSG_TX_SPACE];
 -  fill_in_sockaddr(&dst, s->daddr, s->iface, s->dport);
 -    .msg_name = &dst,
 -    .msg_namelen = sizeof(dst),
++  SOCKADDR_DEFINE(dst, dst_len, s->af);
++  sockaddr_fill(dst, s->daddr, s->iface, s->dport);
+   struct msghdr msg = {
 -    fill_ip_header(s, hdr, iov.iov_len);
++    .msg_name = dst,
++    .msg_namelen = dst_len,
+     .msg_iov = &iov,
+     .msg_iovlen = 1
+   };
+ #ifdef CONFIG_USE_HDRINCL
+   byte hdr[20];
+   struct iovec iov2[2] = { {hdr, 20}, iov };
+   if (s->flags & SKF_HDRINCL)
+   {
 -    sysio_prepare_tx_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
++    sk_prepare_ip_header(s, hdr, iov.iov_len);
+     msg.msg_iov = iov2;
+     msg.msg_iovlen = 2;
+   }
+ #endif
+   if (s->flags & SKF_PKTINFO)
 -  sockaddr src;
++    sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
+   return sendmsg(s->fd, &msg, 0);
+ }
+ static inline int
+ sk_recvmsg(sock *s)
+ {
+   struct iovec iov = {s->rbuf, s->rbsize};
+   byte cmsg_buf[CMSG_RX_SPACE];
 -    .msg_name = &src,
 -    .msg_namelen = sizeof(src),
++
++  SOCKADDR_DEFINE(src, src_len, s->af);
+   struct msghdr msg = {
 -  get_sockaddr(&src, &s->faddr, NULL, &s->fport, 1);
 -  sysio_process_rx_cmsgs(s, &msg);
++    .msg_name = src,
++    .msg_namelen = src_len,
+     .msg_iov = &iov,
+     .msg_iovlen = 1,
+     .msg_control = cmsg_buf,
+     .msg_controllen = sizeof(cmsg_buf),
+     .msg_flags = 0
+   };
+   int rv = recvmsg(s->fd, &msg, 0);
+   if (rv < 0)
+     return rv;
+   //ifdef IPV4
+   //  if (cf_type == SK_IP)
+   //    rv = ipv4_skip_header(pbuf, rv);
+   //endif
++  sockaddr_read(src, &s->faddr, NULL, &s->fport, 1);
++  sk_process_cmsgs(s, &msg);
+   if (msg.msg_flags & MSG_TRUNC)
+     s->flags |= SKF_TRUNCATED;
+   else
+     s->flags &= ~SKF_TRUNCATED;
+   return rv;
+ }
  static inline void reset_tx_buffer(sock *s) { s->ttx = s->tpos = s->tbuf; }
  
  static int
@@@ -1381,6 -1442,6 +1532,7 @@@ sk_maybe_write(sock *s
        while (s->ttx != s->tpos)
        {
          e = write(s->fd, s->ttx, s->tpos - s->ttx);
++
          if (e < 0)
            {
              if (errno != EINTR && errno != EAGAIN)
@@@ -1558,22 -1613,9 +1703,7 @@@ sk_read(sock *s
        return s->rx_hook(s, 0);
      default:
        {
-       SOCKADDR_DEFINE(sa, sa_len, s->af);
--      int e;
-       struct iovec iov = {s->rbuf, s->rbsize};
-       byte cmsg_buf[CMSG_RX_SPACE];
-       struct msghdr msg = {
-         .msg_name = sa,
-         .msg_namelen = sa_len,
-         .msg_iov = &iov,
-         .msg_iovlen = 1,
-         .msg_control = cmsg_buf,
-         .msg_controllen = sizeof(cmsg_buf),
-         .msg_flags = 0};
--
-       e = recvmsg(s->fd, &msg, 0);
 -      e = sk_recvmsg(s);
++      int e = sk_recvmsg(s);
  
        if (e < 0)
          {