]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '6ac4f87a2d661c739e55a63577e7bccf696c7abd' into integrated
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 31 Jul 2013 14:16:48 +0000 (16:16 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 31 Jul 2013 14:29:34 +0000 (16:29 +0200)
Conflicts:

lib/socket.h
proto/ospf/config.Y
proto/ospf/iface.c
proto/ospf/ospf.h
proto/rip/rip.c
sysdep/bsd/sysio.h
sysdep/linux/sysio.h
sysdep/unix/io.c

1  2 
lib/socket.h
proto/ospf/config.Y
proto/ospf/iface.c
proto/ospf/ospf.h
proto/ospf/packet.c
proto/rip/config.Y
proto/rip/rip.c
proto/rip/rip.h
sysdep/bsd/sysio.h
sysdep/linux/sysio.h
sysdep/unix/io.c

diff --cc lib/socket.h
index a68ef490ece3277d891e666e1e8e6aebf1f144c8,6e0a769bb08058bcadbb6da12b5fed15773ba562..5f642fc90bf44b9c3ea2a26731066ceaaccd5bfc
@@@ -89,10 -86,10 +89,11 @@@ extern int sk_priority_control;    /* Sugg
  
  /* Socket flags */
  
- #define SKF_V4ONLY    1       /* Use IPv4 for IP sockets */
- #define SKF_V6ONLY    2       /* Use IPV6_V6ONLY socket option */
- #define SKF_LADDR_RX  4       /* Report local address for RX packets */
- #define SKF_LADDR_TX  6       /* Allow to specify local address for TX packets */
 -#define SKF_V6ONLY    1       /* Use IPV6_V6ONLY socket option */
 -#define SKF_LADDR_RX  2       /* Report local address for RX packets */
 -#define SKF_LADDR_TX  4       /* Allow to specify local address for TX packets */
 -#define SKF_TTL_RX    8       /* Report TTL / Hop Limit for RX packets */
++#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 */
  
  
  /*
index 2350deaf1cad2c49b3db08be989df2e9349db0d6,f042e1aa26a3251e9728980f8d8c3a44510a4ebc..ea186ea1d991c719c6fa6624f2cc578d0c5f3c00
@@@ -297,7 -307,9 +297,9 @@@ ospf_iface_item
   | 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"); } 
   | TX tos { OSPF_PATT->tx_tos = $2; }
   | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
 - | password_list
+  | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
+  | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
 + | password_list { ospf_check_auth(); }
   ;
  
  pref_list:
index 7164a4a0e4a3a128316e273526e9474949fb5962,698ef6208aa50028f71e905ce0abc1dbcfc2eef0..448b08d11d93f29d2bdf45d3f3e922bbf9e4aef5
@@@ -132,9 -130,8 +132,9 @@@ ospf_sk_open(struct ospf_iface *ifa
      }
      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 = 1;    /* Hack, this will affect just the multicast packets */
+       sk->ttl = ifa->cf->ttl_security ? 255 : 1;
  
        if (sk_setup_multicast(sk) < 0)
          goto err;
@@@ -535,10 -534,11 +535,11 @@@ ospf_iface_new(struct ospf_area *oa, st
    ifa->rxbuf = ip->rxbuf;
    ifa->check_link = ip->check_link;
    ifa->ecmp_weight = ip->ecmp_weight;
 -
 -#ifdef OSPFv2
+   ifa->check_ttl = (ip->ttl_security == 1);
    ifa->autype = ip->autype;
    ifa->passwords = ip->passwords;
 +  ifa->instance_id = ip->instance_id;
 +
    ifa->ptp_netmask = addr ? !(addr->flags & IA_PEER) : 0;
    if (ip->ptp_netmask < 2)
      ifa->ptp_netmask = ip->ptp_netmask;
index d6b97ebf12ea3b8d9649f840bb724fec9939280a,f1409af342a372f0a1352803b17ce5caed1c2407..55331697c4b01810291c0b656c5f94e46d04eb95
@@@ -754,9 -816,16 +755,10 @@@ struct ospf_iface_pat
    u8 check_link;
    u8 ecmp_weight;
    u8 real_bcast;              /* Not really used in OSPFv3 */
-   u8 ptp_netmask;             /* bool but 2 for unspecified */
+   u8 ptp_netmask;             /* bool + 2 for unspecified */
+   u8 ttl_security;            /* bool + 2 for TX only */
 -
 -#ifdef OSPFv2
 -  list *passwords;
 -#endif
 -
 -#ifdef OSPFv3
    u8 instance_id;
 -#endif
 +  list *passwords;
  };
  
  int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
Simple merge
index 4b57a9bf1f4a036b6d03d549b68ad27b14f99c6d,791c43a2cdbdb2942eff622feb49bb7514114867..57e291cbac3f77c658eda3f74d97e341f0b3bad9
@@@ -22,12 -22,18 +22,15 @@@ CF_DEFINE
  #define RIP_CFG ((struct rip_proto_config *) this_proto)
  #define RIP_IPATT ((struct rip_patt *) this_ipatt)
  
 -#ifdef IPV6
 -#define RIP_DEFAULT_TTL_SECURITY 2
 -#else
 -#define RIP_DEFAULT_TTL_SECURITY 0
 -#endif
++static inline int rip_cfg_is_old(void) { return RIP_CFG->c.protocol == &proto_rip; }
++static inline int rip_cfg_is_ng(void)  { return RIP_CFG->c.protocol == &proto_ripng; }
  CF_DECLS
  
 -CF_KEYWORDS(RIP, INFINITY, METRIC, PORT, PERIOD, GARBAGE, TIMEOUT,
 +CF_KEYWORDS(RIP, RIPNG, INFINITY, METRIC, PORT, PERIOD, GARBAGE, TIMEOUT,
            MODE, BROADCAST, MULTICAST, QUIET, NOLISTEN, VERSION1, 
-           AUTHENTICATION, NONE, PLAINTEXT, MD5,
-           HONOR, NEVER, NEIGHBOR, ALWAYS, TX, PRIORITY,
+           AUTHENTICATION, NONE, PLAINTEXT, MD5, TTL, SECURITY,
+           HONOR, NEVER, NEIGHBOR, ALWAYS, TX, PRIORITY, ONLY,
            RIP_METRIC, RIP_TAG)
  
  %type <i> rip_mode rip_auth
@@@ -107,6 -106,7 +112,7 @@@ rip_iface_init
       RIP_IPATT->metric = 1;
       RIP_IPATT->tx_tos = IP_PREC_INTERNET_CONTROL;
       RIP_IPATT->tx_priority = sk_priority_control;
 -     RIP_IPATT->ttl_security = RIP_DEFAULT_TTL_SECURITY;
++     RIP_IPATT->ttl_security = rip_cfg_is_ng() ? 1 : 0;
     }
   ;
  
diff --cc proto/rip/rip.c
index f59487ddd069e5bd39ecf428028088633502c3bf,3ec070b3e8ef686e6131b98ba7db254c58fad2ea..40b9789f9652e2660baa3361ed26e4811b109675
@@@ -479,10 -478,18 +479,18 @@@ rip_rx(sock *s, int size
      return 1;
  
    iface = i->iface;
 -#endif
 +
  
+   if (i->check_ttl && (s->ttl < 255))
+   {
+     log( L_REMOTE "%s: Discarding packet with TTL %d (< 255) from %I on %s",
+        p->name, s->ttl, s->faddr, i->iface->name);
+     return 1;
+   }
    CHK_MAGIC;
 -  DBG( "RIP: message came: %d bytes from %I via %s\n", size, s->faddr, i->iface ? i->iface->name : "(dummy)" );
 +  DBG( "RIP: message came: %d bytes from %I via %s\n", size, s->faddr, iface ? iface->name : "(dummy)" );
    size -= sizeof( struct rip_packet_heading );
    if (size < 0) BAD( "Too small packet" );
    if (size % sizeof( struct rip_block )) BAD( "Odd sized packet" );
@@@ -705,13 -713,12 +714,13 @@@ new_iface(struct proto *p, struct ifac
    rif->sock->err_hook = rip_tx_err;
    rif->sock->daddr = IPA_NONE;
    rif->sock->dport = P_CF->port;
 +  rif->sock->flags = rip_is_old(p) ? SKF_V4ONLY : SKF_V6ONLY;
    if (new)
      {
-       rif->sock->ttl = 1;
        rif->sock->tos = PATT->tx_tos;
        rif->sock->priority = PATT->tx_priority;
-       rif->sock->flags |= SKF_LADDR_RX;
+       rif->sock->ttl = PATT->ttl_security ? 255 : 1;
 -      rif->sock->flags = SKF_LADDR_RX | (rif->check_ttl ? SKF_TTL_RX : 0);
++      rif->sock->flags |= SKF_LADDR_RX | (rif->check_ttl ? SKF_TTL_RX : 0);
      }
  
    if (new) {
diff --cc proto/rip/rip.h
Simple merge
index 3506f56fc83aca49b286252818e8b19dd0582a3f,031eac9af92f6a6aee8a2959a737fbf697737acd..e33bc9c66f24332fc06d48cca2470e63965b4199
@@@ -81,43 -113,69 +81,57 @@@ sk_leave_group4(sock *s, ip_addr maddr
  /* BSD RX/TX packet info handling for IPv4 */
  /* it uses IP_RECVDSTADDR / IP_RECVIF socket options instead of IP_PKTINFO */
  
- #define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct sockaddr_dl)))
 -#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_addr)) + \
 -                     CMSG_SPACE(sizeof(struct sockaddr_dl)) + \
 -                     CMSG_SPACE(sizeof(char)))
--#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_addr))
++#define CMSG_SPACE_PKTINFO4 (CMSG_SPACE(sizeof(struct in_addr)) + \
++                           CMSG_SPACE(sizeof(struct sockaddr_dl)))
++#define CMSG_SPACE_PKTINFO6 CMSG_SPACE(sizeof(struct in6_pktinfo))
  
--static char *
- sk_request_pktinfo4(sock *s)
 -sysio_register_cmsgs(sock *s)
++#define CMSG_RX_SPACE (MAX(CMSG_SPACE_PKTINFO4,CMSG_SPACE_PKTINFO6) + CMSG_SPACE(sizeof(int)))
++#define CMSG_TX_SPACE MAX(CMSG_SPACE_PKTINFO4,CMSG_SPACE_PKTINFO6)
++
++
++static inline char *
++sk_request_cmsg4_pktinfo(sock *s)
  {
    int ok = 1;
--  if (s->flags & SKF_LADDR_RX)
-     {
-       if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
-       return "IP_RECVDSTADDR";
 -  {
 -    if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
 -      return "IP_RECVDSTADDR";
  
-       if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
-       return "IP_RECVIF";
-     }
 -    if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
 -      return "IP_RECVIF";
 -  }
 -
 -  if ((s->flags & SKF_TTL_RX) &&
 -      (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0))
 -    return "IP_RECVTTL";
++  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVDSTADDR, &ok, sizeof(ok)) < 0)
++    return "IP_RECVDSTADDR";
++  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVIF, &ok, sizeof(ok)) < 0)
++    return "IP_RECVIF";
  
    return NULL;
  }
  
