Merge lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl

Proposed by David Martin
Status: Merged
Merged at revision: 6206
Proposed branch: lp:~martin-lp/hipl/hipl_retransmissions
Merge into: lp:hipl
Diff against target: 650 lines (+249/-84)
9 files modified
hipd/hadb.c (+15/-6)
hipd/init.c (+31/-6)
hipd/input.c (+119/-5)
hipd/input.h (+6/-0)
hipd/maintenance.c (+39/-45)
hipd/netdev.c (+8/-5)
hipd/output.c (+13/-12)
lib/core/state.h (+7/-4)
modules/update/hipd/update.c (+11/-1)
To merge this branch: bzr merge lp:~martin-lp/hipl/hipl_retransmissions
Reviewer Review Type Date Requested Status
Diego Biurrun Abstain
Miika Komu Approve
Review via email: mp+87072@code.launchpad.net

This proposal supersedes a proposal from 2011-12-20.

Description of the change

Update:
Remarks on the code have been addressed in revisions 6224ff.

Previous description:
This branch fixes and improves the currently partially broken retransmissions in HIPL.

In short:
- buffer up to three retransmissions in simple round-robin style
 -> this does not affect regular management packets during BEX but makes it possible to retransmit the locators of the second UPDATE packet

- we remove buffered retransmission based on incoming packets from the peer
 -> hip_update_retransmissions() in input.c takes care of that
 -> for example an incoming R1 invalidates or acknowledges our buffered I1 retransmission
 -> it's the same for UPDATE packets. incoming U2 invalidates buffered U1, and U3 invalidates U2 respectively
 -> the rationale: if we do not get a response from the peer we can assume our or their packet was lost, so we retransmit. A received packet from the peer acts as acknowledgment and we remove the retransmissions. For this reason R2 and U3 packets do not get buffered for retransmission. Their retransmission is triggered by the peers retransmission of I2 or U2 respectively.

I have relatively thoroughly tested this and in the normal use case (no relay, opportunistic or what else we offer in special use cases) it works fine. Would be great if someone had a look at the other cases.

How to test these changes:
- decrease retransmission timeout define HIP_RETRANSMIT_WAIT in hipd.h (retransmission waiting time is still awfully long at the moment but out of scope of this branch to be changed)

- modify the packet loss defines in output.c (thanks Miika for the hint!)
 -> if it does not compile cast the random() call to uint64_t

To post a comment you must log in.
Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

Seems good to me from the view point of functionality. May I ask few questions though:

1. Did you test that memory is deallocated (valgrind) - optional, but extra good karma if you do this :)
2. Does the scheme ignore retransmission of R1 messages (not really supposed to be resent)
3. Why to buffer to three messages?

Regarding to buffering, the state may change during retransmission and this causes the implementation to resend old messages in addition to new ones? If we're lucky, the peer will ignore UPDATE packets with old SPI numbers. However, the situation may be different in the BEX because there's no state.

A special (and supported) use case from base exchange: try to trigger the BEX simultaneously from both sides (i.e. break point both sides with gdb just after sending I1). I know the state machine can handle this but what happens to the retransmissions?

review: Needs Information
Revision history for this message
Diego Biurrun (diego-biurrun) wrote : Posted in a previous version of this proposal
Download full text (7.2 KiB)

 review needs-fixing

On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
> David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
>
> --- hipd/hadb.c 2011-11-17 11:15:47 +0000
> +++ hipd/hadb.c 2011-12-20 11:41:33 +0000
> @@ -693,17 +693,25 @@
> }
>
> - entry->hip_msg_retrans.count = 0;
>
> /* Initialize module states */

You should remove an excess empty line here.

