// duplicate the frame and queue it
int overlay_forward_payload(struct overlay_frame *f){
  f->ttl--;
  if (f->ttl<=0)
    return 0;
  
  if (debug&DEBUG_OVERLAYFRAMES)
    DEBUGF("Forwarding payload for %s, ttl=%d",
	  (f->destination?alloca_tohex_sid(f->destination->sid):"broadcast"),
	  f->ttl);

  /* Queue frame for dispatch.
   Don't forget to put packet in the correct queue based on type.
   (e.g., mesh management, voice, video, ordinary or opportunistic).
   
   But the really important bit is to clone the frame, since the
   structure we are looking at here must be left as is and returned
   to the caller to do as they please */	  
  struct overlay_frame *qf=op_dup(f);
  if (!qf) 
    return WHY("Could not clone frame for queuing");
  
  // TODO include priority in packet header
  int qn=OQ_ORDINARY;
  /* Make sure voice traffic gets priority */
  if ((qf->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
    qn=OQ_ISOCHRONOUS_VOICE;
    rhizome_saw_voice_traffic();
  }
  
  if (overlay_payload_enqueue(qn,qf)) {
    op_free(qf);
    return WHY("failed to enqueue forwarded payload");
  }
  
  return 0;
}
Exemple #2
0
int overlay_send_probe(struct subscriber *peer, struct sockaddr_in addr, overlay_interface *interface, int queue){
  if (interface==NULL)
    interface = overlay_interface_find(addr.sin_addr, 1);
  
  if (!interface)
    return WHY("I don't know which interface to use");
  
  if (interface->state!=INTERFACE_STATE_UP)
    return WHY("I can't send a probe if the interface is down.");
  
  // don't send a unicast probe unless its on the same interface that is already known to be reachable
  if (peer && peer->reachable & REACHABLE_INDIRECT)
    return -1;
  if (peer && (peer->reachable & REACHABLE_DIRECT) && peer->interface && peer->interface != interface)
    return -1;

    if (addr.sin_addr.s_addr==0) {
      if (config.debug.overlayinterfaces) 
	DEBUG("I can't send a probe to address 0.0.0.0");
      return -1;
    }
    if (addr.sin_port==0) {
      if (config.debug.overlayinterfaces) 
	DEBUG("I can't send a probe to port 0");
      return -1;
    }
  
  // never send unicast probes over a stream interface
  if (interface->socket_type==SOCK_STREAM)
    return 0;
  
  time_ms_t now = gettime_ms();
  
  if (peer && peer->last_probe+1000>now)
    return -1;
  
  struct overlay_frame *frame=malloc(sizeof(struct overlay_frame));
  bzero(frame,sizeof(struct overlay_frame));
  frame->type=OF_TYPE_DATA;
  frame->source = my_subscriber;
  frame->next_hop = frame->destination = peer;
  frame->ttl=1;
  frame->queue=queue;
  frame->destination_resolved=1;
  frame->recvaddr=addr;
  frame->unicast=1;
  frame->interface=interface;
  frame->payload = ob_new();
  frame->source_full = 1;
  // TODO call mdp payload encryption / signing without calling overlay_mdp_dispatch...
  
  if (peer)
    peer->last_probe=gettime_ms();
  
  if (overlay_mdp_encode_ports(frame->payload, MDP_PORT_ECHO, MDP_PORT_PROBE)){
    op_free(frame);
    return -1;
  }
  // not worried about byte order here as we are the only node that should be parsing the contents.
  unsigned char *dst=ob_append_space(frame->payload, sizeof(struct probe_contents));
  if (!dst){
    op_free(frame);
    return -1;
  }
  struct probe_contents probe;
  probe.addr=addr;
  // get interface number
  probe.interface = interface - overlay_interfaces;
  bcopy(&probe, dst, sizeof(struct probe_contents));
  if (overlay_payload_enqueue(frame)){
    op_free(frame);
    return -1;
  }
  if (config.debug.overlayrouting)
    DEBUGF("Queued probe packet on interface %s to %s:%d for %s", 
	 interface->name, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), peer?alloca_tohex_sid(peer->sid):"ANY");
  return 0;
}
Exemple #3
0
/* Construct MDP packet frame from overlay_mdp_frame structure
   (need to add return address from bindings list, and copy
   payload etc).
   This is for use by the SERVER. 
   Clients should use overlay_mdp_send()
 */
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
			 struct sockaddr_un *recvaddr,int recvaddrlen)
{
  IN();

