#endif
struct linux_state {
+ int sol, so_mtu_discover, so_mtu;
int sk;
+ size_t hdrlen;
};
static int linux_setup(void *stv, int sk, const struct param *pp)
/* Check that the address is OK. */
switch (pp->a.sa.sa_family) {
- case AF_INET: break;
- default: errno = EPFNOSUPPORT; return (-1);
+ case AF_INET:
+ st->sol = IPPROTO_IP;
+ st->so_mtu_discover = IP_MTU_DISCOVER;
+ st->so_mtu = IP_MTU;
+ st->hdrlen = 28;
+ break;
+ case AF_INET6:
+ st->sol = IPPROTO_IPV6;
+ st->so_mtu_discover = IPV6_MTU_DISCOVER;
+ st->so_mtu = IPV6_MTU;
+ st->hdrlen = 48;
+ break;
+ default:
+ errno = EPFNOSUPPORT;
+ return (-1);
}
/* Snaffle the UDP socket. */
/* Turn on kernel path-MTU discovery and force DF on. */
i = IP_PMTUDISC_PROBE;
- if (setsockopt(st->sk, IPPROTO_IP, IP_MTU_DISCOVER, &i, sizeof(i)))
+ if (setsockopt(st->sk, st->sol, st->so_mtu_discover, &i, sizeof(i)))
return (-1);
/* Read the initial MTU guess back and report it. */
sz = sizeof(mtu);
- if (getsockopt(st->sk, IPPROTO_IP, IP_MTU, &mtu, &sz))
+ if (getsockopt(st->sk, st->sol, st->so_mtu, &mtu, &sz))
return (-1);
/* Done. */
struct linux_state *st = stv;
/* Write the packet. */
- if (write(st->sk, buf, mtu - 28) >= 0) return (RC_OK);
+ if (write(st->sk, buf, mtu - st->hdrlen) >= 0) return (RC_OK);
else if (errno == EMSGSIZE) return (RC_LOWER);
else return (RC_FAIL);
}
errno == ECONNREFUSED || errno == EHOSTUNREACH)
return (RC_HIGHER);
sz = sizeof(mtu);
- if (getsockopt(st->sk, IPPROTO_IP, IP_MTU, &mtu, &sz))
+ if (getsockopt(st->sk, st->sol, st->so_mtu, &mtu, &sz))
return (RC_FAIL);
return (mtu);
}