> --- hipd/input.c 2011-12-09 09:32:56 +0000
> +++ hipd/input.c 2011-12-20 11:41:33 +0000
> @@ -1877,3 +1873,117 @@
> +
> +/**
> + * Clear the given retransmission.
> + * i.e. set the remaining retransmissions to zero and zero the buffer.
> + *
> + * @param retrans The retransmission to be cleared.
> + */
> +void hip_clear_retransmission(struct hip_msg_retrans *const retrans)
> +{
> + if (!retrans) {
> + return;
> + }
> +
> + retrans->count = 0;
> + if (retrans->buf) {
> + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);

sizeof(retrans->buf) does not work?

> +/**
> + * Update our buffered retransmissions after receiving the given packet.
> + * This functions removes invalid retransmissions after a state change caused
> + * by a received packet. For example after successfully receiving and handling
> + * an I2 or R2 packet all our buffered packets are dropped.
> + *
> + * Call this function after successful handling of the incoming packet.
> + *
> + * @param packet_type The packet type of the control message (RFC 5201, 5.3.)
> + * @param ha_state The host association state (RFC 5201, 4.4.1.)
> + * @param ctx The packet context of the incoming transmission.
> + *
> + * @return always 0
> + */

Why always return 0?

> +int hip_update_retransmissions(UNUSED const uint8_t packet_type,
> + UNUSED const enum hip_state ha_state,
> + struct hip_packet_context *const ctx)
> +{
> + struct hip_msg_retrans *retrans;
> +
> + HIP_ASSERT(ctx);
> + HIP_ASSERT(ctx->input_msg);
> +
> + /* When receiving an I1 there usually is no established state yet. */
> + if (!ctx->hadb_entry) {
> + return 0;
> + }
> +
> + for (unsigned int i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
> + retrans = &ctx->hadb_entry->hip_msg_retrans[i];
> +
> + if (retrans->count == 0) {
> + continue;
> + }
> +
> + switch (hip_get_msg_type(ctx->input_msg)) {
> + case HIP_I1:
> + switch (hip_get_msg_type(retrans->buf)) {
> + case HIP_I1:
> + /* We only remove our sent I1s when we have got a greater HIT
> + * than the peer (ref. RFC 5201, 4.4.2). */
> + if (hip_hit_is_bigger(&ctx->hadb_entry->hit_our, &ctx->hadb_entry->hit_peer)) {
> + hip_clear_retransmission(retrans);
> + }
> + break;
> + }
> + break;

This nested switch statement for only one case looks pretty weird IMO.

> --- hipd/maintenance.c 2011-12-16 13:37:33 +0000
> +++ hipd/maintenance.c 2011-12-20 11:41:33 +0000
> @@ -92,53 +93,48 @@
> static int handle_retransmission(struct hip_hadb_state *entry,
> ...

Read more...

review: Needs Fixing
Revision history for this message
David Martin (martin-lp) wrote : Posted in a previous version of this proposal

Hi,

On Tue, Dec 20, 2011 at 6:50 PM, Miika Komu <email address hidden> wrote:
> Review: Needs Information
>
> 1. Did you test that memory is deallocated (valgrind) - optional, but extra good karma if you do this :)

Actually I did and it looks fine. There are only HIP_RETRANSMIT_QUEUE_SIZE - 1 more calls to calloc compared to before so there is not that much to go wrong. Static memory ftw.

> 2. Does the scheme ignore retransmission of R1 messages (not really supposed to be resent)

R1s don't get buffered (hip_send_r1() sets the retransmit flag to zero when sending the packet) so they are not retransmitted as well. I did not touch this or to answer your question: yes, they are ignored.

What I did change though is R2 and U3. They are now not retransmitted anymore as they don't get explicitly acknowledged. A retransmission is basically triggered by the peer when they send I2 / U2 again.

> 3. Why to buffer to three messages?

It's more than one to retransmit the locators during UPDATEs. And three is more or less arbitrarily chosen by me. Two did not seem worth the effort of looping through it and four seems not needed? How many locators are common when using HIPL? On my test setup it's always only two... This can easily be changed by changing HIP_RETRANSMIT_QUEUE_SIZE though.

> Regarding to buffering, the state may change during retransmission and this causes the implementation to resend old messages in addition to new ones? If we're lucky, the peer will ignore UPDATE packets with old SPI numbers. However, the situation may be different in the BEX because there's no state.

I'm not sure whether I fully get your question. You mean for example when you trigger three UPDATEs in a row you would have three retransmissions? Once one of the UPDATEs has been processed the peer would ignore the older retransmissions (check_update_freshness() would fail) and on our side the buffered retransmissions would be removed after receiving the U2 from the peer.

Can you trigger another BEX during BEX? Can I force hipd to send another I1 when I'm in state R1_SENT for example? I did not test this.

In general the behaviour during BEX is basically unchanged though in this branch. When a I2, R1, R2, CLOSE or CLOSE_ACK comes in from the peer we remove all our retransmissions. On the host side a retransmission does not cause a state change. Retransmissions are simply putting a packet again on the wire, not more.

> A special (and supported) use case from base exchange: try to trigger the BEX simultaneously from both sides (i.e. break point both sides with gdb just after sending I1). I know the state machine can handle this but what happens to the retransmissions?

Actually I did try this and when I let two machines ping each other virtually at the same time the BEX sort of gets stuck and neither side can get any traffic through (this is not specific to this branch as it is the same on trunk).

In theory this situation is dealt with though. When receiving an I1 the host with the greater HIT removes its own I1 retransmissions.

Revision history for this message
Diego Biurrun (diego-biurrun) wrote : Posted in a previous version of this proposal

On Wed, Dec 21, 2011 at 11:32:26AM +0100, Diego Biurrun wrote:
> On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
> > David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
> >
> > --- hipd/output.c 2011-11-10 10:53:21 +0000
> > +++ hipd/output.c 2011-12-20 11:41:33 +0000
> > @@ -1118,22 +1118,25 @@
> > const struct hip_common *msg,
> > struct hip_hadb_state *entry)
> > {
> > - int len = hip_get_msg_total_len(msg);
> > + int len = hip_get_msg_total_len(msg);
> > + struct hip_msg_retrans *retrans;
> >
> > if (!entry) {
> > return 0;
> > }
> >
> > + retrans = &entry->hip_msg_retrans[entry->next_retrans_slot];
> > +
> > /* Not reusing the old entry as the new packet may have different length */
> > + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
>
> see above
>
> > + memcpy(retrans->buf, msg, len);
> > + memcpy(&retrans->saddr, src_addr, sizeof(struct in6_addr));
> > + memcpy(&retrans->daddr, peer_addr, sizeof(struct in6_addr));

The comment I intended to add here was that this looks as if it can be
done by assignments instead of memcpy.

Diego

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

Hi,

On 22/12/11 00:22, Diego Biurrun wrote:
> On Wed, Dec 21, 2011 at 11:32:26AM +0100, Diego Biurrun wrote:
>> On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
>>> David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
>>>
>>> --- hipd/output.c 2011-11-10 10:53:21 +0000
>>> +++ hipd/output.c 2011-12-20 11:41:33 +0000
>>> @@ -1118,22 +1118,25 @@
>>> const struct hip_common *msg,
>>> struct hip_hadb_state *entry)
>>> {
>>> - int len = hip_get_msg_total_len(msg);
>>> + int len = hip_get_msg_total_len(msg);
>>> + struct hip_msg_retrans *retrans;
>>>
>>> if (!entry) {
>>> return 0;
>>> }
>>>
>>> + retrans =&entry->hip_msg_retrans[entry->next_retrans_slot];
>>> +
>>> /* Not reusing the old entry as the new packet may have different length */
>>> + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
>>
>> see above
>>
>>> + memcpy(retrans->buf, msg, len);
>>> + memcpy(&retrans->saddr, src_addr, sizeof(struct in6_addr));
>>> + memcpy(&retrans->daddr, peer_addr, sizeof(struct in6_addr));
>
> The comment I intended to add here was that this looks as if it can be
> done by assignments instead of memcpy.

if you refer to IPv6 addresses, they have to be copied (no such thing as
128-bit integer). Anyway, the most elegant way is to use
ipv6_addr_copy() instead of memcpy().

Revision history for this message
David Martin (martin-lp) wrote : Posted in a previous version of this proposal
Download full text (8.6 KiB)

Hi,

On Wed, Dec 21, 2011 at 11:32 AM, Diego Biurrun <email address hidden> wrote:
> review needs-fixing
>
> On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
>> David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
>>
>> --- hipd/hadb.c 2011-11-17 11:15:47 +0000
>> +++ hipd/hadb.c 2011-12-20 11:41:33 +0000
>> @@ -693,17 +693,25 @@
>> }
>>
>> - entry->hip_msg_retrans.count = 0;
>>
>> /* Initialize module states */
>
> You should remove an excess empty line here.

fixed.

>> --- hipd/input.c 2011-12-09 09:32:56 +0000
>> +++ hipd/input.c 2011-12-20 11:41:33 +0000
>> @@ -1877,3 +1873,117 @@
>> +
>> +/**
>> + * Clear the given retransmission.
>> + * i.e. set the remaining retransmissions to zero and zero the buffer.
>> + *
>> + * @param retrans The retransmission to be cleared.
>> + */
>> +void hip_clear_retransmission(struct hip_msg_retrans *const retrans)
>> +{
>> + if (!retrans) {
>> + return;
>> + }
>> +
>> + retrans->count = 0;
>> + if (retrans->buf) {
>> + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
>
> sizeof(retrans->buf) does not work?

Nope. It's just a pointer so that would not make much sense. But even referencing the struct does not seem right:

debug(hipd/input.c:1891@hip_clear_retransmission): HIP_MAX_NETWORK_PACKET: 2048
debug(hipd/input.c:1892@hip_clear_retransmission): sizeof(retrans->buf): 8
debug(hipd/input.c:1893@hip_clear_retransmission): sizeof(*retrans->buf): 40

>> +/**
>> + * Update our buffered retransmissions after receiving the given packet.
>> + * This functions removes invalid retransmissions after a state change caused
>> + * by a received packet. For example after successfully receiving and handling
>> + * an I2 or R2 packet all our buffered packets are dropped.
>> + *
>> + * Call this function after successful handling of the incoming packet.
>> + *
>> + * @param packet_type The packet type of the control message (RFC 5201, 5.3.)
>> + * @param ha_state The host association state (RFC 5201, 4.4.1.)
>> + * @param ctx The packet context of the incoming transmission.
>> + *
>> + * @return always 0
>> + */
>
> Why always return 0?

Nothing unforeseen may happen that I deem important enough to break the handling of packets. I would make it void but the handle functions have to return an int.

>> +int hip_update_retransmissions(UNUSED const uint8_t packet_type,
>> + UNUSED const enum hip_state ha_state,
>> + struct hip_packet_context *const ctx)
>> +{
>> + struct hip_msg_retrans *retrans;
>> +
>> + HIP_ASSERT(ctx);
>> + HIP_ASSERT(ctx->input_msg);
>> +
>> + /* When receiving an I1 there usually is no established state yet. */
>> + if (!ctx->hadb_entry) {
>> + return 0;
>> + }
>> +
>> + for (unsigned int i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
>> + retrans = &ctx->hadb_entry->hip_msg_retrans[i];
>> +
>> + if (retrans->count == 0) {
>> + continue;
>> + }
>> +
>> + switch (hip_get_msg_type(ctx->input_msg)) {
>> + case HIP_I1:
>> + switch (hip_get_msg_type...

Read more...

Revision history for this message
David Martin (martin-lp) wrote : Posted in a previous version of this proposal

Hi,

On Thu, Dec 22, 2011 at 8:42 AM, Miika Komu <email address hidden> wrote:
> On 22/12/11 00:22, Diego Biurrun wrote:
>>
>> On Wed, Dec 21, 2011 at 11:32:26AM +0100, Diego Biurrun wrote:
>>>
>>> On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
>>>>
>>>> David Martin has proposed merging
>>>> lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
>>>>
>>>> --- hipd/output.c 2011-11-10 10:53:21 +0000
>>>> +++ hipd/output.c 2011-12-20 11:41:33 +0000
>>>> @@ -1118,22 +1118,25 @@
>>>> const struct hip_common *msg,
>>>> struct hip_hadb_state *entry)
>>>> {
>>>> - int len = hip_get_msg_total_len(msg);
>>>> + int len = hip_get_msg_total_len(msg);
>>>> + struct hip_msg_retrans *retrans;
>>>>
>>>> if (!entry) {
>>>> return 0;
>>>> }
>>>>
>>>> + retrans =&entry->hip_msg_retrans[entry->next_retrans_slot];
>>>>
>>>> +
>>>> /* Not reusing the old entry as the new packet may have different
>>>> length */
>>>> + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
>>>
>>>
>>> see above
>>>
>>>> + memcpy(retrans->buf, msg, len);
>>>> + memcpy(&retrans->saddr, src_addr, sizeof(struct in6_addr));
>>>> + memcpy(&retrans->daddr, peer_addr, sizeof(struct in6_addr));
>>
>>
>> The comment I intended to add here was that this looks as if it can be
>> done by assignments instead of memcpy.
>
>
> if you refer to IPv6 addresses, they have to be copied (no such thing as
> 128-bit integer). Anyway, the most elegant way is to use ipv6_addr_copy()
> instead of memcpy().

I don't think you can assign the buffer as they are independent. The retrans buffer slots are allocated at startup and the message comes wherever the caller allocates it from.

I've removed the needless variable indirection of the int len though and replaced the address memcpy() calls with ipv6_addr_copy().

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal
Download full text (4.1 KiB)

Hi,

On 21/12/11 12:46, David Martin wrote:
> Hi,
>
> On Tue, Dec 20, 2011 at 6:50 PM, Miika Komu<email address hidden> wrote:
>> Review: Needs Information
>>
>> 1. Did you test that memory is deallocated (valgrind) - optional,
>> but extra good karma if you do this :)
>
> Actually I did and it looks fine. There are only
> HIP_RETRANSMIT_QUEUE_SIZE - 1 more calls to calloc compared to before
> so there is not that much to go wrong. Static memory ftw.
>
>> 2. Does the scheme ignore retransmission of R1 messages (not really
>> supposed to be resent)
>
> R1s don't get buffered (hip_send_r1() sets the retransmit flag to
> zero when sending the packet) so they are not retransmitted as well.
> I did not touch this or to answer your question: yes, they are
> ignored.
>
> What I did change though is R2 and U3. They are now not retransmitted
> anymore as they don't get explicitly acknowledged. A retransmission
> is basically triggered by the peer when they send I2 / U2 again.
>
>
>> 3. Why to buffer to three messages?
>
> It's more than one to retransmit the locators during UPDATEs. And
> three is more or less arbitrarily chosen by me. Two did not seem
> worth the effort of looping through it and four seems not needed? How
> many locators are common when using HIPL? On my test setup it's
> always only two... This can easily be changed by changing
> HIP_RETRANSMIT_QUEUE_SIZE though.

maybe I failed to understand something or should dig into the code
better. Are you saying that a buffered packet is a) retransmitted three
times or b) three packets can be queued?

Option a) makes sense, option b) doesn't make sense because the
retransmitted packets are identical (in most cases, see below).

>> Regarding to buffering, the state may change during retransmission
>> and this causes the implementation to resend old messages in
>> addition to new ones? If we're lucky, the peer will ignore UPDATE
>> packets with old SPI numbers. However, the situation may be
>> different in the BEX because there's no state.
>
> I'm not sure whether I fully get your question. You mean for example
> when you trigger three UPDATEs in a row you would have three
> retransmissions? Once one of the UPDATEs has been processed the peer
> would ignore the older retransmissions (check_update_freshness()
> would fail) and on our side the buffered retransmissions would be
> removed after receiving the U2 from the peer.

Regarding to option b), the packets can be different e.g. with UPDATEs.
It occurs that a host obtains new locators every now and then. If the
host has a queue of length of more than two, then it keeps sending an
old buffered set of locators in addition to the new set. While this is
not a big issue, it's completely unnecessary and should be avoided IMHO.
The easiest way to avoid this is to have queue of size one.

> Can you trigger another BEX during BEX? Can I force hipd to send
> another I1 when I'm in state R1_SENT for example? I did not test
> this.

No.

> In general the behaviour during BEX is basically unchanged though in
> this branch. When a I2, R1, R2, CLOSE or CLOSE_ACK comes in from the
> peer we remove all our retransmissions. On the host side a
> retransmissi...

Read more...

Revision history for this message
Diego Biurrun (diego-biurrun) wrote : Posted in a previous version of this proposal
Download full text (5.9 KiB)

On Thu, Dec 22, 2011 at 10:05:21AM +0000, David Martin wrote:
> On Wed, Dec 21, 2011 at 11:32 AM, Diego Biurrun <email address hidden> wrote:
> > On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
> >> David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
> >>
> >> --- hipd/input.c 2011-12-09 09:32:56 +0000
> >> +++ hipd/input.c 2011-12-20 11:41:33 +0000
> >> @@ -1877,3 +1873,117 @@
> >> +
> >> +/**
> >> + * Clear the given retransmission.
> >> + * i.e. set the remaining retransmissions to zero and zero the buffer.
> >> + *
> >> + * @param retrans The retransmission to be cleared.
> >> + */
> >> +void hip_clear_retransmission(struct hip_msg_retrans *const retrans)
> >> +{
> >> + if (!retrans) {
> >> + return;
> >> + }
> >> +
> >> + retrans->count = 0;
> >> + if (retrans->buf) {
> >> + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
> >
> > sizeof(retrans->buf) does not work?
>
> Nope. It's just a pointer so that would not make much sense.

Sorry, sizeof(*retrans->buf) of course, I make this mistake all the time :-/

> But even referencing the struct does not seem right:
>
> debug(hipd/input.c:1891@hip_clear_retransmission): HIP_MAX_NETWORK_PACKET: 2048
> debug(hipd/input.c:1892@hip_clear_retransmission): sizeof(retrans->buf): 8
> debug(hipd/input.c:1893@hip_clear_retransmission): sizeof(*retrans->buf): 40

buf is a pointer to struct hip_common, which is

  struct hip_common {
      uint8_t payload_proto;
      uint8_t payload_len;
      uint8_t type_hdr;
      uint8_t ver_res;
      uint16_t checksum;
      uint16_t control;
      struct in6_addr hits; /**< Sender HIT */
      struct in6_addr hitr; /**< Receiver HIT */
  } __attribute__((packed));

so I guess the 40 bytes is about right.

So why 2048? It looks as though you are zeroing way beyond the field
you intend to initialize ...

> >> +/**
> >> + * Update our buffered retransmissions after receiving the given packet.
> >> + * This functions removes invalid retransmissions after a state change caused
> >> + * by a received packet. For example after successfully receiving and handling
> >> + * an I2 or R2 packet all our buffered packets are dropped.
> >> + *
> >> + * Call this function after successful handling of the incoming packet.
> >> + *
> >> + * @param packet_type The packet type of the control message (RFC 5201, 5.3.)
> >> + * @param ha_state The host association state (RFC 5201, 4.4.1.)
> >> + * @param ctx The packet context of the incoming transmission.
> >> + *
> >> + * @return always 0
> >> + */
> >
> > Why always return 0?
>
> Nothing unforeseen may happen that I deem important enough to break
> the handling of packets. I would make it void but the handle functions
> have to return an int.

OK, a short comment explaining this would be nice.

> >> --- hipd/maintenance.c 2011-12-16 13:37:33 +0000
> >> +++ hipd/maintenance.c 2011-12-20 11:41:33 +0000
> >> @@ -92,53 +93,48 @@
> >> static int handle_retransmission(struct hip_hadb_state *entry,
> >> void *current_time)
> >> {
> >> + ...

Read more...

Revision history for this message
David Martin (martin-lp) wrote : Posted in a previous version of this proposal
Download full text (3.5 KiB)

Hi,

On Thu, Dec 22, 2011 at 1:31 PM, Diego Biurrun <email address hidden> wrote:
> On Thu, Dec 22, 2011 at 10:05:21AM +0000, David Martin wrote:
>> On Wed, Dec 21, 2011 at 11:32 AM, Diego Biurrun <email address hidden> wrote:
>> > On Tue, Dec 20, 2011 at 11:43:26AM +0000, David Martin wrote:
>> >> David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
>> >>
>> >> --- hipd/input.c 2011-12-09 09:32:56 +0000
>> >> +++ hipd/input.c 2011-12-20 11:41:33 +0000
>> >> @@ -1877,3 +1873,117 @@
>> >> +
>> >> +/**
>> >> + * Clear the given retransmission.
>> >> + * i.e. set the remaining retransmissions to zero and zero the buffer.
>> >> + *
>> >> + * @param retrans The retransmission to be cleared.
>> >> + */
>> >> +void hip_clear_retransmission(struct hip_msg_retrans *const retrans)
>> >> +{
>> >> + if (!retrans) {
>> >> + return;
>> >> + }
>> >> +
>> >> + retrans->count = 0;
>> >> + if (retrans->buf) {
>> >> + memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
>> >
>> > sizeof(retrans->buf) does not work?
>>
>> Nope. It's just a pointer so that would not make much sense.
>
> Sorry, sizeof(*retrans->buf) of course, I make this mistake all the time :-/
>
>> But even referencing the struct does not seem right:
>>
>> debug(hipd/input.c:1891@hip_clear_retransmission): HIP_MAX_NETWORK_PACKET: 2048
>> debug(hipd/input.c:1892@hip_clear_retransmission): sizeof(retrans->buf): 8
>> debug(hipd/input.c:1893@hip_clear_retransmission): sizeof(*retrans->buf): 40
>
> buf is a pointer to struct hip_common, which is
>
> struct hip_common {
> uint8_t payload_proto;
> uint8_t payload_len;
> uint8_t type_hdr;
> uint8_t ver_res;
> uint16_t checksum;
> uint16_t control;
> struct in6_addr hits; /**< Sender HIT */
> struct in6_addr hitr; /**< Receiver HIT */
> } __attribute__((packed));
>
> so I guess the 40 bytes is about right.
>
> So why 2048? It looks as though you are zeroing way beyond the field
> you intend to initialize ...

You are right and wrong. 40 bytes is wrong as this would only be the size of the message header. You have to keep in mind that there's payload as well. You are right as 2048 is the maximum size and a sort of pessimistic approach. I've changed it so that it zeros only the actual message size. The queuing function uses hip_get_msg_total_len() to determine how many bytes to copy into the buffer. I'm using the same now to determine how many bytes to zero. They are the only two functions actually changing the buffer so this is good now.

>> >> +/**
>> >> + * Update our buffered retransmissions after receiving the given packet.
>> >> + * This functions removes invalid retransmissions after a state change caused
>> >> + * by a received packet. For example after successfully receiving and handling
>> >> + * an I2 or R2 packet all our buffered packets are dropped.
>> >> + *
>> >> + * Call this function after successful handling of the incoming packet.
>> >> + *
>> >> + * @param packet_type The packet type of the control message (RFC 5201, 5.3.)
>> >> + * @param ha_state The host association sta...

Read more...

Revision history for this message
David Martin (martin-lp) wrote : Posted in a previous version of this proposal
Download full text (3.7 KiB)

Hi,

On Thu, Dec 22, 2011 at 11:45 AM, Miika Komu <email address hidden> wrote:
> On 21/12/11 12:46, David Martin wrote:
>> On Tue, Dec 20, 2011 at 6:50 PM, Miika Komu<email address hidden> wrote:

>>> 3. Why to buffer to three messages?
>>
>>
>> It's more than one to retransmit the locators during UPDATEs. And
>> three is more or less arbitrarily chosen by me. Two did not seem
>> worth the effort of looping through it and four seems not needed? How
>> many locators are common when using HIPL? On my test setup it's
>> always only two... This can easily be changed by changing
>> HIP_RETRANSMIT_QUEUE_SIZE though.
>
>
> maybe I failed to understand something or should dig into the code better.
> Are you saying that a buffered packet is a) retransmitted three times or b)
> three packets can be queued?
>
> Option a) makes sense, option b) doesn't make sense because the
> retransmitted packets are identical (in most cases, see below).

We are doing option b) in this branch. Well, are they identical? The destination of the buffered U2 packets differ because of the locators so this is not true, no?

>>> Regarding to buffering, the state may change during retransmission
>>> and this causes the implementation to resend old messages in
>>> addition to new ones? If we're lucky, the peer will ignore UPDATE
>>> packets with old SPI numbers. However, the situation may be
>>> different in the BEX because there's no state.
>>
>>
>> I'm not sure whether I fully get your question. You mean for example
>> when you trigger three UPDATEs in a row you would have three
>> retransmissions? Once one of the UPDATEs has been processed the peer
>> would ignore the older retransmissions (check_update_freshness()
>> would fail) and on our side the buffered retransmissions would be
>> removed after receiving the U2 from the peer.
>
>
> Regarding to option b), the packets can be different e.g. with UPDATEs. It
> occurs that a host obtains new locators every now and then. If the host has
> a queue of length of more than two, then it keeps sending an old buffered
> set of locators in addition to the new set. While this is not a big issue,
> it's completely unnecessary and should be avoided IMHO. The easiest way to
> avoid this is to have queue of size one.

Setting the queue to size to one would completely defeat its point though. How often does such a locator change happen? I guess in theory it may happen that an UPDATE is triggered and lost, the host obtains a new locator and another UPDATE is triggered which is lost again. Then you would actually retransmit both UPDATEs with different locators.
A solution may be to remove older buffered U1 packets when a new UPDATE is triggered. I may change that if necessary or desired.

>> Can you trigger another BEX during BEX? Can I force hipd to send
>> another I1 when I'm in state R1_SENT for example? I did not test
>> this.
>
>
> No.

Ok, so we do not have a problem here.

>>> A special (and supported) use case from base exchange: try to
>>> trigger the BEX simultaneously from both sides (i.e. break point
>>> both sides with gdb just after sending I1). I know the state
>>> machine can handle this but what happens to the retransmissions?
>>...

Read more...

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal
Download full text (4.4 KiB)

Hi,

On 12/29/2011 01:01 PM, David Martin wrote:
> Hi,
>
> On Thu, Dec 22, 2011 at 11:45 AM, Miika Komu<email address hidden>
> wrote:
>> On 21/12/11 12:46, David Martin wrote:
>>> On Tue, Dec 20, 2011 at 6:50 PM, Miika Komu<email address hidden>
>>> wrote:
>
>>>> 3. Why to buffer to three messages?
>>>
>>>
>>> It's more than one to retransmit the locators during UPDATEs.
>>> And three is more or less arbitrarily chosen by me. Two did not
>>> seem worth the effort of looping through it and four seems not
>>> needed? How many locators are common when using HIPL? On my test
>>> setup it's always only two... This can easily be changed by
>>> changing HIP_RETRANSMIT_QUEUE_SIZE though.
>>
>>
>> maybe I failed to understand something or should dig into the code
>> better. Are you saying that a buffered packet is a) retransmitted
>> three times or b) three packets can be queued?
>>
>> Option a) makes sense, option b) doesn't make sense because the
>> retransmitted packets are identical (in most cases, see below).
>
> We are doing option b) in this branch. Well, are they identical? The
> destination of the buffered U2 packets differ because of the locators
> so this is not true, no?

the retransmitted packages are different only in exceptional
circumstances. Similarly, the destination is usually the same because
there is one retransmission queue per host association - right?

Note: the destination can actually change with the shotgun extension
because it sends an UPDATE to all known peer addresses.

>>>> Regarding to buffering, the state may change during
>>>> retransmission and this causes the implementation to resend old
>>>> messages in addition to new ones? If we're lucky, the peer will
>>>> ignore UPDATE packets with old SPI numbers. However, the
>>>> situation may be different in the BEX because there's no
>>>> state.
>>>
>>>
>>> I'm not sure whether I fully get your question. You mean for
>>> example when you trigger three UPDATEs in a row you would have
>>> three retransmissions? Once one of the UPDATEs has been processed
>>> the peer would ignore the older retransmissions
>>> (check_update_freshness() would fail) and on our side the
>>> buffered retransmissions would be removed after receiving the U2
>>> from the peer.
>>
>>
>> Regarding to option b), the packets can be different e.g. with
>> UPDATEs. It occurs that a host obtains new locators every now and
>> then. If the host has a queue of length of more than two, then it
>> keeps sending an old buffered set of locators in addition to the
>> new set. While this is not a big issue, it's completely unnecessary
>> and should be avoided IMHO. The easiest way to avoid this is to
>> have queue of size one.
>
> Setting the queue to size to one would completely defeat its point
> though.

What is the point of having a queue size of more than one actually? Or
is that that the buffer size determines the number of retransmissions?

> How often does such a locator change happen?

Seldom by default because hipd reacts to locator changes with an
intended delay to accumulate the changes.

> I guess in
> theory it may happen that an UPDATE is triggered and lost, the host
> obtains a new locator and another UPDA...

Read more...

Revision history for this message
David Martin (martin-lp) wrote :
Download full text (5.2 KiB)

Hey,

On Thu, Dec 29, 2011 at 12:29 PM, Miika Komu <email address hidden> wrote:
> On 12/29/2011 01:01 PM, David Martin wrote:
>> On Thu, Dec 22, 2011 at 11:45 AM, Miika Komu<email address hidden>
>>> On 21/12/11 12:46, David Martin wrote:
>>>> On Tue, Dec 20, 2011 at 6:50 PM, Miika Komu<email address hidden>

>>>>> 3. Why to buffer to three messages?
>>>>
>>>> It's more than one to retransmit the locators during UPDATEs.
>>>> And three is more or less arbitrarily chosen by me. Two did not
>>>> seem worth the effort of looping through it and four seems not
>>>> needed? How many locators are common when using HIPL? On my test
>>>> setup it's always only two... This can easily be changed by
>>>> changing HIP_RETRANSMIT_QUEUE_SIZE though.
>>>
>>> maybe I failed to understand something or should dig into the code
>>> better. Are you saying that a buffered packet is a) retransmitted
>>> three times or b) three packets can be queued?
>>>
>>> Option a) makes sense, option b) doesn't make sense because the
>>> retransmitted packets are identical (in most cases, see below).
>>
>>
>> We are doing option b) in this branch. Well, are they identical? The
>> destination of the buffered U2 packets differ because of the locators
>> so this is not true, no?
>
> the retransmitted packages are different only in exceptional
> circumstances. Similarly, the destination is usually the same because
> there is one retransmission queue per host association - right?

I'm not sure whether we are talking at cross-purposes right now. :) In principle it's quite simple:
Yes, retransmissions are handled on a per host association basis. At the moment in trunk we have got a single maximum message sized buffer for each host association. When we send a message (which is supposed to be retransmitted when it does not reach its destination) it gets copied to this buffer. Every subsequent message gets copied into the same buffer overwriting the previous one. This is fine for BEX as packets are send on their own and we do not care about previous ones. As far as I understand it it is different for UPDATEs. The first UPDATE packet has got a list of locators. The second UPDATE packet from the peer is send to all of these locators. In the case we send to 3 locators, the first and second transmission would never be retransmitted as they get overwritten by the subsequent ones.

Now what this branch does is instead of having at max a single message per HA buffered we now can buffer up to three (set by a #define and open for discussion which value is best) messages per HA. This means that in case of the second UPDATE packet all transmissions to the different locators are retransmitted and not just the last one. This change for UPDATE retransmissions is the real benefit of increasing the queue size. It does not make a difference for normal BEX.

> Note: the destination can actually change with the shotgun extension because
> it sends an UPDATE to all known peer addresses.

If I see it right in hip_send_pkt() in output.c all packets get transmitted to all known addresses when the shotgun extension is used. This would benefit of a greater queue size as well then as then all packets to the different addresses...

Read more...

Revision history for this message
Miika Komu (miika-iki) wrote :

Thanks, I understood now. Good work!

review: Approve
Revision history for this message
Diego Biurrun (diego-biurrun) wrote :
Download full text (3.3 KiB)

 review abstain

I leave the decision to Miika, who still had some concerns.
Below are some minor issues I noticed; at least the typo
should be addressed before merging.

On Thu, Dec 29, 2011 at 11:15:31AM +0000, David Martin wrote:
> David Martin has proposed merging lp:~martin-lp/hipl/hipl_retransmissions into lp:hipl.
>
> Requested reviews:
> Diego Biurrun (diego-biurrun)
> Miika Komu (miika-iki)
>
> --- hipd/input.c 2011-12-09 09:32:56 +0000
> +++ hipd/input.c 2011-12-29 11:14:24 +0000
> @@ -1877,3 +1873,121 @@
>
> +/**
> + * Update our buffered retransmissions after receiving the given packet.
> + * This functions removes invalid retransmissions after a state change caused
> + * by a received packet. For example after successfully receiving and handling
> + * an I2 or R2 packet all our buffered packets are dropped.
> + *
> + * Call this function after successful handling of the incoming packet.
> + *
> + * @param packet_type The packet type of the control message (RFC 5201, 5.3.)
> + * @param ha_state The host association state (RFC 5201, 4.4.1.)
> + * @param ctx The packet context of the incoming transmission.
> + *
> + * @return Always 0. Nothing onforeseen may happen here which is important

_u_nforeseen

> --- hipd/maintenance.c 2011-12-21 10:54:26 +0000
> +++ hipd/maintenance.c 2011-12-29 11:14:24 +0000
> @@ -89,55 +90,50 @@
> +static int handle_retransmissions(struct hip_hadb_state *entry,
> + void *current_time)
> {
> +
> + for (i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
> + retrans = &entry->hip_msg_retrans[(entry->next_retrans_slot + i) %
> + HIP_RETRANSMIT_QUEUE_SIZE];
> +
> + /* check if the last transmission was at least RETRANSMIT_WAIT seconds ago */
> + if (*now - HIP_RETRANSMIT_WAIT > retrans->last_transmit) {
> + if (retrans->count > 0) {
> + /* @todo: verify that this works over slow ADSL line */
> + if (hip_send_pkt(&retrans->saddr,
> + &retrans->daddr,
> + entry->nat_mode ? hip_get_local_nat_udp_port() : 0,
> + entry->peer_udp_port,
> + retrans->buf,
> + entry, 0) < 0) {
> + HIP_ERROR("Failed to retransmit packet of type %d.\n",
> + hip_get_msg_type(retrans->buf));
> + err = -1;
> + }
> +
> + /* Set entry state, if previous state was unassociated
> + * and type is I1. */
> + if (!err && hip_get_msg_type(retrans->buf) == HIP_I1 &&
> + entry->state == HIP_STATE_UNASSOCIATED) {
> + HIP_DEBUG("Resent I1 succcesfully\n");
> + entry->state = HIP_STATE_I1_SENT;
> + }

Instead of testing err you could move this into the previous if-block.
That would read more natural to me.

> + retrans->count--;
> + time(&retrans->last_transmit);
> } else {
> + if (hip_get_m...

Read more...

review: Abstain
6234. By David Martin

Fix typo in hip_update_retransmissions() doxygen documentation.

6235. By David Martin

Make if-conditions in handle_retransmissions() more reasonable.

Do not check for the err value twice and use else if when there is only
a single if condition in the else case.

Revision history for this message
David Martin (martin-lp) wrote :

I've fixed the two issues mentioned by Diego in revisions 6234f. Should I start another review or is it good as is?

Revision history for this message
Miika Komu (miika-iki) wrote :

In my opinion, go ahead and merge.

Revision history for this message
David Martin (martin-lp) wrote :

Ok, done.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hipd/hadb.c'
2--- hipd/hadb.c 2011-12-28 15:52:14 +0000
3+++ hipd/hadb.c 2011-12-29 15:06:25 +0000
4@@ -693,17 +693,24 @@
5 get_random_bytes(&entry->spi_inbound_current,
6 sizeof(entry->spi_inbound_current));
7
8- if (!(entry->hip_msg_retrans.buf = calloc(1, HIP_MAX_NETWORK_PACKET))) {
9- return -ENOMEM;
10+ entry->next_retrans_slot = 0;
11+ for (unsigned int i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
12+ if (!(entry->hip_msg_retrans[i].buf = calloc(1, HIP_MAX_NETWORK_PACKET))) {
13+ for (unsigned int j = 0; j < i; j++) {
14+ free(entry->hip_msg_retrans[j].buf);
15+ }
16+ return -ENOMEM;
17+ }
18+ entry->hip_msg_retrans[i].count = 0;
19 }
20
21- entry->hip_msg_retrans.count = 0;
22-
23 /* Initialize module states */
24 entry->hip_modular_state = lmod_init_state();
25 if (entry->hip_modular_state == NULL) {
26 HIP_ERROR("Failed to initialize modular state.\n");
27- free(entry->hip_msg_retrans.buf);
28+ for (unsigned int i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
29+ free(entry->hip_msg_retrans[i].buf);
30+ }
31 return -1;
32 }
33 lmod_init_state_items(entry->hip_modular_state);
34@@ -823,7 +830,9 @@
35 /* Delete SAs */
36
37 free(ha->dh_shared_key);
38- free(ha->hip_msg_retrans.buf);
39+ for (i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
40+ free(ha->hip_msg_retrans[i].buf);
41+ }
42 if (ha->peer_pub) {
43 switch (hip_get_host_id_algo(ha->peer_pub)) {
44 case HIP_HI_RSA:
45
46=== modified file 'hipd/init.c'
47--- hipd/init.c 2011-12-12 14:30:43 +0000
48+++ hipd/init.c 2011-12-29 15:06:25 +0000
49@@ -561,31 +561,40 @@
50
51 hip_register_handle_function(HIP_I1, HIP_STATE_UNASSOCIATED, &hip_check_i1, 20000);
52 hip_register_handle_function(HIP_I1, HIP_STATE_UNASSOCIATED, &hip_handle_i1, 30000);
53+ hip_register_handle_function(HIP_I1, HIP_STATE_UNASSOCIATED, &hip_update_retransmissions, 35000);
54 hip_register_handle_function(HIP_I1, HIP_STATE_UNASSOCIATED, &hip_send_r1, 40000);
55 hip_register_handle_function(HIP_I1, HIP_STATE_I1_SENT, &hip_check_i1, 20000);
56 hip_register_handle_function(HIP_I1, HIP_STATE_I1_SENT, &hip_handle_i1, 30000);
57+ hip_register_handle_function(HIP_I1, HIP_STATE_I1_SENT, &hip_update_retransmissions, 35000);
58 hip_register_handle_function(HIP_I1, HIP_STATE_I1_SENT, &hip_send_r1, 40000);
59 hip_register_handle_function(HIP_I1, HIP_STATE_I2_SENT, &hip_check_i1, 20000);
60 hip_register_handle_function(HIP_I1, HIP_STATE_I2_SENT, &hip_handle_i1, 30000);
61+ hip_register_handle_function(HIP_I1, HIP_STATE_I2_SENT, &hip_update_retransmissions, 35000);
62 hip_register_handle_function(HIP_I1, HIP_STATE_I2_SENT, &hip_send_r1, 40000);
63 hip_register_handle_function(HIP_I1, HIP_STATE_R2_SENT, &hip_check_i1, 20000);
64 hip_register_handle_function(HIP_I1, HIP_STATE_R2_SENT, &hip_handle_i1, 30000);
65+ hip_register_handle_function(HIP_I1, HIP_STATE_R2_SENT, &hip_update_retransmissions, 35000);
66 hip_register_handle_function(HIP_I1, HIP_STATE_R2_SENT, &hip_send_r1, 40000);
67 hip_register_handle_function(HIP_I1, HIP_STATE_ESTABLISHED, &hip_check_i1, 20000);
68 hip_register_handle_function(HIP_I1, HIP_STATE_ESTABLISHED, &hip_handle_i1, 30000);
69+ hip_register_handle_function(HIP_I1, HIP_STATE_ESTABLISHED, &hip_update_retransmissions, 35000);
70 hip_register_handle_function(HIP_I1, HIP_STATE_ESTABLISHED, &hip_send_r1, 40000);
71 hip_register_handle_function(HIP_I1, HIP_STATE_CLOSING, &hip_check_i1, 20000);
72 hip_register_handle_function(HIP_I1, HIP_STATE_CLOSING, &hip_handle_i1, 30000);
73+ hip_register_handle_function(HIP_I1, HIP_STATE_CLOSING, &hip_update_retransmissions, 35000);
74 hip_register_handle_function(HIP_I1, HIP_STATE_CLOSING, &hip_send_r1, 40000);
75 hip_register_handle_function(HIP_I1, HIP_STATE_CLOSED, &hip_check_i1, 20000);
76 hip_register_handle_function(HIP_I1, HIP_STATE_CLOSED, &hip_handle_i1, 30000);
77+ hip_register_handle_function(HIP_I1, HIP_STATE_CLOSED, &hip_update_retransmissions, 35000);
78 hip_register_handle_function(HIP_I1, HIP_STATE_CLOSED, &hip_send_r1, 40000);
79 hip_register_handle_function(HIP_I1, HIP_STATE_NONE, &hip_check_i1, 20000);
80 hip_register_handle_function(HIP_I1, HIP_STATE_NONE, &hip_handle_i1, 30000);
81+ hip_register_handle_function(HIP_I1, HIP_STATE_NONE, &hip_update_retransmissions, 35000);
82 hip_register_handle_function(HIP_I1, HIP_STATE_NONE, &hip_send_r1, 40000);
83
84 hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_check_i2, 20000);
85 hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_handle_i2, 30000);
86+ hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_update_retransmissions, 30250);
87 hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_setup_ipsec_sa, 30500);
88 hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_create_r2, 40000);
89 hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_add_rvs_reg_from, 41000);
90@@ -594,6 +603,7 @@
91 hip_register_handle_function(HIP_I2, HIP_STATE_UNASSOCIATED, &hip_send_r2, 50000);
92 hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT, &hip_check_i2, 20000);
93 hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT, &hip_handle_i2, 30000);
94+ hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT, &hip_update_retransmissions, 30250);
95 hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT, &hip_setup_ipsec_sa, 30500);
96 hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT, &hip_create_r2, 40000);
97 hip_register_handle_function(HIP_I2, HIP_STATE_I1_SENT, &hip_add_rvs_reg_from, 41000);
98@@ -603,6 +613,7 @@
99 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_check_i2, 20000);
100 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_handle_i2_in_i2_sent, 21000);
101 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_handle_i2, 30000);
102+ hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_update_retransmissions, 30250);
103 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_setup_ipsec_sa, 30500);
104 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_create_r2, 40000);
105 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_add_rvs_reg_from, 41000);
106@@ -611,6 +622,7 @@
107 hip_register_handle_function(HIP_I2, HIP_STATE_I2_SENT, &hip_send_r2, 50000);
108 hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_check_i2, 20000);
109 hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_handle_i2, 30000);
110+ hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_update_retransmissions, 30250);
111 hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_setup_ipsec_sa, 30500);
112 hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_create_r2, 40000);
113 hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_add_rvs_reg_from, 41000);
114@@ -619,6 +631,7 @@
115 hip_register_handle_function(HIP_I2, HIP_STATE_R2_SENT, &hip_send_r2, 50000);
116 hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_check_i2, 20000);
117 hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_handle_i2, 30000);
118+ hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_update_retransmissions, 30250);
119 hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_setup_ipsec_sa, 30500);
120 hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_create_r2, 40000);
121 hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_add_rvs_reg_from, 41000);
122@@ -627,6 +640,7 @@
123 hip_register_handle_function(HIP_I2, HIP_STATE_ESTABLISHED, &hip_send_r2, 50000);
124 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_check_i2, 20000);
125 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_handle_i2, 30000);
126+ hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_update_retransmissions, 30250);
127 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_setup_ipsec_sa, 30500);
128 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_create_r2, 40000);
129 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_add_rvs_reg_from, 41000);
130@@ -635,6 +649,7 @@
131 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSING, &hip_send_r2, 50000);
132 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_check_i2, 20000);
133 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_handle_i2, 30000);
134+ hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_update_retransmissions, 30250);
135 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_setup_ipsec_sa, 30500);
136 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_create_r2, 40000);
137 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_add_rvs_reg_from, 41000);
138@@ -643,6 +658,7 @@
139 hip_register_handle_function(HIP_I2, HIP_STATE_CLOSED, &hip_send_r2, 50000);
140 hip_register_handle_function(HIP_I2, HIP_STATE_NONE, &hip_check_i2, 20000);
141 hip_register_handle_function(HIP_I2, HIP_STATE_NONE, &hip_handle_i2, 30000);
142+ hip_register_handle_function(HIP_I2, HIP_STATE_NONE, &hip_update_retransmissions, 30250);
143 hip_register_handle_function(HIP_I2, HIP_STATE_NONE, &hip_setup_ipsec_sa, 30500);
144 hip_register_handle_function(HIP_I2, HIP_STATE_NONE, &hip_create_r2, 40000);
145 hip_register_handle_function(HIP_I2, HIP_STATE_NONE, &hip_add_rvs_reg_from, 41000);
146@@ -652,6 +668,7 @@
147
148 hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_check_r1, 20000);
149 hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_handle_r1, 30000);
150+ hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_update_retransmissions, 30500);
151 hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_build_esp_info, 31000);
152 hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_build_solution, 32000);
153 hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_handle_diffie_hellman, 33000);
154@@ -663,6 +680,7 @@
155 hip_register_handle_function(HIP_R1, HIP_STATE_I1_SENT, &hip_send_i2, 50000);
156 hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_check_r1, 20000);
157 hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_handle_r1, 30000);
158+ hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_update_retransmissions, 30500);
159 hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_build_esp_info, 31000);
160 hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_build_solution, 32000);
161 hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_handle_diffie_hellman, 33000);
162@@ -674,6 +692,7 @@
163 hip_register_handle_function(HIP_R1, HIP_STATE_I2_SENT, &hip_send_i2, 50000);
164 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_check_r1, 20000);
165 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_handle_r1, 30000);
166+ hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_update_retransmissions, 30500);
167 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_build_esp_info, 31000);
168 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_build_solution, 32000);
169 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_handle_diffie_hellman, 33000);
170@@ -685,6 +704,7 @@
171 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSING, &hip_send_i2, 50000);
172 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSED, &hip_check_r1, 20000);
173 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSED, &hip_handle_r1, 30000);
174+ hip_register_handle_function(HIP_R1, HIP_STATE_CLOSED, &hip_update_retransmissions, 30500);
175 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSED, &hip_build_esp_info, 31000);
176 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSED, &hip_build_solution, 32000);
177 hip_register_handle_function(HIP_R1, HIP_STATE_CLOSED, &hip_handle_diffie_hellman, 33000);
178@@ -697,6 +717,7 @@
179
180 hip_register_handle_function(HIP_R2, HIP_STATE_I2_SENT, &hip_check_r2, 20000);
181 hip_register_handle_function(HIP_R2, HIP_STATE_I2_SENT, &hip_handle_r2, 30000);
182+ hip_register_handle_function(HIP_R2, HIP_STATE_I2_SENT, &hip_update_retransmissions, 30250);
183 hip_register_handle_function(HIP_R2, HIP_STATE_I2_SENT, &hip_setup_ipsec_sa, 30500);
184
185 hip_register_handle_function(HIP_NOTIFY, HIP_STATE_I1_SENT, &hip_check_notify, 20000);
186@@ -712,18 +733,22 @@
187 hip_register_handle_function(HIP_NOTIFY, HIP_STATE_CLOSED, &hip_check_notify, 20000);
188 hip_register_handle_function(HIP_NOTIFY, HIP_STATE_CLOSED, &hip_handle_notify, 30000);
189
190- hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_close_check_packet, 20000);
191- hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_close_create_response, 30000);
192- hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_close_send_response, 40000);
193+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_close_check_packet, 20000);
194+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_update_retransmissions, 25000);
195+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_close_create_response, 30000);
196+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_ESTABLISHED, &hip_close_send_response, 40000);
197
198- hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_close_check_packet, 20000);
199- hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_close_create_response, 30000);
200- hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_close_send_response, 40000);
201+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_close_check_packet, 20000);
202+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_update_retransmissions, 25000);
203+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_close_create_response, 30000);
204+ hip_register_handle_function(HIP_CLOSE, HIP_STATE_CLOSING, &hip_close_send_response, 40000);
205
206 hip_register_handle_function(HIP_CLOSE_ACK, HIP_STATE_CLOSING, &hip_close_ack_check_packet, 20000);
207+ hip_register_handle_function(HIP_CLOSE_ACK, HIP_STATE_CLOSING, &hip_update_retransmissions, 25000);
208 hip_register_handle_function(HIP_CLOSE_ACK, HIP_STATE_CLOSING, &hip_close_ack_handle_packet, 30000);
209
210 hip_register_handle_function(HIP_CLOSE_ACK, HIP_STATE_CLOSED, &hip_close_ack_check_packet, 20000);
211+ hip_register_handle_function(HIP_CLOSE_ACK, HIP_STATE_CLOSED, &hip_update_retransmissions, 25000);
212 hip_register_handle_function(HIP_CLOSE_ACK, HIP_STATE_CLOSED, &hip_close_ack_handle_packet, 30000);
213
214 hip_register_handle_function(HIP_LUPDATE, HIP_STATE_ESTABLISHED, &esp_prot_handle_light_update, 20000);
215
216=== modified file 'hipd/input.c'
217--- hipd/input.c 2011-12-09 09:32:56 +0000
218+++ hipd/input.c 2011-12-29 15:06:25 +0000
219@@ -58,6 +58,7 @@
220 #include "lib/core/state.h"
221 #include "lib/core/transform.h"
222 #include "lib/tool/xfrmapi.h"
223+#include "modules/update/hipd/update.h"
224 #include "config.h"
225 #include "cookie.h"
226 #include "dh.h"
227@@ -1113,8 +1114,6 @@
228 hip_perf_stop_benchmark(perf_set, PERF_BASE);
229 hip_perf_write_benchmark(perf_set, PERF_BASE);
230 #endif
231- ctx->hadb_entry->hip_msg_retrans.count = 0;
232- memset(ctx->hadb_entry->hip_msg_retrans.buf, 0, HIP_MAX_NETWORK_PACKET);
233
234 if (ctx->hadb_entry->state == HIP_STATE_ESTABLISHED) {
235 HIP_DEBUG("Send response to firewall.\n");
236@@ -1695,9 +1694,6 @@
237 ctx->hadb_entry->state = HIP_STATE_ESTABLISHED;
238 HIP_INFO("Reached %s state\n", hip_state_str(ctx->hadb_entry->state));
239
240- ctx->hadb_entry->hip_msg_retrans.count = 0;
241- memset(ctx->hadb_entry->hip_msg_retrans.buf, 0, HIP_MAX_NETWORK_PACKET);
242-
243 out_err:
244 if (err) {
245 ctx->error = err;
246@@ -1877,3 +1873,121 @@
247
248 return err;
249 }
250+
251+/**
252+ * Clear the given retransmission.
253+ * i.e. set the remaining retransmissions to zero and zero the buffer.
254+ *
255+ * @param retrans The retransmission to be cleared.
256+ */
257+void hip_clear_retransmission(struct hip_msg_retrans *const retrans)
258+{
259+ if (!retrans) {
260+ return;
261+ }
262+
263+ retrans->count = 0;
264+ if (retrans->buf) {
265+ memset(retrans->buf, 0, hip_get_msg_total_len(retrans->buf));
266+ }
267+}
268+
269+/**
270+ * Decide whether the given UPDATE retransmission is still valid with regard to
271+ * the incoming message. For example a buffered U1 packet is invalidated when a
272+ * fresh U2 comes in.
273+ *
274+ * @param ctx The packet context of the incoming transmission.
275+ * @param retrans The retransmission in question.
276+ * @return True if given retransmission is invalid.
277+ * False else.
278+ */
279+static bool update_retrans_is_invalid(struct hip_packet_context *const ctx,
280+ struct hip_msg_retrans *const retrans)
281+{
282+ if (!ctx || !retrans) {
283+ return false;
284+ }
285+
286+ switch (hip_classify_update_type(ctx->input_msg)) {
287+ case SECOND_UPDATE_PACKET:
288+ return hip_classify_update_type(retrans->buf) == FIRST_UPDATE_PACKET;
289+
290+ case THIRD_UPDATE_PACKET:
291+ return hip_classify_update_type(retrans->buf) == SECOND_UPDATE_PACKET;
292+
293+ default:
294+ return false;
295+ }
296+}
297+
298+/**
299+ * Update our buffered retransmissions after receiving the given packet.
300+ * This functions removes invalid retransmissions after a state change caused
301+ * by a received packet. For example after successfully receiving and handling
302+ * an I2 or R2 packet all our buffered packets are dropped.
303+ *
304+ * Call this function after successful handling of the incoming packet.
305+ *
306+ * @param packet_type The packet type of the control message (RFC 5201, 5.3.)
307+ * @param ha_state The host association state (RFC 5201, 4.4.1.)
308+ * @param ctx The packet context of the incoming transmission.
309+ *
310+ * @return Always 0. Nothing unforeseen may happen here which is important
311+ * enough to break the packet processing. Unhandled incoming message
312+ * types are simply ignored. Handle functions have to return an int
313+ * though so always 0 it is.
314+ */
315+int hip_update_retransmissions(UNUSED const uint8_t packet_type,
316+ UNUSED const enum hip_state ha_state,
317+ struct hip_packet_context *const ctx)
318+{
319+ struct hip_msg_retrans *retrans;
320+
321+ HIP_ASSERT(ctx);
322+ HIP_ASSERT(ctx->input_msg);
323+
324+ /* When receiving an I1 there usually is no established state yet. */
325+ if (!ctx->hadb_entry) {
326+ return 0;
327+ }
328+
329+ for (unsigned int i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
330+ retrans = &ctx->hadb_entry->hip_msg_retrans[i];
331+
332+ if (retrans->count == 0) {
333+ continue;
334+ }
335+
336+ switch (hip_get_msg_type(ctx->input_msg)) {
337+ case HIP_I1:
338+ /* We only remove our sent I1s when we have got a greater HIT
339+ * than the peer (ref. RFC 5201, 4.4.2). */
340+ if (hip_get_msg_type(retrans->buf) == HIP_I1 &&
341+ hip_hit_is_bigger(&ctx->hadb_entry->hit_our, &ctx->hadb_entry->hit_peer)) {
342+ hip_clear_retransmission(retrans);
343+ }
344+ break;
345+
346+ case HIP_I2:
347+ case HIP_R1:
348+ case HIP_R2:
349+ case HIP_CLOSE:
350+ case HIP_CLOSE_ACK:
351+ hip_clear_retransmission(retrans);
352+ break;
353+
354+ case HIP_UPDATE:
355+ if (update_retrans_is_invalid(ctx, retrans)) {
356+ hip_clear_retransmission(retrans);
357+ }
358+ break;
359+
360+ /* We do not act on other message types like Light UPDATE for example. */
361+ default:
362+ break;
363+ }
364+ }
365+
366+ return 0;
367+}
368
369=== modified file 'hipd/input.h'
370--- hipd/input.h 2011-11-25 17:56:24 +0000
371+++ hipd/input.h 2011-12-29 15:06:25 +0000
372@@ -127,4 +127,10 @@
373 UNUSED const enum hip_state ha_state,
374 struct hip_packet_context *ctx);
375
376+void hip_clear_retransmission(struct hip_msg_retrans *const retrans);
377+
378+int hip_update_retransmissions(UNUSED const uint8_t packet_type,
379+ UNUSED const enum hip_state ha_state,
380+ struct hip_packet_context *const ctx);
381+
382 #endif /* HIPL_HIPD_INPUT_H */
383
384=== modified file 'hipd/maintenance.c'
385--- hipd/maintenance.c 2011-12-21 10:54:26 +0000
386+++ hipd/maintenance.c 2011-12-29 15:06:25 +0000
387@@ -60,6 +60,7 @@
388 #include "hidb.h"
389 #include "hipd.h"
390 #include "init.h"
391+#include "input.h"
392 #include "output.h"
393 #include "maintenance.h"
394
395@@ -89,55 +90,48 @@
396 * @param current_time current time
397 * @return zero on success or negative on failure
398 */
399-static int handle_retransmission(struct hip_hadb_state *entry,
400- void *current_time)
401+static int handle_retransmissions(struct hip_hadb_state *entry,
402+ void *current_time)
403 {
404- int err = 0;
405- time_t *now = current_time;
406-
407- if (entry->hip_msg_retrans.count == 0) {
408- goto out_err;
409- }
410-
411- /* check if the last transmission was at least RETRANSMIT_WAIT seconds ago */
412- if (*now - HIP_RETRANSMIT_WAIT > entry->hip_msg_retrans.last_transmit) {
413- if (entry->hip_msg_retrans.count > 0 &&
414- ((entry->state != HIP_STATE_ESTABLISHED && entry->retrans_state != entry->state) ||
415- entry->light_update_retrans == 1)) {
416- HIP_DEBUG("state=%d, retrans_state=%d\n", entry->state, entry->retrans_state);
417-
418- /* @todo: verify that this works over slow ADSL line */
419- err = hip_send_pkt(&entry->hip_msg_retrans.saddr,
420- &entry->hip_msg_retrans.daddr,
421- entry->nat_mode ? hip_get_local_nat_udp_port() : 0,
422- entry->peer_udp_port,
423- entry->hip_msg_retrans.buf,
424- entry, 0);
425-
426- /* Set entry state, if previous state was unassociated
427- * and type is I1. */
428- if (!err && hip_get_msg_type(entry->hip_msg_retrans.buf)
429- == HIP_I1 && entry->state == HIP_STATE_UNASSOCIATED) {
430- HIP_DEBUG("Resent I1 succcesfully\n");
431- entry->state = HIP_STATE_I1_SENT;
432- }
433-
434- entry->hip_msg_retrans.count--;
435- time(&entry->hip_msg_retrans.last_transmit);
436- } else {
437- entry->hip_msg_retrans.count = 0;
438- memset(entry->hip_msg_retrans.buf, 0, HIP_MAX_NETWORK_PACKET);
439-
440- if (entry->state == HIP_STATE_ESTABLISHED) {
441- entry->retrans_state = HIP_STATE_NONE;
442- } else {
443- entry->retrans_state = entry->state;
444+ int err = 0, i = 0;
445+ struct hip_msg_retrans *retrans;
446+ time_t *now = current_time;
447+
448+ for (i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
449+ retrans = &entry->hip_msg_retrans[(entry->next_retrans_slot + i) %
450+ HIP_RETRANSMIT_QUEUE_SIZE];
451+
452+ /* check if the last transmission was at least RETRANSMIT_WAIT seconds ago */
453+ if (*now - HIP_RETRANSMIT_WAIT > retrans->last_transmit) {
454+ if (retrans->count > 0) {
455+ /* @todo: verify that this works over slow ADSL line */
456+ if (hip_send_pkt(&retrans->saddr,
457+ &retrans->daddr,
458+ entry->nat_mode ? hip_get_local_nat_udp_port() : 0,
459+ entry->peer_udp_port,
460+ retrans->buf,
461+ entry, 0) == 0) {
462+ /* Set entry state, if previous state was unassociated
463+ * and type is I1. */
464+ if (hip_get_msg_type(retrans->buf) == HIP_I1 &&
465+ entry->state == HIP_STATE_UNASSOCIATED) {
466+ HIP_DEBUG("Resent I1 succcesfully\n");
467+ entry->state = HIP_STATE_I1_SENT;
468+ }
469+ } else {
470+ HIP_ERROR("Failed to retransmit packet of type %d.\n",
471+ hip_get_msg_type(retrans->buf));
472+ err = -1;
473+ }
474+
475+ retrans->count--;
476+ time(&retrans->last_transmit);
477+ } else if (hip_get_msg_type(retrans->buf)) {
478+ hip_clear_retransmission(retrans);
479 }
480 }
481 }
482
483-out_err:
484-
485 return err;
486 }
487
488@@ -151,7 +145,7 @@
489 time_t current_time;
490 time(&current_time);
491
492- if (hip_for_each_ha(handle_retransmission, &current_time)) {
493+ if (hip_for_each_ha(handle_retransmissions, &current_time)) {
494 return -1;
495 }
496 return 0;
497
498=== modified file 'hipd/netdev.c'
499--- hipd/netdev.c 2011-12-09 09:32:56 +0000
500+++ hipd/netdev.c 2011-12-29 15:06:25 +0000
501@@ -921,12 +921,15 @@
502
503 send_i1:
504
505- if (entry->hip_msg_retrans.count == 0) {
506- HIP_DEBUG("Expired retransmissions, sending i1\n");
507- } else {
508- HIP_DEBUG("I1 was already sent, ignoring\n");
509- goto out_err;
510+ HIP_DEBUG("Checking for older queued I1 transmissions.\n");
511+ for (unsigned int i = 0; i < HIP_RETRANSMIT_QUEUE_SIZE; i++) {
512+ if (entry->hip_msg_retrans[i].count > 0
513+ && hip_get_msg_type(entry->hip_msg_retrans[i].buf) == HIP_I1) {
514+ HIP_DEBUG("I1 was already sent, ignoring\n");
515+ goto out_err;
516+ }
517 }
518+ HIP_DEBUG("Expired retransmissions, sending i1\n");
519
520 is_ipv4_locator = IN6_IS_ADDR_V4MAPPED(&entry->peer_addr);
521
522
523=== modified file 'hipd/output.c'
524--- hipd/output.c 2011-11-10 10:53:21 +0000
525+++ hipd/output.c 2011-12-29 15:06:25 +0000
526@@ -1066,7 +1066,7 @@
527 err = hip_send_pkt(&ctx->dst_addr, &ctx->src_addr,
528 ctx->hadb_entry->nat_mode ? hip_get_local_nat_udp_port() : 0,
529 ctx->hadb_entry->peer_udp_port, ctx->output_msg,
530- ctx->hadb_entry, 1);
531+ ctx->hadb_entry, 0);
532
533 HIP_IFEL(err, -ECOMM, "Sending R2 packet failed.\n");
534
535@@ -1111,29 +1111,30 @@
536 * destination HITs.
537 * @param entry a pointer to the current host association database state.
538 * @return zero
539- * @note currently the queue length is one and new packets replace old ones
540 */
541 static int queue_packet(const struct in6_addr *src_addr,
542 const struct in6_addr *peer_addr,
543 const struct hip_common *msg,
544 struct hip_hadb_state *entry)
545 {
546- int len = hip_get_msg_total_len(msg);
547+ struct hip_msg_retrans *retrans;
548
549 if (!entry) {
550 return 0;
551 }
552
553+ retrans = &entry->hip_msg_retrans[entry->next_retrans_slot];
554+
555 /* Not reusing the old entry as the new packet may have different length */
556- memset(entry->hip_msg_retrans.buf, 0, HIP_MAX_NETWORK_PACKET);
557-
558- memcpy(entry->hip_msg_retrans.buf, msg, len);
559- memcpy(&entry->hip_msg_retrans.saddr, src_addr,
560- sizeof(struct in6_addr));
561- memcpy(&entry->hip_msg_retrans.daddr, peer_addr,
562- sizeof(struct in6_addr));
563- entry->hip_msg_retrans.count = HIP_RETRANSMIT_MAX;
564- time(&entry->hip_msg_retrans.last_transmit);
565+ memset(retrans->buf, 0, HIP_MAX_NETWORK_PACKET);
566+
567+ memcpy(retrans->buf, msg, hip_get_msg_total_len(msg));
568+ ipv6_addr_copy(&retrans->saddr, src_addr);
569+ ipv6_addr_copy(&retrans->daddr, peer_addr);
570+ retrans->count = HIP_RETRANSMIT_MAX;
571+ time(&retrans->last_transmit);
572+
573+ entry->next_retrans_slot = (entry->next_retrans_slot + 1) % HIP_RETRANSMIT_QUEUE_SIZE;
574
575 return 0;
576 }
577
578=== modified file 'lib/core/state.h'
579--- lib/core/state.h 2011-12-16 13:37:33 +0000
580+++ lib/core/state.h 2011-12-29 15:06:25 +0000
581@@ -100,6 +100,9 @@
582 HIP_HA_STATE_VALID = 1,
583 };
584
585+/* The maximum number of retransmissions to queue. */
586+#define HIP_RETRANSMIT_QUEUE_SIZE 3
587+
588 /**
589 * A data structure for handling retransmission. Used inside host association
590 * database entries.
591@@ -157,9 +160,6 @@
592 int purge_timeout;
593 /** The state of this host association. */
594 enum hip_state state;
595- /** This guarantees that retransmissions work properly also in
596- * non-established state.*/
597- enum hip_state retrans_state;
598 /** Our control values related to this host association.
599 * @see hip_ha_controls */
600 hip_controls local_controls;
601@@ -282,8 +282,11 @@
602 unsigned char echo_data[4];
603
604 HIP_HASHTABLE *peer_addr_list_to_be_added;
605+ /** The slot in our struct hip_msg_retrans array which will be used to save
606+ * the next retransmission. */
607+ unsigned int next_retrans_slot;
608 /** For storing retransmission related data. */
609- struct hip_msg_retrans hip_msg_retrans;
610+ struct hip_msg_retrans hip_msg_retrans[HIP_RETRANSMIT_QUEUE_SIZE];
611 /** peer hostname */
612 uint8_t peer_hostname[HIP_HOST_ID_HOSTNAME_LEN_MAX];
613 /** Counters of heartbeats (ICMPv6s) */
614
615=== modified file 'modules/update/hipd/update.c'
616--- modules/update/hipd/update.c 2011-12-16 13:37:33 +0000
617+++ modules/update/hipd/update.c 2011-12-29 15:06:25 +0000
618@@ -364,7 +364,7 @@
619 ctx->hadb_entry->peer_udp_port,
620 ctx->output_msg,
621 ctx->hadb_entry,
622- 1);
623+ 0);
624 }
625
626 return err;
627@@ -810,6 +810,11 @@
628 -1, "Error on registering UPDATE handle function.\n");
629 HIP_IFEL(hip_register_handle_function(HIP_UPDATE,
630 HIP_STATE_R2_SENT,
631+ &hip_update_retransmissions,
632+ 20150),
633+ -1, "Error on registering UPDATE handle function.\n");
634+ HIP_IFEL(hip_register_handle_function(HIP_UPDATE,
635+ HIP_STATE_R2_SENT,
636 &prepare_update_response,
637 20200),
638 -1, "Error on registering UPDATE handle function.\n");
639@@ -896,6 +901,11 @@
640 -1, "Error on registering UPDATE handle function.\n");
641 HIP_IFEL(hip_register_handle_function(HIP_UPDATE,
642 HIP_STATE_ESTABLISHED,
643+ &hip_update_retransmissions,
644+ 20150),
645+ -1, "Error on registering UPDATE handle function.\n");
646+ HIP_IFEL(hip_register_handle_function(HIP_UPDATE,
647+ HIP_STATE_ESTABLISHED,
648 &prepare_update_response,
649 20200),
650 -1, "Error on registering UPDATE handle function.\n");

Subscribers

People subscribed via source and target branches

to all changes: