ipadapter.c 46.4 KB
Newer Older
Kishen Maloor's avatar
Kishen Maloor committed
1
/*
2
// Copyright (c) 2018 Intel Corporation
Kishen Maloor's avatar
Kishen Maloor committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

17
#define _GNU_SOURCE
Jaehyun Cho's avatar
Jaehyun Cho committed
18 19 20 21
#include "ipcontext.h"
#ifdef OC_TCP
#include "tcpadapter.h"
#endif
22 23 24
#include "oc_buffer.h"
#include "oc_core_res.h"
#include "oc_endpoint.h"
25
#include "oc_network_monitor.h"
26 27
#include "port/oc_assert.h"
#include "port/oc_connectivity.h"
Kishen Maloor's avatar
Kishen Maloor committed
28 29
#include <arpa/inet.h>
#include <assert.h>
Kishen Maloor's avatar
Kishen Maloor committed
30
#include <errno.h>
Kishen Maloor's avatar
Kishen Maloor committed
31
#include <ifaddrs.h>
32 33
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
Kishen Maloor's avatar
Kishen Maloor committed
34
#include <net/if.h>
Jaehong Jo's avatar
Jaehong Jo committed
35
#include <netdb.h>
Kishen Maloor's avatar
Kishen Maloor committed
36
#include <signal.h>
Kishen Maloor's avatar
Kishen Maloor committed
37 38 39 40 41 42
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/un.h>
#include <unistd.h>
Kishen Maloor's avatar
Kishen Maloor committed
43

44 45 46 47 48 49
/* Some outdated toolchains do not define IFA_FLAGS.
   Note: Requires Linux kernel 3.14 or later. */
#ifndef IFA_FLAGS
#define IFA_FLAGS (IFA_MULTICAST+1)
#endif

50
#define OCF_PORT_UNSECURED (5683)
Kishen Maloor's avatar
Kishen Maloor committed
51 52 53 54 55 56 57 58 59 60
static const uint8_t ALL_OCF_NODES_LL[] = {
  0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58
};
static const uint8_t ALL_OCF_NODES_RL[] = {
  0xff, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58
};
static const uint8_t ALL_OCF_NODES_SL[] = {
  0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58
};
#define ALL_COAP_NODES_V4 0xe00001bb
61

Flavio Ceolin's avatar
Flavio Ceolin committed
62
static pthread_mutex_t mutex;
63 64 65
struct sockaddr_nl ifchange_nl;
int ifchange_sock;
bool ifchange_initialized;
Kishen Maloor's avatar
Kishen Maloor committed
66

67
OC_LIST(ip_contexts);
68
OC_MEMB(ip_context_s, ip_context_t, OC_MAX_NUM_DEVICES);
Kishen Maloor's avatar
Kishen Maloor committed
69

70 71
OC_MEMB(device_eps, oc_endpoint_t, 8 * OC_MAX_NUM_DEVICES); // fix

72
#ifdef OC_NETWORK_MONITOR
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
/**
 * Structure to manage interface list.
 */
typedef struct ip_interface
{
  struct ip_interface *next;
  int if_index;
} ip_interface_t;

OC_LIST(ip_interface_list);
OC_MEMB(ip_interface_s, ip_interface_t, OC_MAX_IP_INTERFACES);

OC_LIST(oc_network_interface_cb_list);
OC_MEMB(oc_network_interface_cb_s, oc_network_interface_cb_t,
        OC_MAX_NETWORK_INTERFACE_CBS);

static ip_interface_t *
get_ip_interface(int target_index)
{
  ip_interface_t *if_item = oc_list_head(ip_interface_list);
  while (if_item != NULL && if_item->if_index != target_index) {
    if_item = if_item->next;
  }
  return if_item;
}

static bool
add_ip_interface(int target_index)
{
  if (get_ip_interface(target_index))
    return false;

  ip_interface_t *new_if = oc_memb_alloc(&ip_interface_s);
  if (!new_if) {
    OC_ERR("interface item alloc failed");
    return false;
  }
  new_if->if_index = target_index;
  oc_list_add(ip_interface_list, new_if);
  OC_DBG("New interface added: %d", new_if->if_index);
  return true;
}

static bool
check_new_ip_interfaces(void)
{
  struct ifaddrs *ifs = NULL, *interface = NULL;
  if (getifaddrs(&ifs) < 0) {
    OC_ERR("querying interface address");
    return false;
  }
  for (interface = ifs; interface != NULL; interface = interface->ifa_next) {
    /* Ignore interfaces that are down and the loopback interface */
    if (!(interface->ifa_flags & IFF_UP) ||
        interface->ifa_flags & IFF_LOOPBACK) {
      continue;
    }
    /* Obtain interface index for this address */
    int if_index = if_nametoindex(interface->ifa_name);

    add_ip_interface(if_index);
  }
  freeifaddrs(ifs);
  return true;
}

static bool
remove_ip_interface(int target_index)
{
  ip_interface_t *if_item = get_ip_interface(target_index);
  if (!if_item) {
    return false;
  }

  oc_list_remove(ip_interface_list, if_item);
  oc_memb_free(&ip_interface_s, if_item);
  OC_DBG("Removed from ip interface list: %d", target_index);
  return true;
}

static void
remove_all_ip_interface(void)
{
  ip_interface_t *if_item = oc_list_head(ip_interface_list), *next;
  while (if_item != NULL) {
    next = if_item->next;
    oc_list_remove(ip_interface_list, if_item);
    oc_memb_free(&ip_interface_s, if_item);
    if_item = next;
  }
}

static void
remove_all_network_interface_cbs(void)
{
  oc_network_interface_cb_t *cb_item =
                              oc_list_head(oc_network_interface_cb_list),
                            *next;
  while (cb_item != NULL) {
    next = cb_item->next;
    oc_list_remove(oc_network_interface_cb_list, cb_item);
    oc_memb_free(&oc_network_interface_cb_s, cb_item);
    cb_item = next;
  }
}
178 179 180 181 182
#endif /* OC_NETWORK_MONITOR */

#ifdef OC_SESSION_EVENTS
OC_LIST(oc_session_event_cb_list);
OC_MEMB(oc_session_event_cb_s, oc_session_event_cb_t, OC_MAX_SESSION_EVENT_CBS);
183 184 185 186 187 188 189 190 191 192 193 194 195 196