  /* Prepare the overlay frame for dispatch */
  struct overlay_frame *frame = calloc(1,sizeof(struct overlay_frame));
  if (!frame)
    FATAL("Couldn't allocate frame buffer");
  
  if (is_sid_any(mdp->out.src.sid)){
    /* set source to ourselves */
    frame->source = my_subscriber;
    bcopy(frame->source->sid, mdp->out.src.sid, SID_SIZE);
  }else if (is_sid_broadcast(mdp->out.src.sid)){
    /* This is rather naughty if it happens, since broadcasting a
     response can lead to all manner of nasty things.
     Picture a packet with broadcast as the source address, sent
     to, say, the MDP echo port on another node, and with a source
     port also of the echo port.  Said echo will get multiplied many,
     many, many times over before the TTL finally reaches zero.
     So we just say no to any packet with a broadcast source address. 
     (Of course we have other layers of protection against such 
     shenanigens, such as using BPIs to smart-flood broadcasts, but
     security comes through depth.)
     */
    op_free(frame);
    RETURN(WHY("Packet had broadcast address as source address"));
  }else{
    // assume all local identities have already been unlocked and marked as SELF.
    frame->source = find_subscriber(mdp->out.src.sid, SID_SIZE, 0);
    if (!frame->source){
      op_free(frame);
      RETURN(WHYF("Possible spoofing attempt, tried to send a packet from %s, which is an unknown SID", alloca_tohex_sid(mdp->out.src.sid)));
    }
    if (frame->source->reachable!=REACHABLE_SELF){
      op_free(frame);
      RETURN(WHYF("Possible spoofing attempt, tried to send a packet from %s", alloca_tohex_sid(mdp->out.src.sid)));
    }
  }
  
  /* Work out if destination is broadcast or not */
  if (overlay_mdp_check_binding(frame->source, mdp->out.src.port, userGeneratedFrameP,
				recvaddr, recvaddrlen)){
    op_free(frame);
    RETURN(overlay_mdp_reply_error
	   (mdp_named.poll.fd,
	    (struct sockaddr_un *)recvaddr,
	    recvaddrlen,8,
	    "Source address is invalid (you must bind to a source address before"
	    " you can send packets"));
  }
  