--static void
- sk_process_rx_cmsg4(sock *s, struct cmsghdr *cm)
 -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_addr *ra = NULL;
 -  struct sockaddr_dl *ri = NULL;
 -  unsigned char *ttl = NULL;
 -
 -  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_type == IP_RECVDSTADDR) && (s->flags & SKF_LADDR_RX))
++    s->laddr = ipa_get_in4((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)
 +{
-   if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
-     {
-       struct in_addr *ra = (struct in_addr *) CMSG_DATA(cm);
-       s->laddr = ipa_get_in4(ra);
-     }
-   if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
-     {
-       struct sockaddr_dl *ri = (struct sockaddr_dl *) CMSG_DATA(cm);
-       s->lifindex = ri->sdl_index;
-     }
-   // log(L_WARN "RX %I %d", s->laddr, s->lifindex);
++  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
index 13f3713e4b8f4c1b733c36fe05994d645e0c9956,250ed5866370773d8a57d0b6101ee5587d3b8ecd..8c52d8681c4c69479a443fb1f7deb11e4703b42a
@@@ -157,34 -192,63 +157,52 @@@ sk_set_md5_auth_int(sock *s, struct soc
  /* RX/TX packet info handling for IPv4 */
  /* Mostly similar to standardized IPv6 code */
  
- #define CMSG_SPACE_PKTINFO4 CMSG_SPACE(sizeof(struct in_pktinfo))
- #define CMSG_SPACE_PKTINFO6 CMSG_SPACE(sizeof(struct in6_pktinfo))
 -#define CMSG_RX_SPACE (CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)))
 -#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_pktinfo))
++#define CMSG4_SPACE_PKTINFO CMSG_SPACE(sizeof(struct in_pktinfo))
  
- #define CMSG_RX_SPACE MAX(CMSG_SPACE_PKTINFO4,CMSG_SPACE_PKTINFO6)
- #define CMSG_TX_SPACE MAX(CMSG_SPACE_PKTINFO4,CMSG_SPACE_PKTINFO6)
 -static char *
 -sysio_register_cmsgs(sock *s)
++static inline char *
++sk_request_cmsg4_pktinfo(sock *s)
+ {
+   int ok = 1;
 -  if ((s->flags & SKF_LADDR_RX) &&
 -      (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0))
++  if (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
+     return "IP_PKTINFO";
 -  if ((s->flags & SKF_TTL_RX) &&
 -      (setsockopt(s->fd, IPPROTO_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 == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO)
 -      pi = (struct in_pktinfo *) CMSG_DATA(cm);
 -
 -    if (cm->cmsg_level == IPPROTO_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))
 +
 +static inline char *
- sk_request_pktinfo4(sock *s)
++sk_request_cmsg4_ttl(sock *s)
 +{
 +  int ok = 1;
-   if (s->flags & SKF_LADDR_RX)
-     if (setsockopt(s->fd, IPPROTO_IP, IP_PKTINFO, &ok, sizeof(ok)) < 0)
-       return "IP_PKTINFO";
++
++  if (setsockopt(s->fd, IPPROTO_IP, IP_RECVTTL, &ok, sizeof(ok)) < 0)
++    return "IP_RECVTTL";
 +
 +  return NULL;
 +}
  
 -  return;
 +static inline void
- sk_process_rx_cmsg4(sock *s, struct cmsghdr *cm)
++sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm)
 +{
-   if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO)
-     {
-       struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm);
-       s->laddr = ipa_get_in4(&pi->ipi_addr);
-       s->lifindex = pi->ipi_ifindex;
-     }
++  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)
index 93fe06e9968ba210ca4318f39392d9bd4ffebded,9386388538f4361d3abb04e6c988f0d364c347a0..85b16b09ace03ca7c6dd263728464d05b55efaab
@@@ -700,42 -685,65 +700,96 @@@ sk_insert(sock *s
  #ifndef IPV6_RECVPKTINFO
  #define IPV6_RECVPKTINFO IPV6_PKTINFO
  #endif
 -static char *
 -sysio_register_cmsgs(sock *s)
+ /*
+  * Same goes for IPV6_HOPLIMIT -> IPV6_RECVHOPLIMIT.
+  */
+ #ifndef IPV6_RECVHOPLIMIT
+ #define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
+ #endif
- sk_request_pktinfo6(sock *s)
++
++#define CMSG6_SPACE_PKTINFO CMSG_SPACE(sizeof(struct in6_pktinfo))
 +
 +static inline char *
++sk_request_cmsg6_pktinfo(sock *s)
  {
    int ok = 1;
-   if (s->flags & SKF_LADDR_RX)
-     if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
-       return "IPV6_RECVPKTINFO";
 -  if ((s->flags & SKF_LADDR_RX) &&
 -      (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0))
++  if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
+     return "IPV6_RECVPKTINFO";
 -  if ((s->flags & SKF_TTL_RX) &&
 -      (setsockopt(s->fd, IPPROTO_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)
+     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
- sk_process_rx_cmsgs(sock *s, struct msghdr *msg)
 -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;
  
-   if (!(s->flags & SKF_LADDR_RX))
-     return;
 -  for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
++  if (s->flags & SKF_LADDR_RX)
+   {
 -    if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
 -      pi = (struct in6_pktinfo *) CMSG_DATA(cm);
 -
 -    if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT)
 -      hlim = (int *) CMSG_DATA(cm);
++    s->laddr = IPA_NONE;
++    s->lifindex = 0;
+   }
  
-   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 (pi)
++    if ((cm->cmsg_level == IPPROTO_IP) && sk_is_ipv4(s))
      {
-       if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
-       {
-         struct in6_pktinfo *pi = (struct in6_pktinfo *) CMSG_DATA(cm);
-         s->laddr = ipa_get_in6(&pi->ipi6_addr);
-         s->lifindex = pi->ipi6_ifindex;
-       }
 -      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
 +
-       sk_process_rx_cmsg4(s, cm);
++    if ((cm->cmsg_level == IPPROTO_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)
@@@ -794,14 -815,16 +848,33 @@@ sk_setup(sock *s
    if (s->priority >= 0)
      sk_set_priority(s, s->priority);
  
-   // XXXX better error handling
 -#ifdef IPV6
 -  int v = 1;
 -  if ((s->flags & SKF_V6ONLY) && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0)
 -    WARN("IPV6_V6ONLY");
 -#endif
 -
    if (s->ttl >= 0)
-     sk_set_ttl(s, s->ttl);
 -    err = sk_set_ttl_int(s);
++    if (sk_set_ttl(s, s->ttl) < 0)
++      ERR("sk_set_ttl");
 +
 +  if (sk_is_ipv4(s))
-     err = sk_request_pktinfo4(s);
-   else
-     err = sk_request_pktinfo6(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;
++  }
++
++  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));
++  }
++
++  return NULL;
 -  sysio_register_cmsgs(s);
  bad:
    return err;
  }
@@@ -1492,8 -1487,8 +1565,8 @@@ sk_read(sock *s
            return 0;
          }
        s->rpos = s->rbuf + e;
 -      get_sockaddr(&sa, &s->faddr, NULL, &s->fport, 1);
 -      sysio_process_rx_cmsgs(s, &msg);
 +      sockaddr_read(sa, &s->faddr, NULL, &s->fport, 1);
-       sk_process_rx_cmsgs(s, &msg);
++      sk_process_cmsgs(s, &msg);
  
        s->rx_hook(s, e);
        return 1;