static void
remove_all_session_event_cbs(void)
{
  oc_session_event_cb_t *cb_item = oc_list_head(oc_session_event_cb_list),
                        *next;
  while (cb_item != NULL) {
    next = cb_item->next;
    oc_list_remove(oc_session_event_cb_list, cb_item);
    oc_memb_free(&oc_session_event_cb_s, cb_item);
    cb_item = next;
  }
}

197 198
#endif /* OC_SESSION_EVENTS */

Kishen Maloor's avatar
Kishen Maloor committed
199
void
Flavio Ceolin's avatar
Flavio Ceolin committed
200
oc_network_event_handler_mutex_init(void)
Kishen Maloor's avatar
Kishen Maloor committed
201 202
{
  if (pthread_mutex_init(&mutex, NULL) != 0) {
203
    oc_abort("error initializing network event handler mutex");
Kishen Maloor's avatar
Kishen Maloor committed
204 205 206 207
  }
}

void
Flavio Ceolin's avatar
Flavio Ceolin committed
208
oc_network_event_handler_mutex_lock(void)
Kishen Maloor's avatar
Kishen Maloor committed
209 210 211 212 213
{
  pthread_mutex_lock(&mutex);
}

void
Flavio Ceolin's avatar
Flavio Ceolin committed
214
oc_network_event_handler_mutex_unlock(void)
Kishen Maloor's avatar
Kishen Maloor committed
215 216 217 218
{
  pthread_mutex_unlock(&mutex);
}

219 220 221 222
void
oc_network_event_handler_mutex_destroy(void)
{
  ifchange_initialized = false;
223
  close(ifchange_sock);
224
#ifdef OC_NETWORK_MONITOR
225 226
  remove_all_ip_interface();
  remove_all_network_interface_cbs();
227 228
#endif /* OC_NETWORK_MONITOR */
#ifdef OC_SESSION_EVENTS
229
  remove_all_session_event_cbs();
230
#endif /* OC_SESSION_EVENTS */
231 232 233
  pthread_mutex_destroy(&mutex);
}

234
static ip_context_t *
George Nash's avatar
George Nash committed
235
get_ip_context_for_device(size_t device)
236
{
237 238 239 240 241 242 243 244 245 246
  ip_context_t *dev = oc_list_head(ip_contexts);
  while (dev != NULL && dev->device != device) {
    dev = dev->next;
  }
  if (!dev) {
    return NULL;
  }
  return dev;
}

247 248 249 250 251 252 253 254 255 256 257
#ifdef OC_IPV4
static int add_mcast_sock_to_ipv4_mcast_group(int mcast_sock,
                                              const struct in_addr *local,
                                              int interface_index) {
  struct ip_mreqn mreq;

  memset(&mreq, 0, sizeof(mreq));
  mreq.imr_multiaddr.s_addr = htonl(ALL_COAP_NODES_V4);
  mreq.imr_ifindex = interface_index;
  memcpy(&mreq.imr_address, local, sizeof(struct in_addr));

258 259
  (void)setsockopt(mcast_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
                   sizeof(mreq));
260 261 262

  if (setsockopt(mcast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
                 sizeof(mreq)) == -1) {
263
    OC_ERR("joining IPv4 multicast group %d", errno);
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    return -1;
  }

  return 0;
}
#endif /* OC_IPV4 */

static int add_mcast_sock_to_ipv6_mcast_group(int mcast_sock,
                                              int interface_index) {
  struct ipv6_mreq mreq;

  /* Link-local scope */
  memset(&mreq, 0, sizeof(mreq));
  memcpy(mreq.ipv6mr_multiaddr.s6_addr, ALL_OCF_NODES_LL, 16);
  mreq.ipv6mr_interface = interface_index;

280 281
  (void)setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq,
                   sizeof(mreq));
282 283 284

  if (setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
                 sizeof(mreq)) == -1) {
285
    OC_ERR("joining link-local IPv6 multicast group %d", errno);
286 287 288 289 290 291 292 293
    return -1;
  }

  /* Realm-local scope */
  memset(&mreq, 0, sizeof(mreq));
  memcpy(mreq.ipv6mr_multiaddr.s6_addr, ALL_OCF_NODES_RL, 16);
  mreq.ipv6mr_interface = interface_index;

294 295
  (void)setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq,
                   sizeof(mreq));
296 297 298

  if (setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
                 sizeof(mreq)) == -1) {
299
    OC_ERR("joining realm-local IPv6 multicast group %d", errno);
300 301 302 303 304 305 306 307
    return -1;
  }

  /* Site-local scope */
  memset(&mreq, 0, sizeof(mreq));
  memcpy(mreq.ipv6mr_multiaddr.s6_addr, ALL_OCF_NODES_SL, 16);
  mreq.ipv6mr_interface = interface_index;

308 309
  (void)setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq,
                   sizeof(mreq));
310 311 312

  if (setsockopt(mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
                 sizeof(mreq)) == -1) {
313
    OC_ERR("joining site-local IPv6 multicast group %d", errno);
314 315 316 317 318 319 320 321 322 323
    return -1;
  }

  return 0;
}