  if (is_sid_broadcast(mdp->out.dst.sid)){
    /* broadcast packets cannot be encrypted, so complain if MDP_NOCRYPT
     flag is not set. Also, MDP_NOSIGN must also be applied, until
     NaCl cryptobox keys can be used for signing. */	
    if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT)){
      op_free(frame);
      RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
				     recvaddr,recvaddrlen,5,
				     "Broadcast packets cannot be encrypted "));
    }
    overlay_broadcast_generate_address(&frame->broadcast_id);
    frame->destination = NULL;
  }else{
    frame->destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
  }
  
  frame->ttl = mdp->out.ttl;
  if (frame->ttl == 0) 
    frame->ttl = PAYLOAD_TTL_DEFAULT;
  else if (frame->ttl > PAYLOAD_TTL_MAX) {
    op_free(frame);
    RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
				    recvaddr,recvaddrlen,9,
				    "TTL out of range"));
  }
  
  if (!frame->destination || frame->destination->reachable == REACHABLE_SELF)
    {
      /* Packet is addressed such that we should process it. */
      overlay_saw_mdp_frame(NULL,mdp,gettime_ms());
      if (frame->destination) {
	/* Is local, and is not broadcast, so shouldn't get sent out
	   on the wire. */
	op_free(frame);
	RETURN(0);
      }
    }
  
  frame->type=OF_TYPE_DATA;
  frame->prev=NULL;
  frame->next=NULL;
  struct overlay_buffer *plaintext=ob_new();
  
  if (overlay_mdp_encode_ports(plaintext, mdp->out.dst.port, mdp->out.src.port)){
    ob_free(plaintext);
    RETURN (-1);
  }
  
  if (ob_append_bytes(plaintext, mdp->out.payload, mdp->out.payload_length)){
    ob_free(plaintext);
    RETURN(-1);
  }
  
  /* Work out the disposition of the frame->  For now we are only worried
     about the crypto matters, and not compression that may be applied
     before encryption (since applying it after is useless as ciphered
     text should have maximum entropy). */
  switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) {
  case 0: /* crypted and signed (using CryptoBox authcryption primitive) */
    frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
    {
      int nm=crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES;
      int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
      int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
      int cz=crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES;
      
      /* generate plain message with zero bytes and get ready to cipher it */
      int cipher_len=ob_position(plaintext);
      
      // TODO, add support for leading zero's in overlay_buffer's, then we don't need to copy the plain text again.
      unsigned char plain[zb+cipher_len];
      
      /* zero bytes */
      bzero(&plain[0],zb);
      bcopy(ob_ptr(plaintext),&plain[zb],cipher_len);
      
      cipher_len+=zb;
      
      ob_free(plaintext);
      
      frame->payload = ob_new();
      
      unsigned char *nonce = ob_append_space(frame->payload, nb+cipher_len);
      unsigned char *cipher_text = nonce + nb;
      if (!nonce)
	RETURN(-1);
      if (generate_nonce(nonce,nb)) {
	op_free(frame);
	RETURN(WHY("generate_nonce() failed to generate nonce"));
      }
      // reserve the high bit of the nonce as a flag for transmitting a shorter nonce.
      nonce[0]&=0x7f;
      
      /* get pre-computed PKxSK bytes (the slow part of auth-cryption that can be
	 retained and reused, and use that to do the encryption quickly. */
      unsigned char *k=keyring_get_nm_bytes(mdp->out.src.sid, mdp->out.dst.sid);
      if (!k) {
	op_free(frame);
	RETURN(WHY("could not compute Curve25519(NxM)")); 
      }
      /* Actually authcrypt the payload */
      if (crypto_box_curve25519xsalsa20poly1305_afternm
	  (cipher_text,plain,cipher_len,nonce,k)){
	op_free(frame);
	RETURN(WHY("crypto_box_afternm() failed")); 
      }
      if (0) {
	DEBUG("authcrypted mdp frame");
	dump("nm",k,nm);
	dump("plain text",plain,sizeof(plain));
	dump("nonce",nonce,nb);
	dump("cipher text",cipher_text,cipher_len);
      }
      /* now shuffle down to get rid of the temporary space that crypto_box
       uses. 
       TODO extend overlay buffer so we don't need this.
       */
      bcopy(&cipher_text[cz],&cipher_text[0],cipher_len-cz);
      frame->payload->position-=cz;
      if (0){
	dump("frame",&frame->payload->bytes[0],
	     frame->payload->position);
      }
    }
    break;
      
  case MDP_NOCRYPT: 
    /* Payload is sent unencrypted, but signed. */
    frame->modifiers=OF_CRYPTO_SIGNED;
    frame->payload = plaintext;
    ob_makespace(frame->payload,SIGNATURE_BYTES);
    if (crypto_sign_message(frame->source, frame->payload->bytes, frame->payload->allocSize, &frame->payload->position)){
      op_free(frame);
      RETURN(-1);
    }
    break;
      
  case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
    frame->modifiers=0; 
    frame->payload = plaintext;
    break;
  case MDP_NOSIGN: 
  default:
    /* ciphered, but not signed.
     This means we don't use CryptoBox, but rather a more compact means
     of representing the ciphered stream segment.
     */
    op_free(frame);
    RETURN(WHY("Not implemented"));
  }
  
  frame->queue=mdp->out.queue;
  if (frame->queue==0)
    frame->queue = OQ_ORDINARY;
  
  if (overlay_payload_enqueue(frame))
    op_free(frame);
  RETURN(0);
  OUT();
}
Exemple #4
0
/* Construct MDP packet frame from overlay_mdp_frame structure
   (need to add return address from bindings list, and copy
   payload etc).
   This is for use by the SERVER. 
   Clients should use overlay_mdp_send()
 */
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
			 struct sockaddr_un *recvaddr,int recvaddrlen)
{
  IN();

