dhcp6_startdiscover(ifp);
}
-static struct ipv6_addr *
-dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix,
- const struct if_sla *sla, struct interface *ifs)
+static struct dhcp6_state *
+dhcp6_getstate(struct interface *ifp)
{
- struct in6_addr addr;
struct dhcp6_state *state;
- struct ipv6_addr *a, *ap;
- char iabuf[INET6_ADDRSTRLEN];
- const char *ia;
-
- if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
- sla->sla, &addr, sla->prefix_len) == -1)
- {
- syslog(LOG_ERR, "%s: invalid prefix", ifp->name);
- return NULL;
- }
state = D6_STATE(ifp);
if (state == NULL) {
state->state = DH6S_DELEGATED;
state->reason = "DELEGATED6";
}
+ return state;
+}
+
+static struct ipv6_addr *
+dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix,
+ const struct if_sla *sla, struct interface *ifs)
+{
+ struct in6_addr addr;
+ struct dhcp6_state *state;
+ struct ipv6_addr *a, *ap;
+ char iabuf[INET6_ADDRSTRLEN];
+ const char *ia;
+
+ if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
+ sla->sla, &addr, sla->prefix_len) == -1)
+ {
+ ia = inet_ntop(AF_INET6, &prefix->prefix.s6_addr,
+ iabuf, sizeof(iabuf));
+ syslog(LOG_ERR, "%s: invalid prefix %s/%d + %d/%d: %m",
+ ifp->name, ia, prefix->prefix_len,
+ sla->sla, sla->prefix_len);
+ return NULL;
+ }
+
+ state = dhcp6_getstate(ifp);
+ if (state == NULL)
+ return NULL;
a = calloc(1, sizeof(*a));
if (a == NULL) {
return a;
}
+static uint32_t
+dhcp6_findsla(void)
+{
+ uint32_t sla;
+ const struct interface *ifp;
+ const struct dhcp6_state *state;
+
+ /* Slow, but finding the lowest free SLA is needed if we get a
+ * /62 or /63 prefix from upstream */
+ for (sla = 0; sla < UINT32_MAX; sla++) {
+ TAILQ_FOREACH(ifp, ifaces, next) {
+ state = D6_CSTATE(ifp);
+ if (state && state->sla_set && state->sla == sla)
+ break;
+ }
+ if (ifp == NULL)
+ return sla;
+ }
+
+ errno = E2BIG;
+ return 0;
+}
+
static void
dhcp6_delegate_prefix(struct interface *ifp)
{
struct ipv6_addr *ap;
size_t i, j, k;
struct if_iaid *iaid;
- struct if_sla *sla;
+ struct if_sla *sla, asla;
struct interface *ifd;
uint8_t carrier_warned;
+ asla.prefix_len = 64;
ifo = ifp->options;
state = D6_STATE(ifp);
TAILQ_FOREACH(ifd, ifaces, next) {
if (memcmp(iaid->iaid, ap->iaid,
sizeof(iaid->iaid)))
continue;
+ if (iaid->sla_len == 0) {
+ /* no SLA configured, so lets
+ * automate it */
+ if (ifp == ifd)
+ continue;
+ ifd_state = dhcp6_getstate(ifd);
+ if (ifd_state == NULL)
+ return;
+ if (!ifd_state->sla_set) {
+ errno = 0;
+ ifd_state->sla =
+ dhcp6_findsla();
+ if (errno) {
+ syslog(LOG_ERR,
+ "%s: dhcp6_find_sla:"
+ " %m", ifd->name);
+ continue;
+ }
+ syslog(LOG_DEBUG,
+ "%s: set SLA %d",
+ ifd->name, ifd_state->sla);
+ ifd_state->sla_set = 1;
+ }
+ asla.sla = ifd_state->sla;
+ if (ifd->carrier == LINK_DOWN) {
+ syslog(LOG_DEBUG,
+ "%s: has no carrier, cannot"
+ " delegate addresses",
+ ifd->name);
+ carrier_warned = 1;
+ break;
+ }
+ if (dhcp6_delegate_addr(ifd, ap,
+ &asla, ifp))
+ k++;
+ }
for (j = 0; j < iaid->sla_len; j++) {
sla = &iaid->sla[j];
if (strcmp(ifd->name, sla->ifname))
If
.Ar hostname
is a FQDN (ie, contains a .) then it will be encoded as such.
-.It Ic ia_na Ar iaid
+.It Ic ia_na Op Ar iaid
Request a DHCPv6 Normal Address for
.Ar iaid .
If none is specified, a default
is used.
If the interface name is 4 characters or less then that is used,
otherwise the interface index is used.
-.It Ic ia_ta Ar iaid
+.It Ic ia_ta Op Ar iaid
Request a DHCPv6 Temporary Address for
.Ar iaid .
-.It Ic ia_pd Ar iaid Op Ar interface / Ar sla_id Op / Ar prefix_len
+.It Ic ia_pd Op Ar iaid Op Ar interface / Ar sla_id Op / Ar prefix_len
Request a DHCPv6 Delegated Prefix for
.Ar iaid .
-If an
+If no
+.Ar interface
+is given then we will assign a prefix to every other interface with a unique
+.Ar sla_id
+for each, starting from 0.
+Otherwise addresses are only assigned for each
.Ar interface
and
.Ar sla_id
-is given,
-then an address is also assigned to that
-.Ar interface .
A default
.Ar prefix_len
-of 64 is assumed if not given.
+of 64 is assumed.
.Ar sla_id
is an integer and is added to the prefix which must fit inside
.Ar prefix_len
less the length of the delegated prefix.
+You can specify multiple
+.Ar interface /
+.Ar sla_id /
+.Ar prefix_len
+per
+.Ic ia_pd ,
+space separated.
IPv6RS should be disabled globally when requesting a Prefix Delegation like so:
.Pp
.D1 noipv6rs
int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int);
int ipv6_mask(struct in6_addr *, int);
int ipv6_prefixlen(const struct in6_addr *);
-int ipv6_userprefix( const struct in6_addr *, int prefix_len,
- uint64_t user_number, struct in6_addr *result, int result_len);
+int ipv6_userprefix( const struct in6_addr *, short prefix_len,
+ uint64_t user_number, struct in6_addr *result, short result_len);
int ipv6_addaddr(struct ipv6_addr *);
ssize_t ipv6_addaddrs(struct ipv6_addrhead *);
void ipv6_handleifa(int, struct if_head *,