PRIVATE_EXTERN int RTADVSocketSendSolicitation(RTADVSocketRef sock, bool lladdr_ok) { interface_t * if_p = RTADVSocketGetInterface(sock); boolean_t needs_close = FALSE; int ret; uint32_t txbuf[RTSOL_PACKET_MAX / sizeof(uint32_t)]; int txbuf_used; /* amount actually used */ if (sock->fd_open == FALSE) { /* open the RTADV socket in case it's needed */ if (RTADVSocketOpenSocket(sock) == FALSE) { my_log(LOG_NOTICE, "RTADVSocket: failed to open socket"); return (FALSE); } needs_close = TRUE; } txbuf_used = RTADVSocketInitTXBuf(sock, txbuf, lladdr_ok); ret = IPv6SocketSend(FDCalloutGetFD(S_globals->read_fd), if_link_index(if_p), &sin6_allrouters, (void *)txbuf, txbuf_used, ND_RTADV_HOP_LIMIT); if (needs_close) { RTADVSocketCloseSocket(sock); } return (ret); }
int DHCPv6SocketTransmit(DHCPv6SocketRef sock, DHCPv6PacketRef pkt, int pkt_len) { DHCPv6OptionErrorString err; int ret; boolean_t needs_close = FALSE; if (sock->fd_open == FALSE) { /* open the DHCPv6 socket in case it's needed */ if (DHCPv6SocketOpenSocket(sock) == FALSE) { my_log(LOG_ERR, "DHCPv6Socket: failed to open socket"); return (FALSE); } needs_close = TRUE; } if (S_verbose) { DHCPv6OptionListRef options; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); DHCPv6PacketPrintToString(str, pkt, pkt_len); options = DHCPv6OptionListCreateWithPacket(pkt, pkt_len, &err); if (options == NULL) { my_log_fl(LOG_DEBUG, "parse options failed, %s", err.str); } else { DHCPv6OptionListPrintToString(str, options); DHCPv6OptionListRelease(&options); } my_log(-LOG_DEBUG,"[%s] Transmit %@", if_name(sock->if_p), str); CFRelease(str); } ret = S_send_packet(FDCalloutGetFD(S_globals->read_fd), if_link_index(sock->if_p), pkt, pkt_len); if (needs_close) { DHCPv6SocketCloseSocket(sock); } return (ret); }
static void DHCPv6SocketDelayedClose(void * arg1, void * arg2, void * arg3) { if (S_globals->read_fd == NULL) { my_log(LOG_ERR, "DHCPv6SocketDelayedClose(): socket is already closed"); return; } if (S_globals->read_fd_refcount > 0) { my_log(LOG_ERR, "DHCPv6SocketDelayedClose(): called when socket in use"); return; } my_log(LOG_DEBUG, "DHCPv6SocketDelayedClose(): closing DHCPv6 socket %d", FDCalloutGetFD(S_globals->read_fd)); /* this closes the file descriptor */ FDCalloutRelease(&S_globals->read_fd); return; }
STATIC void RTADVSocketDelayedClose(void * arg1, void * arg2, void * arg3) { if (S_globals->read_fd == NULL) { my_log(LOG_NOTICE, "RTADVSocketDelayedClose(): socket is already closed"); return; } if (S_globals->read_fd_refcount > 0) { my_log(LOG_NOTICE, "RTADVSocketDelayedClose(): called when socket in use"); return; } my_log(LOG_INFO, "RTADVSocketDelayedClose(): closing RTADV socket %d", FDCalloutGetFD(S_globals->read_fd)); /* this closes the file descriptor */ FDCalloutRelease(&S_globals->read_fd); return; }
static void DHCPv6SocketRead(void * arg1, void * arg2) { struct cmsghdr * cm; char cmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct iovec iov; struct sockaddr_in6 from; struct msghdr mhdr; int n; struct in6_pktinfo *pktinfo = NULL; char receive_buf[1500]; /* initialize msghdr for receiving packets */ iov.iov_base = (caddr_t)receive_buf; iov.iov_len = sizeof(receive_buf); mhdr.msg_name = (caddr_t)&from; mhdr.msg_namelen = sizeof(from); mhdr.msg_iov = &iov; mhdr.msg_iovlen = 1; mhdr.msg_control = (caddr_t)cmsgbuf; mhdr.msg_controllen = sizeof(cmsgbuf); /* get message */ n = recvmsg(FDCalloutGetFD(S_globals->read_fd), &mhdr, 0); if (n < 0) { if (errno != EAGAIN) { my_log(LOG_ERR, "DHCPv6SocketRead: recvfrom failed %s (%d)", strerror(errno), errno); } return; } if (n == 0) { /* nothing to read */ return; } /* get the control message that has the interface index */ pktinfo = NULL; for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm != NULL; cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) { if (cm->cmsg_level != IPPROTO_IPV6) { continue; } switch (cm->cmsg_type) { case IPV6_PKTINFO: if (cm->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { continue; } /* ALIGN: CMSG_DATA is should return aligned data */ pktinfo = (struct in6_pktinfo *)(void *)(CMSG_DATA(cm)); break; default: /* this should never occur */ my_log(LOG_ERR, "Why did we get control message type %d?", cm->cmsg_type); break; } } if (pktinfo == NULL) { my_log(LOG_ERR, "DHCPv6SocketRead: missing IPV6_PKTINFO"); return; } DHCPv6SocketDemux(pktinfo->ipi6_ifindex, (const DHCPv6PacketRef)receive_buf, n); return; }
STATIC void RTADVSocketRead(void * arg1, void * arg2) { struct cmsghdr * cm; char cmsgbuf[RECEIVE_CMSG_BUF_SIZE]; int * hop_limit_p; struct icmp6_hdr * icmp_hdr; struct iovec iov; struct sockaddr_in6 from; struct msghdr mhdr; ssize_t n; struct nd_router_advert * ndra_p; char ntopbuf[INET6_ADDRSTRLEN]; struct in6_pktinfo * pktinfo = NULL; char receive_buf[1500]; /* initialize msghdr for receiving packets */ iov.iov_base = (caddr_t)receive_buf; iov.iov_len = sizeof(receive_buf); mhdr.msg_name = (caddr_t)&from; mhdr.msg_namelen = sizeof(from); mhdr.msg_iov = &iov; mhdr.msg_iovlen = 1; mhdr.msg_control = (caddr_t)cmsgbuf; mhdr.msg_controllen = sizeof(cmsgbuf); /* get message */ n = recvmsg(FDCalloutGetFD(S_globals->read_fd), &mhdr, 0); if (n < 0) { if (errno != EAGAIN) { my_log(LOG_ERR, "RTADVSocketRead: recvfrom failed %s (%d)", strerror(errno), errno); } return; } if (n == 0) { /* nothing to read */ return; } if (n < sizeof(struct nd_router_advert)) { my_log(LOG_NOTICE, "RTADVSocketRead: packet size(%d) is too short", n); return; } if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { my_log(LOG_NOTICE, "RTADVSocketRead: RA has non link-local source address %s", inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, sizeof(ntopbuf))); return; } /* process the packet */ pktinfo = NULL; hop_limit_p = NULL; for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm != NULL; cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) { if (cm->cmsg_level != IPPROTO_IPV6) { continue; } switch (cm->cmsg_type) { case IPV6_PKTINFO: if (cm->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { continue; } /* ALIGN: CMSG_DATA returns aligned data, cast ok. */ pktinfo = (struct in6_pktinfo *)(void *)(CMSG_DATA(cm)); break; case IPV6_HOPLIMIT: if (cm->cmsg_len < CMSG_LEN(sizeof(int))) { continue; } /* ALIGN: CMSG_DATA returns aligned data, cast ok. */ hop_limit_p = (int *)(void *)CMSG_DATA(cm); break; default: /* this should never occur */ my_log(LOG_NOTICE, "RTADVSocketRead: why control message type %d?", cm->cmsg_type); break; } } if (pktinfo == NULL) { my_log(LOG_NOTICE, "RTADVSocketRead: missing IPV6_PKTINFO"); return; } if (hop_limit_p == NULL) { my_log(LOG_NOTICE, "RTADVSocketRead: missing IPV6_HOPLIMIT"); return; } ndra_p = (struct nd_router_advert *)receive_buf; icmp_hdr = &ndra_p->nd_ra_hdr; if (icmp_hdr->icmp6_type != ND_ROUTER_ADVERT) { /* this should not happen, the kernel filters for us */ my_log(LOG_NOTICE, "RTADVSocket: received unexpected ND packet type %d", icmp_hdr->icmp6_type); return; } if (icmp_hdr->icmp6_code != 0) { my_log(LOG_NOTICE, "RTADVSocket: invalid icmp code %d", icmp_hdr->icmp6_code); return; } if (ndra_p->nd_ra_router_lifetime == 0) { /* router lifetime is zero, ignore it */ return; } if (*hop_limit_p != ND_RTADV_HOP_LIMIT) { my_log(LOG_NOTICE, "RTADVSocket: invalid RA hop limit %d from %s", *hop_limit_p, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, sizeof(ntopbuf))); return; } RTADVSocketDemux(pktinfo->ipi6_ifindex, &from.sin6_addr, ndra_p, (int)n); return; }