  /* Prepare the overlay frame for dispatch */
  struct overlay_frame *frame = calloc(1,sizeof(struct overlay_frame));
  if (!frame)
    FATAL("Couldn't allocate frame buffer");
  
  if (is_sid_any(mdp->out.src.sid)){
    /* set source to ourselves */
    frame->source = my_subscriber;
    bcopy(frame->source->sid, mdp->out.src.sid, SID_SIZE);
  }else if (is_broadcast(mdp->out.src.sid)){
    /* This is rather naughty if it happens, since broadcasting a
     response can lead to all manner of nasty things.
     Picture a packet with broadcast as the source address, sent
     to, say, the MDP echo port on another node, and with a source
     port also of the echo port.  Said echo will get multiplied many,
     many, many times over before the TTL finally reaches zero.
     So we just say no to any packet with a broadcast source address. 
     (Of course we have other layers of protection against such 
     shenanigens, such as using BPIs to smart-flood broadcasts, but
     security comes through depth.)
     */
    op_free(frame);
    RETURN(WHY("Packet had broadcast address as source address"));
  }else{
    // assume all local identities have already been unlocked and marked as SELF.
    frame->source = find_subscriber(mdp->out.src.sid, SID_SIZE, 0);
    if (!frame->source){
      op_free(frame);
      RETURN(WHYF("Possible spoofing attempt, tried to send a packet from %s, which is an unknown SID", alloca_tohex_sid(mdp->out.src.sid)));
    }
    if (frame->source->reachable!=REACHABLE_SELF){
      op_free(frame);
      RETURN(WHYF("Possible spoofing attempt, tried to send a packet from %s", alloca_tohex_sid(mdp->out.src.sid)));
    }
  }
  
  /* Work out if destination is broadcast or not */
  if (overlay_mdp_check_binding(frame->source, mdp->out.src.port, userGeneratedFrameP,
				recvaddr, recvaddrlen)){
    op_free(frame);
    RETURN(overlay_mdp_reply_error
	   (mdp_named.poll.fd,
	    (struct sockaddr_un *)recvaddr,
	    recvaddrlen,8,
	    "Source address is invalid (you must bind to a source address before"
	    " you can send packets"));
  }
  