static int configure_mcast_socket(int mcast_sock, int sa_family) {
  int ret = 0;
  struct ifaddrs *ifs = NULL, *interface = NULL;
  if (getifaddrs(&ifs) < 0) {
324
    OC_ERR("querying interface addrs");
325 326 327 328
    return -1;
  }
  for (interface = ifs; interface != NULL; interface = interface->ifa_next) {
    /* Ignore interfaces that are down and the loopback interface */
329 330
    if (!(interface->ifa_flags & IFF_UP) ||
        interface->ifa_flags & IFF_LOOPBACK) {
331 332 333 334
      continue;
    }
    /* Ignore interfaces not belonging to the address family under consideration
     */
335
    if (interface->ifa_addr && interface->ifa_addr->sa_family != sa_family) {
336 337 338 339 340 341 342
      continue;
    }
    /* Obtain interface index for this address */
    int if_index = if_nametoindex(interface->ifa_name);
    /* Accordingly handle IPv6/IPv4 addresses */
    if (sa_family == AF_INET6) {
      struct sockaddr_in6 *a = (struct sockaddr_in6 *)interface->ifa_addr;
343
      if (a && IN6_IS_ADDR_LINKLOCAL(&a->sin6_addr)) {
344 345 346 347 348 349
        ret += add_mcast_sock_to_ipv6_mcast_group(mcast_sock, if_index);
      }
    }
#ifdef OC_IPV4
    else if (sa_family == AF_INET) {
      struct sockaddr_in *a = (struct sockaddr_in *)interface->ifa_addr;
350 351
      if (a)
        ret += add_mcast_sock_to_ipv4_mcast_group(mcast_sock, &a->sin_addr,
352 353 354 355 356 357 358 359
                                                if_index);
    }
#endif /* OC_IPV4 */
  }
  freeifaddrs(ifs);
  return ret;
}

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
static void
get_interface_addresses(ip_context_t *dev, unsigned char family, uint16_t port,
                        bool secure, bool tcp)
{
  struct
  {
    struct nlmsghdr nlhdr;
    struct ifaddrmsg addrmsg;
  } request;
  struct nlmsghdr *response;

  memset(&request, 0, sizeof(request));
  request.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
  request.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
  request.nlhdr.nlmsg_type = RTM_GETADDR;
  request.addrmsg.ifa_family = family;

  int nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (nl_sock < 0) {
    return;
  }

  if (send(nl_sock, &request, request.nlhdr.nlmsg_len, 0) < 0) {
    close(nl_sock);
    return;
  }

  fd_set rfds;
  FD_ZERO(&rfds);
  FD_SET(nl_sock, &rfds);

  if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) {
    close(nl_sock);
    return;
  }

  int prev_interface_index = -1;
  bool done = false;
  while (!done) {
    int guess = 512, response_len;
    do {
      guess <<= 1;
      uint8_t dummy[guess];
      response_len = recv(nl_sock, dummy, guess, MSG_PEEK);
      if (response_len < 0) {
        close(nl_sock);
        return;
      }
    } while (response_len == guess);

    uint8_t buffer[response_len];
    response_len = recv(nl_sock, buffer, response_len, 0);
    if (response_len < 0) {
      close(nl_sock);
      return;
    }

    response = (struct nlmsghdr *)buffer;
    if (response->nlmsg_type == NLMSG_ERROR) {
      close(nl_sock);
      return;
    }

    while (NLMSG_OK(response, response_len)) {
      if (response->nlmsg_type == NLMSG_DONE) {
        done = true;
        break;
      }
      oc_endpoint_t ep;
      memset(&ep, 0, sizeof(oc_endpoint_t));
      bool include = false;
      struct ifaddrmsg *addrmsg = (struct ifaddrmsg *)NLMSG_DATA(response);
      if (addrmsg->ifa_scope < RT_SCOPE_HOST) {
        if ((int)addrmsg->ifa_index == prev_interface_index) {
          goto next_ifaddr;
        }
        ep.interface_index = addrmsg->ifa_index;
        include = true;
        struct rtattr *attr = (struct rtattr *)IFA_RTA(addrmsg);
        int att_len = IFA_PAYLOAD(response);
        while (RTA_OK(attr, att_len)) {
          if (attr->rta_type == IFA_ADDRESS) {
#ifdef OC_IPV4
            if (family == AF_INET) {
              memcpy(ep.addr.ipv4.address, RTA_DATA(attr), 4);
              ep.flags = IPV4;
            } else
#endif /* OC_IPV4 */
              if (family == AF_INET6) {
              memcpy(ep.addr.ipv6.address, RTA_DATA(attr), 16);
              ep.flags = IPV6;
            }
          } else if (attr->rta_type == IFA_FLAGS) {
            if (*(uint32_t *)(RTA_DATA(attr)) & IFA_F_TEMPORARY) {
              include = false;
            }
          }
          attr = RTA_NEXT(attr, att_len);
        }
      }
      if (include) {
        prev_interface_index = addrmsg->ifa_index;
        if (addrmsg->ifa_scope == RT_SCOPE_LINK && family == AF_INET6) {
          ep.addr.ipv6.scope = addrmsg->ifa_index;
        }
        if (secure) {
          ep.flags |= SECURED;
        }
#ifdef OC_IPV4
        if (family == AF_INET) {
          ep.addr.ipv4.port = port;
        } else
#endif /* OC_IPV4 */
          if (family == AF_INET6) {
          ep.addr.ipv6.port = port;
        }
#ifdef OC_TCP
        if (tcp) {
          ep.flags |= TCP;
        }
#else
        (void)tcp;
#endif /* OC_TCP */
        oc_endpoint_t *new_ep = oc_memb_alloc(&device_eps);
        if (!new_ep) {
          close(nl_sock);
          return;
        }
        memcpy(new_ep, &ep, sizeof(oc_endpoint_t));
        oc_list_add(dev->eps, new_ep);
      }

    next_ifaddr:
      response = NLMSG_NEXT(response, response_len);
    }
  }
  close(nl_sock);
}

static void
free_endpoints_list(ip_context_t *dev)
{
  oc_endpoint_t *ep = oc_list_pop(dev->eps);

  while (ep != NULL) {
    oc_memb_free(&device_eps, ep);
    ep = oc_list_pop(dev->eps);
  }
}

static void
refresh_endpoints_list(ip_context_t *dev)
{
  free_endpoints_list(dev);

  get_interface_addresses(dev, AF_INET6, dev->port, false, false);
#ifdef OC_SECURITY
  get_interface_addresses(dev, AF_INET6, dev->dtls_port, true, false);
#endif /* OC_SECURITY */
#ifdef OC_IPV4
  get_interface_addresses(dev, AF_INET, dev->port4, false, false);
#ifdef OC_SECURITY
  get_interface_addresses(dev, AF_INET, dev->dtls4_port, true, false);
#endif /* OC_SECURITY */
#endif /* OC_IPV4 */

#ifdef OC_TCP
  get_interface_addresses(dev, AF_INET6, dev->tcp.port, false, true);
#ifdef OC_SECURITY
  get_interface_addresses(dev, AF_INET6, dev->tcp.tls_port, true, true);
#endif /* OC_SECURITY */
#ifdef OC_IPV4
  get_interface_addresses(dev, AF_INET, dev->tcp.port4, false, true);
#ifdef OC_SECURITY
  get_interface_addresses(dev, AF_INET, dev->tcp.tls4_port, true, true);
#endif /* OC_SECURITY */
#endif /* OC_IPV4 */
#endif /* OC_TCP */
}

oc_endpoint_t *
George Nash's avatar
George Nash committed
541
oc_connectivity_get_endpoints(size_t device)
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
{
  ip_context_t *dev = get_ip_context_for_device(device);

  if (!dev) {
    return NULL;
  }

  if (oc_list_length(dev->eps) == 0) {
    oc_network_event_handler_mutex_lock();
    refresh_endpoints_list(dev);
    oc_network_event_handler_mutex_unlock();
  }

  return oc_list_head(dev->eps);
}

