void *icmp6_listen(void *arg) { uint8_t msg[MAX_PKT_LEN]; struct sockaddr_in6 addr; struct in6_addr *saddr, *daddr; struct in6_pktinfo pkt_info; struct icmp6_hdr *ih; int iif, hoplimit; ssize_t len; int *fd_arg = (int *)arg; int sock_fd = *fd_arg; // struct icmp6_handler *h; while (1) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); len = icmp6_recv(sock_fd, msg, sizeof(msg), &addr, &pkt_info, &hoplimit); /* check if socket has closed */ if (len == -EBADF) break; /* common validity check */ if (len < sizeof(struct icmp6_hdr)) continue; saddr = &addr.sin6_addr; daddr = &pkt_info.ipi6_addr; iif = pkt_info.ipi6_ifindex; ih = (struct icmp6_hdr *)msg; /* multiplex to right handler */ // pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); // pthread_rwlock_rdlock(&handler_lock); /* if ((h = icmp6_handler_get(ih->icmp6_type)) != NULL)*/ if(conf.mode == MAPD_MODE_CLIENT) mapd_client_recv(ih, len, saddr, daddr, iif, hoplimit, sock_fd); else if(conf.mode == MAPD_MODE_SERVER) mapd_server_recv(ih, len, saddr, daddr, iif, hoplimit, sock_fd); // pthread_rwlock_unlock(&handler_lock); } pthread_exit(NULL); }
static void *icmp6_listen(void *arg) { uint8_t msg[MAX_PKT_LEN]; struct sockaddr_in6 addr; struct in6_addr *saddr, *daddr; struct in6_pktinfo pkt_info; struct icmp6_hdr *ih; int iif, hoplimit; ssize_t len; struct icmp6_handler *h; pthread_dbg("thread started"); while (1) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); len = icmp6_recv(icmp6_sock.fd, msg, sizeof(msg), &addr, &pkt_info, &hoplimit); /* check if socket has closed */ if (len == -EBADF) break; /* common validity check */ if (len < sizeof(struct icmp6_hdr)) continue; saddr = &addr.sin6_addr; daddr = &pkt_info.ipi6_addr; iif = pkt_info.ipi6_ifindex; ih = (struct icmp6_hdr *)msg; /* multiplex to right handler */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_rwlock_rdlock(&handler_lock); if ((h = icmp6_handler_get(ih->icmp6_type)) != NULL) h->recv(ih, len, saddr, daddr, iif, hoplimit); pthread_rwlock_unlock(&handler_lock); } pthread_exit(NULL); }
int ndisc_do_dad(int ifi, struct in6_addr *addr, int do_ll) { struct in6_pktinfo pinfo; struct sockaddr_in6 saddr; struct nd_neighbor_advert *hdr; struct icmp6_filter filter; struct in6_addr solicit, ll; unsigned char msg[MAX_PKT_LEN]; int hoplimit, sock = -1, ret, val = 1, err = -1; fd_set rset; struct timeval tv; ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter); sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if (sock < 0) { dbg("socket: %s\n", strerror(errno)); goto end; } if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)) < 0) { dbg("cannot set IPV6_RECVPKTINFO: %s\n", strerror(errno)); goto end; } if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val)) < 0) { dbg("cannot set IPV6_RECVHOPLIMIT: %s\n", strerror(errno)); goto end; } if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(struct icmp6_filter)) < 0) { dbg("cannot set ICMPV6_FILTER: %s\n", strerror(errno)); goto end; } ipv6_addr_solict_mult(addr, &solicit); if (if_mc_group(sock, ifi, &in6addr_all_nodes_mc, IPV6_JOIN_GROUP)) { dbg("cannot join all node mc\n"); goto end; } if (if_mc_group(sock, ifi, &solicit, IPV6_JOIN_GROUP)) { dbg("cannot joing slicit node mc\n"); goto end; } if (ndisc_send_ns(ifi, addr) <= 0) { dbg("Error at sending NS\n"); goto end; } if (do_ll) { ipv6_addr_llocal(addr, &ll); if (ndisc_send_ns(ifi, &ll) <= 0) { dbg("Error at sending NS (link-local target)\n"); goto end; } } FD_ZERO(&rset); FD_SET(sock, &rset); tv.tv_sec = DAD_TIMEOUT; tv.tv_usec = 0; for (;;) { /* Note on portability: we assume that tv is modified to show the time left which is AFAIK true only in Linux timeout */ if (select(sock+1, &rset, NULL, NULL, &tv) == 0) { dbg("Dad success\n"); err = 0; break; } if (!FD_ISSET(sock, &rset)) continue; /* We got an ICMPv6 packet */ ret = icmp6_recv(sock, msg, sizeof(msg), &saddr, &pinfo, &hoplimit); if (ret < 0) continue; hdr = (struct nd_neighbor_advert *)msg; if (hdr->nd_na_code != 0) continue; if (IN6_ARE_ADDR_EQUAL(addr, &hdr->nd_na_target) || (do_ll && IN6_ARE_ADDR_EQUAL(&ll, &hdr->nd_na_target))) { dbg("Failure\n"); break; } } end: if (sock >= 0) close(sock); return err; }