  if (is_broadcast(mdp->out.dst.sid)){
    /* broadcast packets cannot be encrypted, so complain if MDP_NOCRYPT
     flag is not set. Also, MDP_NOSIGN must also be applied, until
     NaCl cryptobox keys can be used for signing. */	
    if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT)){
      op_free(frame);
      RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
				     recvaddr,recvaddrlen,5,
				     "Broadcast packets cannot be encrypted "));
    }
    overlay_broadcast_generate_address(&frame->broadcast_id);
    frame->destination = NULL;
  }else{
    frame->destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
  }
  frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */	
  
  if (!frame->destination || frame->destination->reachable == REACHABLE_SELF)
    {
      /* Packet is addressed such that we should process it. */
      overlay_saw_mdp_frame(mdp,gettime_ms());
      if (frame->destination) {
	/* Is local, and is not broadcast, so shouldn't get sent out
	   on the wire. */
	op_free(frame);
	RETURN(0);
      }
    }
  
  /* give voice packets priority */
  if (mdp->out.dst.port==MDP_PORT_VOMP) frame->type=OF_TYPE_DATA_VOICE;
  else frame->type=OF_TYPE_DATA;
  frame->prev=NULL;
  frame->next=NULL;
  frame->payload=ob_new();
  
  int fe=0;

  /* Work out the disposition of the frame->  For now we are only worried
     about the crypto matters, and not compression that may be applied
     before encryption (since applying it after is useless as ciphered
     text should have maximum entropy). */
  switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) {
  case 0: /* crypted and signed (using CryptoBox authcryption primitive) */
    frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
    /* Prepare payload */
    ob_makespace(frame->payload, 
	   1 // frame type (MDP)
	  +1 // MDP version 
	  +4 // dst port 
	  +4 // src port 
	  +crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
	  +crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
	  +mdp->out.payload_length);
    {
      /* write cryptobox nonce */
      unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
      if (urandombytes(nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)) {
	op_free(frame);
	RETURN(WHY("urandombytes() failed to generate nonce"));
      }
      fe|= ob_append_bytes(frame->payload,nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
      /* generate plain message with zero bytes and get ready to cipher it */
      unsigned char plain[crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
			  +10+mdp->out.payload_length];
      /* zero bytes */
      int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
      bzero(&plain[0],zb);
      /* MDP version 1 */
      plain[zb+0]=0x01; 
      plain[zb+1]=0x01;
      /* Ports */
      plain[zb+2]=(mdp->out.src.port>>24)&0xff;
      plain[zb+3]=(mdp->out.src.port>>16)&0xff;
      plain[zb+4]=(mdp->out.src.port>>8)&0xff;
      plain[zb+5]=(mdp->out.src.port>>0)&0xff;
      plain[zb+6]=(mdp->out.dst.port>>24)&0xff;
      plain[zb+7]=(mdp->out.dst.port>>16)&0xff;
      plain[zb+8]=(mdp->out.dst.port>>8)&0xff;
      plain[zb+9]=(mdp->out.dst.port>>0)&0xff;
      /* payload */
      bcopy(&mdp->out.payload,&plain[zb+10],mdp->out.payload_length);
      int cipher_len=zb+10+mdp->out.payload_length;
      
      /* get pre-computed PKxSK bytes (the slow part of auth-cryption that can be
	 retained and reused, and use that to do the encryption quickly. */
      unsigned char *k=keyring_get_nm_bytes(&mdp->out.src,&mdp->out.dst);
      if (!k) {
	op_free(frame);
	RETURN(WHY("could not compute Curve25519(NxM)")); 
      }
      /* Get pointer to place in frame where the ciphered text needs to go */
      int cipher_offset=frame->payload->position;
      unsigned char *cipher_text=ob_append_space(frame->payload,cipher_len);
      if (fe||(!cipher_text)){
	op_free(frame);
	RETURN(WHY("could not make space for ciphered text")); 
      }
      /* Actually authcrypt the payload */
      if (crypto_box_curve25519xsalsa20poly1305_afternm
	  (cipher_text,plain,cipher_len,nonce,k)){
	op_free(frame);
	RETURN(WHY("crypto_box_afternm() failed")); 
      }
      /* now shuffle down 16 bytes to get rid of the temporary space that crypto_box
	 uses. */
      bcopy(&cipher_text[16],&cipher_text[0],cipher_len-16);
      frame->payload->position-=16;
      if (0) {
	DEBUG("authcrypted mdp frame");
	dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES);
	dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
	dump("plain text",&plain[16],cipher_len-16);
	dump("cipher text",cipher_text,cipher_len-16);	
	DEBUGF("frame->payload->length=%d,cipher_len-16=%d,cipher_offset=%d", frame->payload->position,cipher_len-16,cipher_offset);
	dump("frame",&frame->payload->bytes[0],
	     frame->payload->position);
      }
    }
    break;
  case MDP_NOCRYPT: 
    /* Payload is sent unencrypted, but signed.

       To save space we do a trick where we hash the payload, and get the 
       signature of that, but do not send the hash itself, since that can
       be reproduced (and indeed must be for verification) at the receiver's
       end.

       As the signing key is implicit, and the hash is also implicit, we can
       chop out part of the signature and thus save some bytes.
    */
    frame->modifiers=OF_CRYPTO_SIGNED; 
    /* Prepare payload */
    ob_makespace(frame->payload,
	1 // frame type (MDP) 
	+1 // MDP version 
	+4 // dst port 
	+4 // src port 
	+crypto_sign_edwards25519sha512batch_BYTES
	+mdp->out.payload_length);
    {
      unsigned char *key=keyring_find_sas_private(keyring, frame->source->sid, NULL);
      if (!key) {
	op_free(frame);
	RETURN(WHY("could not find signing key"));
      }
      
      /* Build plain-text that includes header and hash it so that
         we can sign that hash. */
      unsigned char hash[crypto_hash_sha512_BYTES];
      int plain_len = 10+mdp->out.payload_length;
      unsigned char *plain = frame->payload->bytes + frame->payload->position;
      
      if (!plain)
	return WHY("Unable to allocate space for payload and signature");
      
      /* MDP version 1 */
      ob_append_byte(frame->payload,0x01);
      ob_append_byte(frame->payload,0x01);
      /* Destination port */
      ob_append_ui32(frame->payload,mdp->out.src.port);
      ob_append_ui32(frame->payload,mdp->out.dst.port);
      ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
      
      /* now hash it */
      crypto_hash_sha512(hash,plain,plain_len);
      
      unsigned char signature[crypto_hash_sha512_BYTES
			      +crypto_sign_edwards25519sha512batch_BYTES];
      unsigned long long  sig_len=0;
      crypto_sign_edwards25519sha512batch(signature,&sig_len,
					  hash,crypto_hash_sha512_BYTES,
					  key);
      if (!sig_len) {
	op_free(frame);
	RETURN(WHY("Signing MDP frame failed"));
      }
      
      if (0){
	dump("payload", plain, plain_len);
	dump("signature", signature, sizeof(signature));
      }
      /* chop hash out of middle of signature since it has to be recomputed
	 at the far end, anyway, and ammend the two halves of the signature. */
      ob_append_bytes(frame->payload,&signature[0],32);
      ob_append_bytes(frame->payload,&signature[32+crypto_hash_sha512_BYTES],32);
    }
    break;
  case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
    frame->modifiers=0; 
    /* Copy payload body in */
    ob_makespace(frame->payload, 
	   1 // frame type (MDP) 
	  +1 // MDP version 
	  +4 // dst port 
	  +4 // src port 
	  +mdp->out.payload_length);
    /* MDP version 1 */
    ob_append_byte(frame->payload,0x01);
    ob_append_byte(frame->payload,0x01);
    /* Destination port */
    ob_append_ui32(frame->payload,mdp->out.src.port);
    ob_append_ui32(frame->payload,mdp->out.dst.port);
    ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
    break;
  case MDP_NOSIGN: 
  default:
    /* ciphered, but not signed.
     This means we don't use CryptoBox, but rather a more compact means
     of representing the ciphered stream segment.
     */
    op_free(frame);
    RETURN(WHY("Not implemented"));
    break;
  }
  
  // TODO include priority in packet header
  int qn=OQ_ORDINARY;
  /* Make sure voice traffic gets priority */
  if ((frame->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
    qn=OQ_ISOCHRONOUS_VOICE;
    rhizome_saw_voice_traffic();
  }
  
  frame->send_copies = mdp->out.send_copies;
  
  if (overlay_payload_enqueue(qn, frame))
    op_free(frame);
  RETURN(0);
}
Exemple #5
0
int overlay_route_ack_selfannounce(overlay_frame *f,overlay_neighbour *n)
{
  /* Acknowledge the receipt of a self-announcement of an immediate neighbour.
     We could acknowledge immediately, but that requires the transmission of an
     extra packet with all the overhead that entails.  However, there is no real
     need to send the ack out immediately.  It should be entirely reasonable to 
     send the ack out with the next interface tick. 

     So we can craft the ack and submit it to the queue. As the next-hop will get
     determined at TX time, this will ensure that we send the packet out on the 
     right interface to reach the originator of the self-assessment.

     So all we need to do is craft the payload and put it onto the queue for 
     OVERLAY_MESH_MANAGEMENT messages.

     Also, we should check for older such frames on the queue and drop them.

     There is one caveat to the above:  until the first selfannounce gets returned,
     we don't have an open route.  Thus we need to just make sure that the ack
     goes out broadcast if we don't know about a return path. Once the return path
     starts getting built, it should be fine.

   */

  /* XXX Allocate overlay_frame structure and populate it */
  overlay_frame *out=NULL;
  out=calloc(sizeof(overlay_frame),1);
  if (!out) return WHY("calloc() failed to allocate an overlay frame");

  out->type=OF_TYPE_SELFANNOUNCE_ACK;
  out->modifiers=0;
  out->ttl=6; /* maximum time to live for an ack taking an indirect route back
		 to the originator.  If it were 1, then we would not be able to
		 handle mono-directional links (which WiFi is notorious for).
	         XXX 6 is quite an arbitrary selection however. */

  /* Set destination of ack to source of observed frame */
  if (overlay_frame_set_neighbour_as_destination(out,n)) {
    op_free(out);
    return WHY("overlay_frame_set_neighbour_as_source() failed");
  }


  /* set source to ourselves */
  overlay_frame_set_me_as_source(out);
  /* Next-hop will get set at TX time, so no need to set it here.
     However, if there is no known next-hop for this node (because the return path
     has not yet begun to be built), then we need to set the nexthop to broadcast. */
  out->nexthop_address_status=OA_UNINITIALISED;
  { unsigned char nexthop[SID_SIZE]; int nexthoplen,interface;
    if (overlay_get_nexthop(out->destination,nexthop,&nexthoplen,&interface))
      {
	/* No path, so set nexthop to be broadcast, but don't broadcast it too far. */
	int i;
	for(i=0;i<SID_SIZE;i++) out->nexthop[i]=0xff;
	out->nexthop_address_status=OA_RESOLVED;
	out->ttl=2;
	if (debug&DEBUG_OVERLAYROUTING) 
	  fprintf(stderr,"Broadcasting ack to selfannounce");
      }
    else
      if (debug&DEBUG_OVERLAYROUTING)
	fprintf(stderr,"singlecasting ack to selfannounce via known route");
  }
  
  /* Set the time in the ack. Use the last sequence number we have seen
     from this neighbour, as that may be helpful information for that neighbour
     down the track.  My policy is to communicate that information which should
     be helpful for forming and maintaining the health of the mesh, as that way
     each node can in potentially implement a different mesh routing protocol,
     without breaking the wire protocol.  This makes over-the-air software updates
     much safer.

     Combining of adjacent observation reports may mean that the most recent
     observation is not the last one in the list, also the wrapping of the sequence
     numbers means we can't just take the highest-numbered sequence number.  
     So we need to take the observation which was most recently received.
  */
  out->payload=ob_new(4+32*2+1); /* will grow if it isn't big enough, but let's try to
				    avoid a realloc() if possible */

  int i;
  int best_obs_id=-1;
  long long best_obs_time=0;
  for(i=0;i<OVERLAY_MAX_OBSERVATIONS;i++) {
    if (n->observations[i].time_ms>best_obs_time) {
      best_obs_id=i;
      best_obs_time=n->observations[i].time_ms;
    }
  }
  /* Observation time is presented in seconds to save space in transit.
     This is used to base score decay on when the last ACTUAL FIRST-HAND was made,
     rather than when someone heard that someone else heard from the nodes third
     cousin's step-uncle's room-mate-in-law, twice removed. */
  ob_append_int(out->payload,n->observations[best_obs_id].s2/1000);

  /* The ack needs to contain the per-interface scores that we have built up
     for this neighbour.
     We expect that for most neighbours they will have many fewer than 32 interfaces,
     and even when they have multiple interfaces that we will only be able to hear
     them on one or a few. 

     So we will structure the format so that we use fewer bytes when fewer interfaces
     are involved.

     Probably the simplest is to put each non-zero score followed by it's interface.
     That way the whole list will be easy to parse, and as short as 3 bytes for a
     single interface.

     We could use the spare 2 bits at the top of the interface id to indicate
     multiple interfaces with same score? 
  */
  for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
    {
      /* Only include interfaces with score >0 */
      if (n->scores[i]) {
	ob_append_byte(out->payload,n->scores[i]);
	ob_append_byte(out->payload,i);
      }
    }
  /* Terminate list */
  ob_append_byte(out->payload,0);

  /* Add to queue */
  if (overlay_payload_enqueue(OQ_MESH_MANAGEMENT,out))
    {
      op_free(out);
      return WHY("overlay_payload_enqueue(self-announce ack) failed");
    }
  
  /* XXX Remove any stale versions (or should we just freshen, and forget making
     a new one, since it would be more efficient). */

  return 0;
}