558 559 560 561 562 563 564 565 566 567 568 569 570 571
/* Called after network interface up/down events.
 * This function reconfigures IPv6/v4 multicast sockets for
 * all logical devices.
 */
static int process_interface_change_event(void) {
  int ret = 0, i, num_devices = oc_core_get_num_devices();
  struct nlmsghdr *response = NULL;

  int guess = 512, response_len;
  do {
    guess <<= 1;
    uint8_t dummy[guess];
    response_len = recv(ifchange_sock, dummy, guess, MSG_PEEK);
    if (response_len < 0) {
572
      OC_ERR("reading payload size from netlink interface");
573 574 575 576 577 578 579
      return -1;
    }
  } while (response_len == guess);

  uint8_t buffer[response_len];
  response_len = recv(ifchange_sock, buffer, response_len, 0);
  if (response_len < 0) {
580
    OC_ERR("reading payload from netlink interface");
581 582 583 584 585
    return -1;
  }

  response = (struct nlmsghdr *)buffer;
  if (response->nlmsg_type == NLMSG_ERROR) {
586
    OC_ERR("caught NLMSG_ERROR in payload from netlink interface");
587 588 589
    return -1;
  }

590 591
  bool if_state_changed = false;

592 593 594 595
  while (NLMSG_OK(response, response_len)) {
    if (response->nlmsg_type == RTM_NEWADDR) {
      struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(response);
      if (ifa) {
596
#ifdef OC_NETWORK_MONITOR
597 598 599
        if (add_ip_interface(ifa->ifa_index)) {
          oc_network_interface_event(NETWORK_INTERFACE_UP);
        }
600
#endif /* OC_NETWORK_MONITOR */
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
        struct rtattr *attr = (struct rtattr *)IFA_RTA(ifa);
        int att_len = IFA_PAYLOAD(response);
        while (RTA_OK(attr, att_len)) {
          if (attr->rta_type == IFA_ADDRESS) {
#ifdef OC_IPV4
            if (ifa->ifa_family == AF_INET) {
              for (i = 0; i < num_devices; i++) {
                ip_context_t *dev = get_ip_context_for_device(i);
                ret += add_mcast_sock_to_ipv4_mcast_group(
                    dev->mcast4_sock, RTA_DATA(attr), ifa->ifa_index);
              }
            } else
#endif /* OC_IPV4 */
                if (ifa->ifa_family == AF_INET6 &&
                    ifa->ifa_scope == RT_SCOPE_LINK) {
              for (i = 0; i < num_devices; i++) {
                ip_context_t *dev = get_ip_context_for_device(i);
                ret += add_mcast_sock_to_ipv6_mcast_group(dev->mcast_sock,
                                                          ifa->ifa_index);
              }
            }
          }
          attr = RTA_NEXT(attr, att_len);
        }
      }
626
      if_state_changed = true;
627 628 629
    } else if (response->nlmsg_type == RTM_DELADDR) {
      struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(response);
      if (ifa) {
630
#ifdef OC_NETWORK_MONITOR
631 632 633
        if (remove_ip_interface(ifa->ifa_index)) {
          oc_network_interface_event(NETWORK_INTERFACE_DOWN);
        }
634
#endif /* OC_NETWORK_MONITOR */
635
      }
636
      if_state_changed = true;
637 638 639 640
    }
    response = NLMSG_NEXT(response, response_len);
  }

641 642 643 644 645 646 647 648 649
  if (if_state_changed) {
    for (i = 0; i < num_devices; i++) {
      ip_context_t *dev = get_ip_context_for_device(i);
      oc_network_event_handler_mutex_lock();
      refresh_endpoints_list(dev);
      oc_network_event_handler_mutex_unlock();
    }
  }

650 651 652
  return ret;
}

653 654 655 656
static int
recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size,
         oc_endpoint_t *endpoint, bool multicast)
{
657
  struct sockaddr_storage client;
658 659 660 661 662
  struct iovec iovec[1];
  struct msghdr msg;
  char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))];

  iovec[0].iov_base = recv_buf;
663
  iovec[0].iov_len = (size_t)recv_buf_size;
664 665 666

  msg.msg_name = &client;
  msg.msg_namelen = sizeof(client);
Kishen Maloor's avatar
Kishen Maloor committed
667

668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
  msg.msg_iov = iovec;
  msg.msg_iovlen = 1;

  msg.msg_control = msg_control;
  msg.msg_controllen = sizeof(msg_control);

  msg.msg_flags = 0;

  int ret = recvmsg(sock, &msg, 0);

  if (ret < 0 || msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
    OC_ERR("recvmsg returned with an error: %d", errno);
    return -1;
  }

  struct cmsghdr *cmsg;
  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != 0; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
      if (msg.msg_namelen != sizeof(struct sockaddr_in6)) {
        OC_ERR("anciliary data contains invalid source address");
        return -1;
      }
      /* Set source address of packet in endpoint structure */
      struct sockaddr_in6 *c6 = (struct sockaddr_in6 *)&client;
      memcpy(endpoint->addr.ipv6.address, c6->sin6_addr.s6_addr,
             sizeof(c6->sin6_addr.s6_addr));
      endpoint->addr.ipv6.scope = c6->sin6_scope_id;
      endpoint->addr.ipv6.port = ntohs(c6->sin6_port);

      /* Set receiving network interface index */
      struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
      endpoint->interface_index = pktinfo->ipi6_ifindex;

      /* For a unicast receiving socket, extract the destination address
       * of the UDP packet into the endpoint's addr_local attribute.
       * This would be used to set the source address of a response that
       * results from this message.
       */
      if (!multicast) {
        memcpy(endpoint->addr_local.ipv6.address, pktinfo->ipi6_addr.s6_addr,
               16);
      } else {
        /* For a multicast receiving socket, check the incoming interface
               * index and save that interface's highest scoped address in the
               * endpoint's addr_local attribute. This would be used as the
         * source
               * address of a multicast response.
               */
        oc_endpoint_t *dst = oc_connectivity_get_endpoints(endpoint->device);
717 718 719
        while (dst != NULL &&
               (dst->interface_index != endpoint->interface_index ||
               !(dst->flags & IPV6))) {
720 721
          dst = dst->next;
        }
722 723 724
        if (dst == NULL) {
          return -1;
        }
725 726 727 728
        memcpy(endpoint->addr_local.ipv6.address, dst->addr.ipv6.address, 16);
      }
      break;
    }
