예제 #1
0
/**
 * 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;
}
예제 #2
0
파일: message.c 프로젝트: surki/hipl
/* 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;
}