+static void
+mptcp_do_add_addr_opt(struct mptses *mpte, u_char *cp)
+{
+ struct mptcp_add_addr_opt *addr_opt = (struct mptcp_add_addr_opt *)cp;
+
+ if (addr_opt->maddr_len != MPTCP_ADD_ADDR_OPT_LEN_V4 &&
+ addr_opt->maddr_len != MPTCP_ADD_ADDR_OPT_LEN_V6) {
+ os_log_info(mptcp_log_handle, "%s - %lx: Wrong ADD_ADDR length %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ addr_opt->maddr_len);
+
+ return;
+ }
+
+ if (addr_opt->maddr_len == MPTCP_ADD_ADDR_OPT_LEN_V4 &&
+ addr_opt->maddr_ipversion != 4) {
+ os_log_info(mptcp_log_handle, "%s - %lx: ADD_ADDR length for v4 but version is %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ addr_opt->maddr_ipversion);
+
+ return;
+ }
+
+ if (addr_opt->maddr_len == MPTCP_ADD_ADDR_OPT_LEN_V6 &&
+ addr_opt->maddr_ipversion != 6) {
+ os_log_info(mptcp_log_handle, "%s - %lx: ADD_ADDR length for v6 but version is %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ addr_opt->maddr_ipversion);
+
+ return;
+ }
+
+ if (addr_opt->maddr_len == MPTCP_ADD_ADDR_OPT_LEN_V4) {
+ struct sockaddr_in *dst = &mpte->mpte_sub_dst_v4;
+ struct in_addr *addr = &addr_opt->maddr_u.maddr_addrv4;
+ in_addr_t haddr = ntohl(addr->s_addr);
+
+ if (IN_ZERONET(haddr) ||
+ IN_LOOPBACK(haddr) ||
+ IN_LINKLOCAL(haddr) ||
+ IN_DS_LITE(haddr) ||
+ IN_6TO4_RELAY_ANYCAST(haddr) ||
+ IN_MULTICAST(haddr) ||
+ INADDR_BROADCAST == haddr ||
+ IN_PRIVATE(haddr) ||
+ IN_SHARED_ADDRESS_SPACE(haddr)) {
+ os_log_info(mptcp_log_handle, "%s - %lx: ADD_ADDR invalid addr: %x\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ addr->s_addr);
+
+ return;
+ }
+
+ dst->sin_len = sizeof(*dst);
+ dst->sin_family = AF_INET;
+ dst->sin_port = mpte->__mpte_dst_v4.sin_port;
+ dst->sin_addr.s_addr = addr->s_addr;
+ } else {
+ struct sockaddr_in6 *dst = &mpte->mpte_sub_dst_v6;
+ struct in6_addr *addr = &addr_opt->maddr_u.maddr_addrv6;
+
+ if (IN6_IS_ADDR_LINKLOCAL(addr) ||
+ IN6_IS_ADDR_MULTICAST(addr) ||
+ IN6_IS_ADDR_UNSPECIFIED(addr) ||
+ IN6_IS_ADDR_LOOPBACK(addr) ||
+ IN6_IS_ADDR_V4COMPAT(addr) ||
+ IN6_IS_ADDR_V4MAPPED(addr)) {
+ char dbuf[MAX_IPv6_STR_LEN];
+
+ inet_ntop(AF_INET6, &dst->sin6_addr, dbuf, sizeof(dbuf));
+ os_log_info(mptcp_log_handle, "%s - %lx: ADD_ADDRv6 invalid addr: %s\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ dbuf);
+
+ return;
+ }
+
+ dst->sin6_len = sizeof(*dst);
+ dst->sin6_family = AF_INET6;
+ dst->sin6_port = mpte->__mpte_dst_v6.sin6_port;
+ memcpy(&dst->sin6_addr, addr, sizeof(*addr));
+ }
+
+ os_log_info(mptcp_log_handle, "%s - %lx: Received ADD_ADDRv%u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ addr_opt->maddr_ipversion);
+
+ mptcp_sched_create_subflows(mpte);
+}
+