/** * an iterator to handle packet retransmission for a given host association * * @param entry the host association which to handle * @param current_time current time * @return zero on success or negative on failure */ static int hip_handle_retransmission(struct hip_hadb_state *entry, void *current_time) { int err = 0; time_t *now = (time_t *) current_time; if (entry->hip_msg_retrans.buf == NULL || entry->hip_msg_retrans.count == 0) { goto out_err; } /* check if the last transmision was at least RETRANSMIT_WAIT seconds ago */ if (*now - HIP_RETRANSMIT_WAIT > entry->hip_msg_retrans.last_transmit) { if ((entry->hip_msg_retrans.count > 0) && entry->hip_msg_retrans.buf && ((entry->state != HIP_STATE_ESTABLISHED && entry->retrans_state != entry->state) || (entry->update_state != 0 && entry->retrans_state != entry->update_state) || entry->light_update_retrans == 1)) { HIP_DEBUG("state=%d, retrans_state=%d, update_state=%d\n", entry->state, entry->retrans_state, entry->update_state, entry->retrans_state); /* @todo: verify that this works over slow ADSL line */ err = hip_send_pkt(&entry->hip_msg_retrans.saddr, &entry->hip_msg_retrans.daddr, (entry->nat_mode ? hip_get_local_nat_udp_port() : 0), entry->peer_udp_port, entry->hip_msg_retrans.buf, entry, 0); /* Set entry state, if previous state was unassosiated * and type is I1. */ if (!err && hip_get_msg_type(entry->hip_msg_retrans.buf) == HIP_I1 && entry->state == HIP_STATE_UNASSOCIATED) { HIP_DEBUG("Resent I1 succcesfully\n"); entry->state = HIP_STATE_I1_SENT; } entry->hip_msg_retrans.count--; /* set the last transmission time to the current time value */ time(&entry->hip_msg_retrans.last_transmit); } else { if (entry->hip_msg_retrans.buf) { entry->hip_msg_retrans.count = 0; memset(entry->hip_msg_retrans.buf, 0, HIP_MAX_NETWORK_PACKET); } if (entry->state == HIP_STATE_ESTABLISHED) { entry->retrans_state = entry->update_state; } else { entry->retrans_state = entry->state; } } } out_err: return err; }
/* Moved function doxy descriptor to the header file. Lauri 11.03.2008 */ int hip_read_control_msg_all(int socket, struct hip_common *hip_msg, struct in6_addr *saddr, struct in6_addr *daddr, hip_portpair_t *msg_info, int encap_hdr_size, int is_ipv4) { struct sockaddr_storage addr_from, addr_to; struct sockaddr_in *addr_from4 = ((struct sockaddr_in *) &addr_from); struct sockaddr_in6 *addr_from6 = ((struct sockaddr_in6 *) &addr_from); struct cmsghdr *cmsg; struct msghdr msg; union { struct in_pktinfo *pktinfo_in4; struct inet6_pktinfo *pktinfo_in6; } pktinfo; struct iovec iov; char cbuff[CMSG_SPACE(256)]; int err = 0, len; int cmsg_level, cmsg_type; HIP_ASSERT(saddr); HIP_ASSERT(daddr); HIP_DEBUG("hip_read_control_msg_all() invoked.\n"); HIP_IFEL(((len = hip_peek_recv_total_len(socket, encap_hdr_size, HIP_DEFAULT_MSG_TIMEOUT))<= 0), -1, "Bad packet length (%d)\n", len); memset(msg_info, 0, sizeof(hip_portpair_t)); memset(&msg, 0, sizeof(msg)); memset(cbuff, 0, sizeof(cbuff)); memset(&addr_to, 0, sizeof(addr_to)); /* setup message header with control and receive buffers */ msg.msg_name = &addr_from; msg.msg_namelen = sizeof(struct sockaddr_storage); msg.msg_iov = &iov; msg.msg_iovlen = 1; memset(cbuff, 0, sizeof(cbuff)); msg.msg_control = cbuff; msg.msg_controllen = sizeof(cbuff); msg.msg_flags = 0; iov.iov_len = len; iov.iov_base = hip_msg; pktinfo.pktinfo_in4 = NULL; len = recvmsg(socket, &msg, 0); HIP_IFEL((len < 0), -1, "ICMP%s error: errno=%d, %s\n", (is_ipv4 ? "v4" : "v6"), errno, strerror(errno)); cmsg_level = (is_ipv4) ? IPPROTO_IP : IPPROTO_IPV6; cmsg_type = (is_ipv4) ? IP_PKTINFO : IPV6_2292PKTINFO; /* destination address comes from ancillary data passed * with msg due to IPV6_PKTINFO socket option */ for (cmsg=CMSG_FIRSTHDR(&msg); cmsg; cmsg=CMSG_NXTHDR(&msg,cmsg)){ if ((cmsg->cmsg_level == cmsg_level) && (cmsg->cmsg_type == cmsg_type)) { /* The structure is a union, so this fills also the pktinfo_in6 pointer */ pktinfo.pktinfo_in4 = (struct in_pktinfo*)CMSG_DATA(cmsg); break; } } /* If this fails, change IPV6_2292PKTINFO to IPV6_PKTINFO in hip_init_raw_sock_v6 */ HIP_IFEL(!pktinfo.pktinfo_in4, -1, "Could not determine dst addr, dropping\n"); /* UDP port numbers */ if (is_ipv4 && encap_hdr_size == HIP_UDP_ZERO_BYTES_LEN) { HIP_DEBUG("hip_read_control_msg_all() source port = %d\n", ntohs(addr_from4->sin_port)); msg_info->src_port = ntohs(addr_from4->sin_port); /* Destination port is known from the bound socket. */ msg_info->dst_port = hip_get_local_nat_udp_port(); } /* IPv4 addresses */ if (is_ipv4) { struct sockaddr_in *addr_to4 = (struct sockaddr_in *) &addr_to; IPV4_TO_IPV6_MAP(&addr_from4->sin_addr, saddr); IPV4_TO_IPV6_MAP(&pktinfo.pktinfo_in4->ipi_addr, daddr); addr_to4->sin_family = AF_INET; addr_to4->sin_addr = pktinfo.pktinfo_in4->ipi_addr; addr_to4->sin_port = msg_info->dst_port; } else /* IPv6 addresses */ { struct sockaddr_in6 *addr_to6 = (struct sockaddr_in6 *) &addr_to; memcpy(saddr, &addr_from6->sin6_addr, sizeof(struct in6_addr)); memcpy(daddr, &pktinfo.pktinfo_in6->ipi6_addr, sizeof(struct in6_addr)); addr_to6->sin6_family = AF_INET6; ipv6_addr_copy(&addr_to6->sin6_addr, daddr); } //added by santtu if (hip_read_control_msg_plugin_handler(hip_msg,len, saddr,msg_info->src_port)) goto out_err; //endadd if (is_ipv4 && (encap_hdr_size == IPV4_HDR_SIZE)) {/* raw IPv4, !UDP */ /* For some reason, the IPv4 header is always included. Let's remove it here. */ memmove(hip_msg, ((char *)hip_msg) + IPV4_HDR_SIZE, HIP_MAX_PACKET - IPV4_HDR_SIZE); } else if (is_ipv4 && encap_hdr_size == HIP_UDP_ZERO_BYTES_LEN) { /* remove 32-bits of zeroes between UDP and HIP headers */ memmove(hip_msg, ((char *)hip_msg) + HIP_UDP_ZERO_BYTES_LEN, HIP_MAX_PACKET - HIP_UDP_ZERO_BYTES_LEN); } HIP_IFEL(hip_verify_network_header(hip_msg, (struct sockaddr *) &addr_from, (struct sockaddr *) &addr_to, len - encap_hdr_size), -1, "verifying network header failed\n"); if (saddr) HIP_DEBUG_IN6ADDR("src", saddr); if (daddr) HIP_DEBUG_IN6ADDR("dst", daddr); out_err: return err; }