+// More data was received from TCP connection
+static void managed_handle_pd_data(struct ustream *s, _unused int bytes_new)
+{
+ struct dhcpv6_assignment *c = container_of(s, struct dhcpv6_assignment, managed_sock);
+ time_t now = odhcpd_time();
+ bool first = c->managed_size < 0;
+
+ for (;;) {
+ int pending;
+ char *data = ustream_get_read_buf(s, &pending);
+ char *end = memmem(data, pending, "\n\n", 2);
+
+ if (!end)
+ break;
+
+ end += 2;
+ end[-1] = 0;
+
+ c->managed_size = 0;
+ if (c->accept_reconf)
+ c->reconf_cnt = 1;
+
+ char *saveptr;
+ for (char *line = strtok_r(data, "\n", &saveptr); line; line = strtok_r(NULL, "\n", &saveptr)) {
+ c->managed = realloc(c->managed, (c->managed_size + 1) * sizeof(*c->managed));
+ struct odhcpd_ipaddr *n = &c->managed[c->managed_size];
+
+ char *saveptr2, *x = strtok_r(line, "/", &saveptr2);
+ if (!x || inet_pton(AF_INET6, x, &n->addr) < 1)
+ continue;
+
+ x = strtok_r(NULL, ",", &saveptr2);
+ if (sscanf(x, "%hhu", &n->prefix) < 1)
+ continue;
+
+ x = strtok_r(NULL, ",", &saveptr2);
+ if (sscanf(x, "%u", &n->preferred) < 1)
+ continue;
+
+ x = strtok_r(NULL, ",", &saveptr2);
+ if (sscanf(x, "%u", &n->valid) < 1)
+ continue;
+
+ if (n->preferred > n->valid)
+ continue;
+
+ if (UINT32_MAX - now < n->preferred)
+ n->preferred = UINT32_MAX;
+ else
+ n->preferred += now;
+
+ if (UINT32_MAX - now < n->valid)
+ n->valid = UINT32_MAX;
+ else
+ n->valid += now;
+
+ n->dprefix = 0;
+
+ ++c->managed_size;
+ }
+
+ ustream_consume(s, end - data);
+ }
+
+ if (first && c->managed_size == 0)
+ free_dhcpv6_assignment(c);
+ else if (first)
+ c->valid_until = now + 150;
+}
+
+
+// TCP transmission has ended, either because of success or timeout or other error
+static void managed_handle_pd_done(struct ustream *s)
+{
+ struct dhcpv6_assignment *c = container_of(s, struct dhcpv6_assignment, managed_sock);
+ c->valid_until = odhcpd_time() + 15;
+ c->managed_size = 0;
+ if (c->accept_reconf)
+ c->reconf_cnt = 1;
+}
+
+
+