Flavio Ceolin's avatar
Flavio Ceolin committed
729
#ifdef OC_IPV4
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
    else if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
      if (msg.msg_namelen != sizeof(struct sockaddr_in)) {
        OC_ERR("anciliary data contains invalid source address");
        return -1;
      }
      struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
      struct sockaddr_in *c4 = (struct sockaddr_in *)&client;
      memcpy(endpoint->addr.ipv4.address, &c4->sin_addr.s_addr,
             sizeof(c4->sin_addr.s_addr));
      endpoint->addr.ipv4.port = ntohs(c4->sin_port);
      endpoint->interface_index = pktinfo->ipi_ifindex;
      if (!multicast) {
        memcpy(endpoint->addr_local.ipv4.address, &pktinfo->ipi_addr.s_addr, 4);
      } else {
        oc_endpoint_t *dst = oc_connectivity_get_endpoints(endpoint->device);
745 746 747
        while (dst != NULL &&
               (dst->interface_index != endpoint->interface_index ||
               !(dst->flags & IPV4))) {
748 749
          dst = dst->next;
        }
750 751 752
        if (dst == NULL) {
          return -1;
        }
753 754 755 756 757 758 759 760 761
        memcpy(endpoint->addr_local.ipv4.address, dst->addr.ipv4.address, 4);
      }
      break;
    }
#endif /* OC_IPV4 */
  }

  return ret;
}
Flavio Ceolin's avatar
Flavio Ceolin committed
762

763 764
static void
oc_udp_add_socks_to_fd_set(ip_context_t *dev)
765
{
Jaehyun Cho's avatar
Jaehyun Cho committed
766 767
  FD_SET(dev->server_sock, &dev->rfds);
  FD_SET(dev->mcast_sock, &dev->rfds);
Kishen Maloor's avatar
Kishen Maloor committed
768
#ifdef OC_SECURITY
Jaehyun Cho's avatar
Jaehyun Cho committed
769
  FD_SET(dev->secure_sock, &dev->rfds);
770
#endif /* OC_SECURITY */
Kishen Maloor's avatar
Kishen Maloor committed
771

Flavio Ceolin's avatar
Flavio Ceolin committed
772
#ifdef OC_IPV4
Jaehyun Cho's avatar
Jaehyun Cho committed
773 774
  FD_SET(dev->server4_sock, &dev->rfds);
  FD_SET(dev->mcast4_sock, &dev->rfds);
Flavio Ceolin's avatar
Flavio Ceolin committed
775
#ifdef OC_SECURITY
Jaehyun Cho's avatar
Jaehyun Cho committed
776
  FD_SET(dev->secure4_sock, &dev->rfds);
777 778
#endif /* OC_SECURITY */
#endif /* OC_IPV4 */
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
}

static adapter_receive_state_t
oc_udp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message)
{
  if (FD_ISSET(dev->server_sock, fds)) {
    int count = recv_msg(dev->server_sock, message->data, OC_PDU_SIZE,
                         &message->endpoint, false);
    if (count < 0) {
      return ADAPTER_STATUS_ERROR;
    }
    message->length = (size_t)count;
    message->endpoint.flags = IPV6;
    FD_CLR(dev->server_sock, fds);
    return ADAPTER_STATUS_RECEIVE;
  }

  if (FD_ISSET(dev->mcast_sock, fds)) {
    int count = recv_msg(dev->mcast_sock, message->data, OC_PDU_SIZE,
                         &message->endpoint, true);
    if (count < 0) {
      return ADAPTER_STATUS_ERROR;
    }
    message->length = (size_t)count;
    message->endpoint.flags = IPV6 | MULTICAST;
    FD_CLR(dev->mcast_sock, fds);
    return ADAPTER_STATUS_RECEIVE;
  }

#ifdef OC_IPV4
  if (FD_ISSET(dev->server4_sock, fds)) {
    int count = recv_msg(dev->server4_sock, message->data, OC_PDU_SIZE,
                         &message->endpoint, false);
    if (count < 0) {
      return ADAPTER_STATUS_ERROR;
    }
    message->length = (size_t)count;
    message->endpoint.flags = IPV4;
    FD_CLR(dev->server4_sock, fds);
    return ADAPTER_STATUS_RECEIVE;
  }

  if (FD_ISSET(dev->mcast4_sock, fds)) {
    int count = recv_msg(dev->mcast4_sock, message->data, OC_PDU_SIZE,
                         &message->endpoint, true);
    if (count < 0) {
      return ADAPTER_STATUS_ERROR;
    }
    message->length = (size_t)count;
    message->endpoint.flags = IPV4 | MULTICAST;
    FD_CLR(dev->mcast4_sock, fds);
    return ADAPTER_STATUS_RECEIVE;
  }
#endif /* OC_IPV4 */

#ifdef OC_SECURITY
  if (FD_ISSET(dev->secure_sock, fds)) {
    int count = recv_msg(dev->secure_sock, message->data, OC_PDU_SIZE,
                         &message->endpoint, false);
    if (count < 0) {
      return ADAPTER_STATUS_ERROR;
    }
    message->length = (size_t)count;
    message->endpoint.flags = IPV6 | SECURED;
    FD_CLR(dev->secure_sock, fds);
    return ADAPTER_STATUS_RECEIVE;
  }
#ifdef OC_IPV4
  if (FD_ISSET(dev->secure4_sock, fds)) {
    int count = recv_msg(dev->secure4_sock, message->data, OC_PDU_SIZE,
                         &message->endpoint, false);
    if (count < 0) {
      return ADAPTER_STATUS_ERROR;
    }
    message->length = (size_t)count;
    message->endpoint.flags = IPV4 | SECURED;
    FD_CLR(dev->secure4_sock, fds);
    return ADAPTER_STATUS_RECEIVE;
  }
#endif /* OC_IPV4 */
#endif /* OC_SECURITY */

  return ADAPTER_STATUS_NONE;
}

