diff --git a/mphlr.h b/mphlr.h index 52588902..ee358892 100644 --- a/mphlr.h +++ b/mphlr.h @@ -373,6 +373,43 @@ int packetSendRequest(int method,unsigned char *packet,int packet_len,int batchP struct response_set *responses); +typedef struct overlay_frame { + struct overlay_frame *prev; + struct overlay_frame *next; + + unsigned int type; + unsigned int modifiers; + + unsigned char ttl; + + unsigned char nexthop[32]; + int nexthop_address_status; + + unsigned char destination[32]; + int destination_address_status; + + unsigned char source[32]; + int source_address_status; + + /* Frame content from destination address onwards */ + unsigned int bytecount; + unsigned char *bytes; + + /* Actual payload */ + unsigned int payloadlength; + unsigned char *payload; + int payloadFreeP; /* Set if this needs to be freed on disposal + of the frame */ + + int rfs; /* remainder of frame size */ + + long long enqueued_at; + +} overlay_frame; + +int overlay_frame_process(int interface,overlay_frame *f); +int overlay_frame_resolve_addresses(int interface,overlay_frame *f); + #define CRYPT_CIPHERED 1 #define CRYPT_SIGNED 2 @@ -503,46 +540,16 @@ typedef struct overlay_buffer { int allocSize; int checkpointLength; int sizeLimit; + int var_length_offset; + int var_length_bytes; } overlay_buffer; int ob_unlimitsize(overlay_buffer *b); -typedef struct overlay_payload { - struct overlay_payload *prev; - struct overlay_payload *next; - - /* We allows 256 bit addresses and 32bit port numbers */ - unsigned char src[SIDDIDFIELD_LEN]; - unsigned char dst[SIDDIDFIELD_LEN]; - int srcPort; - int dstPort; - - /* Hops before packet is dropped */ - unsigned char ttl; - unsigned char trafficClass; - - unsigned char srcAddrType; - unsigned char dstAddrType; - - /* Method of encryption if any employed */ - unsigned char cipher; - - /* Payload flags */ - unsigned char flags; - - /* Size and Pointer to the payload itself */ - int payloadLength; - /* make the payload pointer be at the end, so that we can conveniently have the data follow this structure if necessary. - (this lets us change the char * to a char payload[1] down the track to simplify this) */ - unsigned char *payload; - - /* time this frame was enqueued */ - long long enqueued_at; -} overlay_payload; typedef struct overlay_txqueue { - overlay_payload *first; - overlay_payload *last; + struct overlay_frame *first; + struct overlay_frame *last; int length; int maxLength; /* Latency target in ms for this traffic class. @@ -578,8 +585,11 @@ int ob_makespace(overlay_buffer *b,int bytes); int ob_append_bytes(overlay_buffer *b,unsigned char *bytes,int count); int ob_append_short(overlay_buffer *b,unsigned short v); int ob_append_int(overlay_buffer *b,unsigned int v); +int ob_patch_rfs(overlay_buffer *b,int l); +int ob_indel_space(overlay_buffer *b,int offset,int shift); +int ob_append_rfs(overlay_buffer *b,int l); -int op_free(overlay_payload *p); +int op_free(overlay_frame *p); long long parse_quantity(char *q); @@ -593,7 +603,7 @@ long long overlay_time_until_next_tick(); int overlay_rx_messages(); int overlay_check_ticks(); int overlay_add_selfannouncement(); -int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b); +int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b); int overlay_interface_args(char *arg); int overlay_get_nexthop(unsigned char *final_destination,unsigned char *nexthop,int *nexthoplen); @@ -627,7 +637,7 @@ extern int overlay_interface_count; #define OF_TYPE_FLAG_BITS 0xf0000000 #define OF_TYPE_FLAG_NORMAL 0x0 #define OF_TYPE_FLAG_E12 0x10000000 -#define OF_TYPE_FLAG_E20 0x00000000 +#define OF_TYPE_FLAG_E20 0x20000000 /* Modifiers that indicate the disposition of the frame */ #define OF_MODIFIER_BITS 0x0f @@ -648,6 +658,8 @@ extern int overlay_interface_count; #define OVERLAY_ADDRESS_CACHE_SIZE 1024 int overlay_abbreviate_address(unsigned char *in,char *out,int *ofs); +int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a); + int overlay_abbreviate_expand_address(int interface,unsigned char *in,int *inofs,unsigned char *out,int *ofs); int overlay_abbreviate_cache_address(unsigned char *sid); int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *ofs, @@ -682,32 +694,13 @@ int overlay_abbreviate_set_most_recent_address(unsigned char *in); /* The TTL field in a frame is used to differentiate between link-local and wide-area broadcasts */ #define OA_CODE_BROADCAST 0x0f -typedef struct overlay_frame { - unsigned int type; - unsigned int modifiers; +#define RFS_PLUS250 0xfa +#define RFS_PLUS456 0xfb +#define RFS_PLUS762 0xfc +#define RFS_PLUS1018 0xfd +#define RFS_PLUS1274 0xfe +#define RFS_3BYTE 0xff +int rfs_length(int l); +int rfs_encode(int l,unsigned char *b); +int rfs_decode(unsigned char *b,int *offset); - unsigned char ttl; - - unsigned char nexthop[32]; - int nexthop_address_status; - - unsigned char destination[32]; - int destination_address_status; - - unsigned char source[32]; - int source_address_status; - - /* Frame content from destination address onwards */ - unsigned int bytecount; - unsigned char *bytes; - - /* Actual payload */ - unsigned int payloadlength; - unsigned char *payload; - - int rfs; /* remainder of frame size */ - -} overlay_frame; - -int overlay_frame_process(int interface,overlay_frame *f); -int overlay_frame_resolve_addresses(int interface,overlay_frame *f); diff --git a/overlay.c b/overlay.c index 7f773ae0..e57f8167 100644 --- a/overlay.c +++ b/overlay.c @@ -200,16 +200,26 @@ int overlay_frame_process(int interface,overlay_frame *f) return WHY("Could not find next hop for host - dropping frame"); f->ttl--; /* Queue frame for dispatch */ + /* XXX We currently have separate overlay_payload structures for sending and + overlay_frame for receiving. Need to harmonise this. Multiple conversions + are wasteful. We really should be able to cope with a single structure. */ - return WHY("forwarding of frame not implemented"); + + WHY("forwarding of frame not implemented"); + + /* If the frame was a broadcast frame, then we need to hang around + so that we can process it, since we are one of the recipients. + Otherwise, return triumphant. */ + if (!broadcast) return 0; } switch(f->type) { case OF_TYPE_SELFANNOUNCE: - - - + overlay_route_saw_selfannounce(f); + break; + case OF_TYPE_SELFANNOUNCE_ACK: + overlay_route_saw_selfannounce_ack(f); break; default: return WHY("Support for that f->type not yet implemented"); diff --git a/overlay_abbreviations.c b/overlay_abbreviations.c index b475ffc3..cbdc36b7 100644 --- a/overlay_abbreviations.c +++ b/overlay_abbreviations.c @@ -203,6 +203,16 @@ int overlay_abbreviate_try_byindex(unsigned char *in,char *out,int *ofs,int inde return 1; } +int overlay_abbreviate_append_address(overlay_buffer *b,unsigned char *a) +{ + int count=0; + ob_makespace(b,SID_SIZE+3); + int r=overlay_abbreviate_address(a,&b->bytes[b->length],&count); + if (r) return r; + b->length+=count; + return 0; +} + int overlay_abbreviate_address(unsigned char *in,char *out,int *ofs) { int i; diff --git a/overlay_buffer.c b/overlay_buffer.c index f50a72a2..91f849af 100644 --- a/overlay_buffer.c +++ b/overlay_buffer.c @@ -1,6 +1,5 @@ #include "mphlr.h" - overlay_buffer *ob_new(int size) { overlay_buffer *ret=calloc(sizeof(overlay_buffer),1); @@ -99,3 +98,91 @@ int ob_append_int(overlay_buffer *b,unsigned int v) unsigned int s=htonl(v); return ob_append_bytes(b,(unsigned char *)&s,sizeof(unsigned int)); } + +int ob_append_rfs(overlay_buffer *b,int l) +{ + /* Encode the specified length and append it to the buffer */ + if (l<0||l>0xffff) return -1; + + /* First work out how long the field needs to be, then write dummy bytes + and use ob_patch_length to set the value. That way we have only one + lot of code that does the encoding. */ + + b->var_length_offset=b->length; + b->var_length_bytes=rfs_length(l); + + unsigned char c[3]={0,0,0}; + if (ob_append_bytes(b,c,b->var_length_bytes)) { + b->var_length_offset=0; + return -1; + } + + return ob_patch_rfs(b,l); + +} + +int rfs_length(int l) +{ + if (l<0) return -1; + if (l<250) return 1; + else if (l<(255+250+(256*4))) return 2; + else if (l<=0xffff) return 3; + else return -1; +} + +int rfs_encode(int l, unsigned char *b) +{ + if (l<250) { b[0]=l; } + else if (l<(255+250+(256*4))) { + b[0]=RFS_PLUS250+(l-250)/256; + b[1]=l-((l-250)/256); + } else { + b[0]=RFS_3BYTE; + b[1]=l>>8; + b[2]=l&0xff; + } + return 0; +} + +int rfs_decode(unsigned char *b,int *ofs) +{ + int rfs=b[*ofs]; + switch(rfs) { + case RFS_PLUS250: case RFS_PLUS456: case RFS_PLUS762: case RFS_PLUS1018: case RFS_PLUS1274: + rfs=250+256*(rfs-RFS_PLUS250)+b[++(*ofs)]; + break; + case RFS_3BYTE: rfs=(b[(*ofs)+1]<<8)+b[(*ofs)+2]; (*ofs)+=2; + default: /* Length is natural value of field, so nothing to do */ + break; + } + (*ofs)++; + return rfs; +} + +int ob_indel_space(overlay_buffer *b,int offset,int shift) +{ + if (shift>0) { /* make space */ + if (ob_makespace(b,-shift)) return -1; + bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->length-(offset+shift)); + } else if (shift<0) { /* free up space */ + bcopy(&b->bytes[offset],&b->bytes[offset-shift],b->length-(offset-shift)); + } + b->length+=shift; + return 0; +} + + +int ob_patch_rfs(overlay_buffer *b,int l) +{ + if (l<0||l>0xffff) return -1; + + /* Adjust size of field */ + int new_size=rfs_length(l); + int shift=new_size-b->var_length_bytes; + if (ob_indel_space(b,b->var_length_offset,shift)) return -1; + + if (rfs_encode(l,&b->bytes[b->var_length_offset])) return -1; + + return 0; + +} diff --git a/overlay_interface.c b/overlay_interface.c index f2f97bb8..f5c6ed1c 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -452,7 +452,7 @@ int overlay_tick_interface(int i, long long now) { int frame_pax=0; #define MAX_FRAME_PAX 1024 - overlay_payload *pax[MAX_FRAME_PAX]; + overlay_frame *pax[MAX_FRAME_PAX]; if (overlay_interfaces[i].bits_per_second<1) { /* An interface with no speed budget is for listening only, so doesn't get ticked */ @@ -481,11 +481,11 @@ int overlay_tick_interface(int i, long long now) overlay_add_selfannouncement(i,e); /* 2. Add any queued high-priority isochronous data (i.e. voice) to the frame. */ - overlay_payload **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first; + overlay_frame **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first; while(p) { /* Throw away any stale frames */ - overlay_payload *pp=*p; + overlay_frame *pp=*p; if (!pp) break; @@ -505,7 +505,7 @@ int overlay_tick_interface(int i, long long now) bad. The only hard limit is the maximum number of payloads we allow in a frame, which is set so high as to be irrelevant, even on loopback or gigabit ethernet interface */ if (frame_pax>=MAX_FRAME_PAX) break; - if (!overlay_payload_package_fmt1(*p,e)) + if (!overlay_frame_package_fmt1(*p,e)) { /* Add payload to list of payloads we are sending with this frame so that we can dequeue them if we send them. */ @@ -533,7 +533,7 @@ int overlay_tick_interface(int i, long long now) overlay_interfaces[i].sequence_number,i,e->length); /* De-queue the passengers who were aboard. */ int j; - overlay_payload **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first; + overlay_frame **p=&overlay_tx[OVERLAY_ISOCHRONOUS_VOICE].first; for(j=0;jtype&OF_TYPE_FLAG_BITS) + { + case OF_TYPE_FLAG_NORMAL: + c[0]=p->type|p->modifiers; + if (ob_append_bytes(headers,c,1)) return -1; + break; + case OF_TYPE_FLAG_E12: + c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED12; + c[1]=(p->type>>4)&0xff; + if (ob_append_bytes(headers,c,2)) return -1; + break; + case OF_TYPE_FLAG_E20: + c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED20; + c[1]=(p->type>>4)&0xff; + c[2]=(p->type>>12)&0xff; + if (ob_append_bytes(headers,c,3)) return -1; + break; + default: + /* Don't know this type of frame */ + WHY("Asked for format frame with unknown TYPE_FLAG bits"); + return -1; + } + return 0; +} - unsigned char nexthop[SIDDIDFIELD_LEN+1]; + +int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) +{ + /* Convert a payload (frame) structure into a series of bytes. + Assumes that any encryption etc has already been done. + Will pick a next hop if one has not been chosen. + */ + + unsigned char c[64]; int nexthoplen=0; overlay_buffer *headers=ob_new(256); @@ -25,31 +56,55 @@ int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b) /* Build header */ int fail=0; - if (overlay_get_nexthop((unsigned char *)p->dst,nexthop,&nexthoplen)) fail++; - if (ob_append_bytes(headers,nexthop,nexthoplen)) fail++; + if (p->nexthop_address_status!=OA_RESOLVED) { + if (overlay_get_nexthop((unsigned char *)p->destination,p->nexthop,&nexthoplen)) fail++; + else p->nexthop_address_status=OA_RESOLVED; + } - /* XXX Can use shorter fields for different address types, and if we know that the next hop - knows a short-hand for the address. - XXX Need a prefix byte for the type of address being used. - BETTER - We just insist that the first byte of Curve25519 addresses be >0x0f, and use - the low numbers for special cases: - - */ - if (p->src[0]<0x10||p->dst[0]<0x10) { + if (p->source[0]<0x10||p->destination[0]<0x10||p->nexthop[0]<0x10) { // Make sure that addresses do not overload the special address spaces of 0x00*-0x0f* fail++; - return WHY("address begins with reserved value 0x00-0x0f"); + return WHY("one or more packet addresses begins with reserved value 0x00-0x0f"); } - if (ob_append_bytes(headers,(unsigned char *)p->src,SIDDIDFIELD_LEN)) fail++; - if (ob_append_bytes(headers,(unsigned char *)p->dst,SIDDIDFIELD_LEN)) fail++; - + + /* XXX Write fields in correct order */ + + /* Write out type field byte(s) */ + if (op_append_type(headers,p)) fail++; + + /* Write out TTL */ + c[0]=p->ttl; if (ob_append_bytes(headers,c,1)) fail++; + + /* Length. This is the fun part, because we cannot calculate how many bytes we need until + we have abbreviated the addresses, and the length encoding we use varies according to the + length encoded. The simple option of running the abbreviations twice won't work because + we rely on context for abbreviating the addresses. So we write it initially and then patch it + after. + */ + int max_len=((SID_SIZE+3)*3+headers->length+p->payloadlength); + ob_append_rfs(b,max_len); + + int addrs_len=b->length; + + /* Write out addresses as abbreviated as possible */ + overlay_abbreviate_append_address(b,p->nexthop); + overlay_abbreviate_set_most_recent_address(p->nexthop); + overlay_abbreviate_append_address(b,p->destination); + overlay_abbreviate_set_most_recent_address(p->destination); + overlay_abbreviate_append_address(b,p->source); + overlay_abbreviate_set_most_recent_address(p->source); + + addrs_len=b->length-addrs_len; + int actual_len=addrs_len+p->payloadlength; + ob_patch_rfs(b,actual_len); + if (fail) { ob_free(headers); return WHY("failure count was non-zero"); } /* Write payload format plus total length of header bits */ - if (ob_makespace(b,2+headers->length+p->payloadLength)) { + if (ob_makespace(b,2+headers->length+p->payloadlength)) { /* Not enough space free in output buffer */ ob_free(headers); return WHY("Could not make enough space free in output buffer"); @@ -57,11 +112,11 @@ int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b) /* Package up headers and payload */ ob_checkpoint(b); - if (ob_append_short(b,0x1000|(p->payloadLength+headers->length))) + if (ob_append_short(b,0x1000|(p->payloadlength+headers->length))) { fail++; WHY("could not append version and length bytes"); } if (ob_append_bytes(b,headers->bytes,headers->length)) { fail++; WHY("could not append header"); } - if (ob_append_bytes(b,p->payload,p->payloadLength)) + if (ob_append_bytes(b,p->payload,p->payloadlength)) { fail++; WHY("could not append payload"); } /* XXX SIGN &/or ENCRYPT */ @@ -71,14 +126,14 @@ int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b) if (fail) { ob_rewind(b); return WHY("failure count was non-zero"); } else return 0; } -overlay_payload *overlay_payload_unpackage(overlay_buffer *b) { +overlay_buffer *overlay_payload_unpackage(overlay_frame *b) { /* Extract the payload at the current location in the buffer. */ WHY("not implemented"); return NULL; } -int overlay_payload_enqueue(int q,overlay_payload *p) +int overlay_payload_enqueue(int q,overlay_frame *p) { /* Add payload p to queue q. */ @@ -86,7 +141,7 @@ int overlay_payload_enqueue(int q,overlay_payload *p) return WHY("not implemented"); } -int op_free(overlay_payload *p) +int op_free(overlay_frame *p) { if (!p) return WHY("Asked to free NULL"); if (p->prev&&p->prev->next==p) return WHY("p->prev->next still points here"); diff --git a/overlay_route.c b/overlay_route.c index 12032420..7ef91e01 100644 --- a/overlay_route.c +++ b/overlay_route.c @@ -4,3 +4,13 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *nexthoplen) { return WHY("Not implemented"); } + +int overlay_route_saw_selfannounce(overlay_frame *f) +{ + return WHY("Not implemented"); +} + +int overlay_route_saw_selfannounce_ack(overlay_frame *f) +{ + return WHY("Not implemented"); +}