+/**
+ * Add or remove UPnP-mapped addresses.
+ *
+ * @param cls the GNUNET_NAT_Handle
+ * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
+ * the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of the address
+ */
+static void
+upnp_add (void *cls, int add_remove, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+ struct LocalAddressList *pos;
+ struct LocalAddressList *next;
+
+ if (GNUNET_YES == add_remove)
+ {
+ add_to_address_list (h, LAL_UPNP, addr, addrlen);
+ return;
+ }
+ /* remove address */
+ next = h->lal_head;
+ while (NULL != (pos = next))
+ {
+ next = pos->next;
+ if ((pos->source != LAL_UPNP) || (pos->addrlen != addrlen) ||
+ (0 != memcmp (&pos[1], addr, addrlen)))
+ continue;
+ GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos);
+ if (NULL != h->address_callback)
+ h->address_callback (h->callback_cls, GNUNET_NO,
+ (const struct sockaddr *) &pos[1], pos->addrlen);
+ GNUNET_free (pos);
+ return; /* only remove once */
+ }
+ /* asked to remove address that does not exist */
+ GNUNET_break (0);
+}
+
+
+/**
+ * Try to add a port mapping using UPnP.
+ *
+ * @param h overall NAT handle
+ * @param port port to map with UPnP
+ */
+static void
+add_minis (struct GNUNET_NAT_Handle *h, uint16_t port)
+{
+ struct MiniList *ml;
+
+ ml = h->mini_head;
+ while (NULL != ml)
+ {
+ if (port == ml->port)
+ return; /* already got this port */
+ ml = ml->next;
+ }
+ ml = GNUNET_malloc (sizeof (struct MiniList));
+ ml->port = port;
+ ml->mini = GNUNET_NAT_mini_map_start (port, h->is_tcp, &upnp_add, h);
+ GNUNET_CONTAINER_DLL_insert (h->mini_head, h->mini_tail, ml);
+}
+
+
+/**
+ * Task to add addresses from original bind to set of valid addrs.
+ *
+ * @param cls the NAT handle
+ * @param tc scheduler context
+ */
+static void
+add_from_bind (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ static struct in6_addr any = IN6ADDR_ANY_INIT;
+ struct GNUNET_NAT_Handle *h = cls;
+ unsigned int i;
+ struct sockaddr *sa;
+ const struct sockaddr_in *v4;
+
+ h->bind_task = GNUNET_SCHEDULER_NO_TASK;
+ for (i = 0; i < h->num_local_addrs; i++)
+ {
+ sa = h->local_addrs[i];
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (sizeof (struct sockaddr_in) != h->local_addrlens[i])
+ {
+ GNUNET_break (0);
+ break;
+ }
+ v4 = (const struct sockaddr_in *) sa;
+ if (0 != v4->sin_addr.s_addr)
+ add_to_address_list (h, LAL_BINDTO_ADDRESS, sa,
+ sizeof (struct sockaddr_in));
+ if (h->enable_upnp)
+ add_minis (h, ntohs (v4->sin_port));
+ break;
+ case AF_INET6:
+ if (sizeof (struct sockaddr_in6) != h->local_addrlens[i])
+ {
+ GNUNET_break (0);
+ break;
+ }
+ if (0 !=
+ memcmp (&((const struct sockaddr_in6 *) sa)->sin6_addr, &any,
+ sizeof (struct in6_addr)))
+ add_to_address_list (h, LAL_BINDTO_ADDRESS, sa,
+ sizeof (struct sockaddr_in6));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+