static void *
network_event_thread(void *data)
{
  ip_context_t *dev = (ip_context_t *)data;
Flavio Ceolin's avatar
Flavio Ceolin committed
868

869 870 871 872 873 874 875 876 877 878 879
  fd_set setfds;
  FD_ZERO(&dev->rfds);
  /* Monitor network interface changes on the platform from only the 0th logical
   * device
   */
  if (dev->device == 0) {
    FD_SET(ifchange_sock, &dev->rfds);
  }
  FD_SET(dev->shutdown_pipe[0], &dev->rfds);

  oc_udp_add_socks_to_fd_set(dev);
Jaehyun Cho's avatar
Jaehyun Cho committed
880 881 882 883
#ifdef OC_TCP
  oc_tcp_add_socks_to_fd_set(dev);
#endif /* OC_TCP */

Kishen Maloor's avatar
Kishen Maloor committed
884 885
  int i, n;

886
  while (dev->terminate != 1) {
Jaehyun Cho's avatar
Jaehyun Cho committed
887
    setfds = dev->rfds;
Kishen Maloor's avatar
Kishen Maloor committed
888 889
    n = select(FD_SETSIZE, &setfds, NULL, NULL, NULL);

890 891 892 893 894 895 896 897 898 899 900 901
    if (FD_ISSET(dev->shutdown_pipe[0], &setfds)) {
      char buf;
      // write to pipe shall not block - so read the byte we wrote
      if (read(dev->shutdown_pipe[0], &buf, 1) < 0) {
          // intentionally left blank
      }
    }

    if (dev->terminate) {
      break;
    }

Kishen Maloor's avatar
Kishen Maloor committed
902
    for (i = 0; i < n; i++) {
903 904 905
      if (dev->device == 0) {
        if (FD_ISSET(ifchange_sock, &setfds)) {
          if (process_interface_change_event() < 0) {
906
            OC_WRN("caught errors while handling a network interface change");
907 908 909 910 911 912
          }
          FD_CLR(ifchange_sock, &setfds);
          continue;
        }
      }

Kishen Maloor's avatar
Kishen Maloor committed
913 914 915
      oc_message_t *message = oc_allocate_message();

      if (!message) {
Kishen Maloor's avatar
Kishen Maloor committed
916
        break;
Kishen Maloor's avatar
Kishen Maloor committed
917 918
      }

919 920
      message->endpoint.device = dev->device;

921 922
      if (oc_udp_receive_message(dev, &setfds, message) ==
          ADAPTER_STATUS_RECEIVE) {
Jaehyun Cho's avatar
Jaehyun Cho committed
923
        goto common;
Kishen Maloor's avatar
Kishen Maloor committed
924
      }
Jaehyun Cho's avatar
Jaehyun Cho committed
925
#ifdef OC_TCP
926 927
      if (oc_tcp_receive_message(dev, &setfds, message) ==
          ADAPTER_STATUS_RECEIVE) {
928
        goto common;
Jaehyun Cho's avatar
Jaehyun Cho committed
929 930 931
      }
#endif /* OC_TCP */

932 933 934
      oc_message_unref(message);
      continue;

Kishen Maloor's avatar
Kishen Maloor committed
935
    common:
936 937 938 939 940
#ifdef OC_DEBUG
      PRINT("Incoming message of size %d bytes from ", message->length);
      PRINTipaddr(message->endpoint);
      PRINT("\n\n");
#endif /* OC_DEBUG */
Kishen Maloor's avatar
Kishen Maloor committed
941 942

      oc_network_event(message);
Kishen Maloor's avatar
Kishen Maloor committed
943 944
    }
  }
Kishen Maloor's avatar
Kishen Maloor committed
945
  pthread_exit(NULL);
Kishen Maloor's avatar
Kishen Maloor committed
946 947
}

Inho Oh's avatar
Inho Oh committed
948
static int
949
send_msg(int sock, struct sockaddr_storage *receiver, oc_message_t *message)
950
{
951 952 953
  char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))];
  struct iovec iovec[1];
  struct msghdr msg;
954

955 956 957
  memset(&msg, 0, sizeof(struct msghdr));
  msg.msg_name = (void *)receiver;
  msg.msg_namelen = sizeof(struct sockaddr_storage);
958

959 960
  msg.msg_iov = iovec;
  msg.msg_iovlen = 1;
961

962 963 964
  if (message->endpoint.flags & IPV6) {
    struct cmsghdr *cmsg;
    struct in6_pktinfo *pktinfo;
965

966 967
    msg.msg_control = msg_control;
    msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
968
    memset(msg.msg_control, 0, msg.msg_controllen);
969

970 971 972 973
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = IPPROTO_IPV6;
    cmsg->cmsg_type = IPV6_PKTINFO;
    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
974

975 976
    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
    memset(pktinfo, 0, sizeof(struct in6_pktinfo));
977

978 979 980 981 982 983 984 985 986 987 988
    /* Get the outgoing interface index from message->endpint */
    pktinfo->ipi6_ifindex = message->endpoint.interface_index;
    /* Set the source address of this message using the address
     * from the endpoint's addr_local attribute.
     */
    memcpy(&pktinfo->ipi6_addr, message->endpoint.addr_local.ipv6.address, 16);
  }
#ifdef OC_IPV4
  else if (message->endpoint.flags & IPV4) {
    struct cmsghdr *cmsg;
    struct in_pktinfo *pktinfo;
989

990 991
    msg.msg_control = msg_control;
    msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
992
    memset(msg.msg_control, 0, msg.msg_controllen);
993

994 995 996 997
    cmsg = CMSG_FIRSTHDR(&msg);
    cmsg->cmsg_level = SOL_IP;
    cmsg->cmsg_type = IP_PKTINFO;
    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
998

999 1000
    pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
    memset(pktinfo, 0, sizeof(struct in_pktinfo));
1001

1002 1003 1004
    pktinfo->ipi_ifindex = message->endpoint.interface_index;
    memcpy(&pktinfo->ipi_spec_dst, message->endpoint.addr_local.ipv4.address,
           4);
1005
  }
1006 1007 1008 1009 1010 1011
#else  /* OC_IPV4 */
  else {
    OC_ERR("invalid endpoint");
    return -1;
  }
#endif /* !OC_IPV4 */
1012

1013 1014 1015
  int bytes_sent = 0, x;
  while (bytes_sent < (int)message->length) {
    iovec[0].iov_base = message->data + bytes_sent;
1016
    iovec[0].iov_len = message->length - (size_t)bytes_sent;
1017 1018 1019 1020 1021 1022 1023 1024
    x = sendmsg(sock, &msg, 0);
    if (x < 0) {
      OC_WRN("sendto() returned errno %d", errno);
      break;
    }
    bytes_sent += x;
  }
  OC_DBG("Sent %d bytes", bytes_sent);
Jaehyun Cho's avatar
Jaehyun Cho committed
1025

1026 1027 1028
  if (bytes_sent == 0) {
    return -1;
  }
Jaehyun Cho's avatar
Jaehyun Cho committed
1029

1030
  return bytes_sent;
1031 1032
}

1033 1034 1035
int
oc_send_buffer(oc_message_t *message)
{
1036 1037 1038 1039 1040
#ifdef OC_DEBUG
  PRINT("Outgoing message of size %d bytes to ", message->length);
  PRINTipaddr(message->endpoint);
  PRINT("\n\n");
#endif /* OC_DEBUG */
Kishen Maloor's avatar
Kishen Maloor committed
1041 1042

  struct sockaddr_storage receiver;
1043
  memset(&receiver, 0, sizeof(struct sockaddr_storage));
Flavio Ceolin's avatar
Flavio Ceolin committed
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
#ifdef OC_IPV4
  if (message->endpoint.flags & IPV4) {
    struct sockaddr_in *r = (struct sockaddr_in *)&receiver;
    memcpy(&r->sin_addr.s_addr, message->endpoint.addr.ipv4.address,
           sizeof(r->sin_addr.s_addr));
    r->sin_family = AF_INET;
    r->sin_port = htons(message->endpoint.addr.ipv4.port);
  } else {
#else
  {
#endif
    struct sockaddr_in6 *r = (struct sockaddr_in6 *)&receiver;
    memcpy(r->sin6_addr.s6_addr, message->endpoint.addr.ipv6.address,
           sizeof(r->sin6_addr.s6_addr));
    r->sin6_family = AF_INET6;
    r->sin6_port = htons(message->endpoint.addr.ipv6.port);
    r->sin6_scope_id = message->endpoint.addr.ipv6.scope;
  }
Kishen Maloor's avatar
Kishen Maloor committed
1062
  int send_sock = -1;
Kishen Maloor's avatar
Kishen Maloor committed
1063

1064 1065
  ip_context_t *dev = get_ip_context_for_device(message->endpoint.device);

Jaehyun Cho's avatar
Jaehyun Cho committed
1066 1067
#ifdef OC_TCP
  if (message->endpoint.flags & TCP) {
1068
    return oc_tcp_send_buffer(dev, message, &receiver);
Jaehyun Cho's avatar
Jaehyun Cho committed
1069 1070 1071
  }
#endif /* OC_TCP */

Kishen Maloor's avatar
Kishen Maloor committed
1072
#ifdef OC_SECURITY
Kishen Maloor's avatar
Kishen Maloor committed
1073
  if (message->endpoint.flags & SECURED) {
Flavio Ceolin's avatar
Flavio Ceolin committed
1074
#ifdef OC_IPV4
Kishen Maloor's avatar
Kishen Maloor committed
1075
    if (message->endpoint.flags & IPV4) {
1076
      send_sock = dev->secure4_sock;
Kishen Maloor's avatar
Kishen Maloor committed
1077
    } else {
1078
      send_sock = dev->secure_sock;
Kishen Maloor's avatar
Kishen Maloor committed
1079
    }
1080 1081 1082
#else  /* OC_IPV4 */
    send_sock = dev->secure_sock;
#endif /* !OC_IPV4 */
Kishen Maloor's avatar
Kishen Maloor committed
1083
  } else
Kishen Maloor's avatar
Kishen Maloor committed
1084
#endif /* OC_SECURITY */
Flavio Ceolin's avatar
Flavio Ceolin committed
1085
#ifdef OC_IPV4
Kishen Maloor's avatar
Kishen Maloor committed
1086
    if (message->endpoint.flags & IPV4) {
1087
    send_sock = dev->server4_sock;
Kishen Maloor's avatar
Kishen Maloor committed
1088
  } else {
1089
    send_sock = dev->server_sock;
Kishen Maloor's avatar
Kishen Maloor committed
1090 1091 1092
  }
#else  /* OC_IPV4 */
  {
1093
    send_sock = dev->server_sock;
Kishen Maloor's avatar
Kishen Maloor committed
1094 1095 1096
  }
#endif /* !OC_IPV4 */

1097
  return send_msg(send_sock, &receiver, message);
Kishen Maloor's avatar
Kishen Maloor committed
1098 1099
}

Kishen Maloor's avatar
Kishen Maloor committed
1100
#ifdef OC_CLIENT
Kishen Maloor's avatar
Kishen Maloor committed
1101
void
1102
oc_send_discovery_request(oc_message_t *message)
Kishen Maloor's avatar
Kishen Maloor committed
1103
{
Kishen Maloor's avatar
Kishen Maloor committed
1104 1105
  struct ifaddrs *ifs = NULL, *interface = NULL;
  if (getifaddrs(&ifs) < 0) {
1106
    OC_ERR("querying interfaces: %d", errno);
Kishen Maloor's avatar
Kishen Maloor committed
1107 1108
    goto done;
  }
1109

1110 1111 1112 1113
  memset(&message->endpoint.addr_local, 0,
         sizeof(message->endpoint.addr_local));
  message->endpoint.interface_index = 0;

1114 1115
  ip_context_t *dev = get_ip_context_for_device(message->endpoint.device);

Kishen Maloor's avatar
Kishen Maloor committed
1116
  for (interface = ifs; interface != NULL; interface = interface->ifa_next) {
1117
    if (!(interface->ifa_flags & IFF_UP) || interface->ifa_flags & IFF_LOOPBACK)
Kishen Maloor's avatar
Kishen Maloor committed
1118
      continue;
Flavio Ceolin's avatar
Flavio Ceolin committed
1119 1120
    if (message->endpoint.flags & IPV6 && interface->ifa_addr &&
        interface->ifa_addr->sa_family == AF_INET6) {
Kishen Maloor's avatar
Kishen Maloor committed
1121 1122
      struct sockaddr_in6 *addr = (struct sockaddr_in6 *)interface->ifa_addr;
      if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
1123
        unsigned int mif = if_nametoindex(interface->ifa_name);
1124
        if (setsockopt(dev->server_sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &mif,
Kishen Maloor's avatar
Kishen Maloor committed
1125
                       sizeof(mif)) == -1) {
1126
          OC_ERR("setting socket option for default IPV6_MULTICAST_IF: %d",
1127
                 errno);
Kishen Maloor's avatar
Kishen Maloor committed
1128 1129
          goto done;
        }
1130
        message->endpoint.interface_index = mif;
1131
        message->endpoint.addr.ipv6.scope = mif;
Kishen Maloor's avatar
Kishen Maloor committed
1132
        oc_send_buffer(message);
Kishen Maloor's avatar
Kishen Maloor committed
1133
      }
Flavio Ceolin's avatar
Flavio Ceolin committed
1134 1135 1136 1137
#ifdef OC_IPV4
    } else if (message->endpoint.flags & IPV4 && interface->ifa_addr &&
               interface->ifa_addr->sa_family == AF_INET) {
      struct sockaddr_in *addr = (struct sockaddr_in *)interface->ifa_addr;
1138 1139
      if (setsockopt(dev->server4_sock, IPPROTO_IP, IP_MULTICAST_IF,
                     &addr->sin_addr, sizeof(addr->sin_addr)) == -1) {
1140
        OC_ERR("setting socket option for default IP_MULTICAST_IF: %d",
1141
               errno);
Flavio Ceolin's avatar
Flavio Ceolin committed
1142 1143
        goto done;
      }
1144
      message->endpoint.interface_index = if_nametoindex(interface->ifa_name);
Flavio Ceolin's avatar
Flavio Ceolin committed
1145 1146
      oc_send_buffer(message);
    }
1147
#else  /* OC_IPV4 */
Kishen Maloor's avatar
Kishen Maloor committed
1148
    }
1149
#endif /* !OC_IPV4 */
Kishen Maloor's avatar
Kishen Maloor committed
1150 1151
  }
done:
Kishen Maloor's avatar
Kishen Maloor committed
1152
  freeifaddrs(ifs);
Kishen Maloor's avatar
Kishen Maloor committed
1153
}
Kishen Maloor's avatar
Kishen Maloor committed
1154
#endif /* OC_CLIENT */
Kishen Maloor's avatar
Kishen Maloor committed
1155

1156
#ifdef OC_NETWORK_MONITOR
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
int
oc_add_network_interface_event_callback(interface_event_handler_t cb)
{
  if (!cb)
    return -1;

  oc_network_interface_cb_t *cb_item =
    oc_memb_alloc(&oc_network_interface_cb_s);
  if (!cb_item) {
    OC_ERR("network interface callback item alloc failed");
    return -1;
  }

  cb_item->handler = cb;
  oc_list_add(oc_network_interface_cb_list, cb_item);
  return 0;
}

int
oc_remove_network_interface_event_callback(interface_event_handler_t cb)
{
  if (!cb)
    return -1;

  oc_network_interface_cb_t *cb_item =
    oc_list_head(oc_network_interface_cb_list);
  while (cb_item != NULL && cb_item->handler != cb) {
    cb_item = cb_item->next;
  }
  if (!cb_item) {
    return -1;
  }
  oc_list_remove(oc_network_interface_cb_list, cb_item);

  oc_memb_free(&oc_network_interface_cb_s, cb_item);
  return 0;
}

void
handle_network_interface_event_callback(oc_interface_event_t event)
{
  if (oc_list_length(oc_network_interface_cb_list) > 0) {
    oc_network_interface_cb_t *cb_item =
      oc_list_head(oc_network_interface_cb_list);
    while (cb_item) {
      cb_item->handler(event);
      cb_item = cb_item->next;
    }
  }
}
1207
#endif /* OC_NETWORK_MONITOR */
1208

1209
#ifdef OC_SESSION_EVENTS
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
int
oc_add_session_event_callback(session_event_handler_t cb)
{
  if (!cb)
    return -1;

  oc_session_event_cb_t *cb_item = oc_memb_alloc(&oc_session_event_cb_s);
  if (!cb_item) {
    OC_ERR("session event callback item alloc failed");
    return -1;
  }

  cb_item->handler = cb;
  oc_list_add(oc_session_event_cb_list, cb_item);
  return 0;
}

int
oc_remove_session_event_callback(session_event_handler_t cb)
{
  if (!cb)
    return -1;

  oc_session_event_cb_t *cb_item = oc_list_head(oc_session_event_cb_list);
  while (cb_item != NULL && cb_item->handler != cb) {
    cb_item = cb_item->next;
  }
  if (!cb_item) {
    return -1;
  }
  oc_list_remove(oc_session_event_cb_list, cb_item);

  oc_memb_free(&oc_session_event_cb_s, cb_item);
  return 0;
}

void
handle_session_event_callback(const oc_endpoint_t *endpoint,
                              oc_session_state_t state)
{
  if (oc_list_length(oc_session_event_cb_list) > 0) {
    oc_session_event_cb_t *cb_item = oc_list_head(oc_session_event_cb_list);
    while (cb_item) {
      cb_item->handler(endpoint, state);
      cb_item = cb_item->next;
    }
  }
}
1258
#endif /* OC_SESSION_EVENTS */
1259

Flavio Ceolin's avatar
Flavio Ceolin committed
1260 1261
#ifdef OC_IPV4
static int
1262
connectivity_ipv4_init(ip_context_t *dev)
Flavio Ceolin's avatar
Flavio Ceolin committed
1263
{
1264
  OC_DBG("Initializing IPv4 connectivity for device %d", dev->device);
1265 1266
  memset(&dev->mcast4, 0, sizeof(struct sockaddr_storage));
  memset(&dev->server4, 0, sizeof(struct sockaddr_storage));
Flavio Ceolin's avatar
Flavio Ceolin committed
1267

1268
  struct sockaddr_in *m = (struct sockaddr_in *)&dev->mcast4;
Flavio Ceolin's avatar
Flavio Ceolin committed
1269 1270 1271 1272
  m->sin_family = AF_INET;
  m->sin_port = htons(OCF_PORT_UNSECURED);
  m->sin_addr.s_addr = INADDR_ANY;

1273
  struct sockaddr_in *l = (struct sockaddr_in *)&dev->server4;
Flavio Ceolin's avatar
Flavio Ceolin committed
1274 1275 1276 1277 1278
  l->sin_family = AF_INET;
  l->sin_addr.s_addr = INADDR_ANY;
  l->sin_port = 0;

#ifdef OC_SECURITY
1279 1280
  memset(&dev->secure4, 0, sizeof(struct sockaddr_storage));
  struct sockaddr_in *sm = (struct sockaddr_in *)&dev->secure4;
Flavio Ceolin's avatar
Flavio Ceolin committed
1281
  sm->sin_family = AF_INET;
1282
  sm->sin_port = 0;
Flavio Ceolin's avatar
Flavio Ceolin committed
1283 1284
  sm->sin_addr.s_addr = INADDR_ANY;

1285 1286
  dev->secure4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if (dev->secure4_sock < 0) {
1287
    OC_ERR("creating secure IPv4 socket");
Flavio Ceolin's avatar
Flavio Ceolin committed
1288 1289 1290 1291
    return -1;
  }
#endif /* OC_SECURITY */

1292 1293
  dev->server4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  dev->mcast4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Flavio Ceolin's avatar
Flavio Ceolin committed
1294

1295
  if (dev->server4_sock < 0 || dev->mcast4_sock < 0) {