Beispiel #1
0
void l2_resend_on_timeout(link_entry_t *link, int sending_seq_nr) {
  char* l1buf;
  struct L2Header*  hdr_pointer;

  int buffer_index = sending_seq_nr % link->sending_buffer_size;

  int length = link->sending_buffer_length[buffer_index];
  char *buf = link->sending_buffer[buffer_index];

  l1buf = (char*) safe_malloc(length + sizeof(struct L2Header));
  memset(l1buf, 0, length + sizeof(struct L2Header));

  memcpy(&l1buf[sizeof(struct L2Header)], buf, length);
  
  hdr_pointer = (struct L2Header*) l1buf;
  hdr_pointer->src_mac_address = htonl(l2_get_local_mac_address());
  hdr_pointer->dst_mac_address = htonl(link->remote_mac_address);
  hdr_pointer->frame_type = 0x0;
  hdr_pointer->seq_nr = htonl(sending_seq_nr); 
  hdr_pointer->ack_nr = htonl(-1); // Do possible piggybacking here. For now, unused.
    
  l1_send(link->phys_device, l1buf, length + sizeof(struct L2Header));
  
  // Free the buf memory
  free(l1buf);
  
  // Restart timeout clock.
  start_clock(link, sending_seq_nr);
}
Beispiel #2
0
static int l2_send_nak(link_entry_t *link, int nak_nr) {
  char *l1buf;
  struct L2Header *header;

  l1buf = (char*) safe_malloc(sizeof(struct L2Header));

  header = (struct L2Header*) l1buf;
  header->src_mac_address = htonl(l2_get_local_mac_address());
  header->dst_mac_address = htonl(link->remote_mac_address);
  header->frame_type = 0x1;
  header->seq_nr = htonl(nak_nr);
  header->ack_nr = htonl(nak_nr);
  
  return l1_send(link->phys_device, l1buf, sizeof(struct L2Header));
}
Beispiel #3
0
/*
 * Called by layer 3, network, when it wants to send data to a
 * direct neighbour identified by the MAC address.
 * A positive return value means the number of bytes that have been
 * sent.
 * A negative return value means that an error has occured.
 *
 * NOTE:
 * You will need to split this function into many small helper
 * functions. In particular, you will need something that allows
 * you to perform retransmissions after a timeout.
 */
int l2_send( int dest_mac_addr, const char* buf, int length )
{
    int   device = -1;
    int   src_mac_addr = -1;
    char* l1buf;
    struct L2Header*  hdr_pointer;
    int   retval;
    int   i;

    for( i=0; i<MAX_ADDRESSES; i++ )
    {
        if( mac_to_device_map[i].remote_mac_address == dest_mac_addr )
        {
            device       = mac_to_device_map[i].phys_device;
            src_mac_addr = i;
            break;
        }
    }
    if( i==MAX_ADDRESSES )
    {
        fprintf( stderr, "MAC address not found in l2_send" );
        return -1;
    }

    l1buf = (char*)malloc( length+sizeof(struct L2Header) );
    if( l1buf == 0 )
    {
        fprintf( stderr, "Not enough memory in l2_send\n" );
        return -1;
    }

    memcpy( &l1buf[sizeof(struct L2Header)], buf, length );

    hdr_pointer = (struct L2Header*)l1buf;
    hdr_pointer->src_mac_address = htonl(src_mac_addr);
    hdr_pointer->dst_mac_address = htonl(dest_mac_addr);

    retval = l1_send( device, l1buf, length+sizeof(struct L2Header) );
    free(l1buf);
    if( retval < 0 )
    {
        return -1;
    }
    else
    {
        return retval-sizeof(struct L2Header);
    }
}
Beispiel #4
0
/**
 * Called by layer 1 - physical, when a frame has arrived.
 *
 * This function has no return value. It must handle all
 * problems itself because the physical layer isn't able
 * to handle errors.
 *
 * NOTE:
 * Link layer error correction and flow control must be considered
 * here. You will certainly need several helper functions because
 * you will need to perform retransmissions after a timeout.
 */
void l2_recv( int device, const char* buf, int length ) {

  const struct L2Header* hdr_pointer;
  const char* l3buf;
  int src_mac_address;
  int dst_mac_address;
  int seq_nr;
  int ack_nr;
  unsigned char frame_type;
  int err;
  
  hdr_pointer = (const struct L2Header*)buf;
  src_mac_address  = ntohl(hdr_pointer->src_mac_address);
  dst_mac_address  = ntohl(hdr_pointer->dst_mac_address);
  seq_nr = ntohl(hdr_pointer->seq_nr);
  ack_nr = ntohl(hdr_pointer->ack_nr);
  frame_type = hdr_pointer->frame_type;
   
  link_entry_t *link;
  // Lookup the link
  int   i;
  for(i = 0; i < MAX_ADDRESSES; i++) {
    if(mac_to_device_map[i].phys_device == device) {
      link = &mac_to_device_map[i];
      break;
    }
  }
  if(i == MAX_ADDRESSES) {
    fprintf( stderr, "MAC address not found in l2_send\n" );
    return;
  }   

  // Determine what kind of frame this is
  if(frame_type == 0x0) { // Normal data frame
    
    // Check if it's a ACK frame first.
    if(seq_nr == -1) {
      
      while(ack_nr >= link->sending_ack_nr) {
        // Stop timer & free buffers
        int buffer_index = link->sending_ack_nr % link->sending_buffer_size;
        
        stop_clock(link, link->sending_ack_nr);
        
        free(link->sending_buffer[buffer_index]);
        link->sending_buffer[buffer_index] = NULL;
        link->sending_buffer_length[buffer_index] = 0;

        increment_seq_nr(&link->sending_ack_nr);
      }      
      // It is safe to return here, since we don't use piggybacking
      return;
    }else if(seq_nr >= link->receive_ack && seq_nr <= link->receive_seq_nr) {
      // Seq_nr in window range.
      if(link->receiving == false) {
        // Initiate buffer and set receiving to true
        link->receive_buffer = safe_malloc(link->receive_buffer_size * sizeof(char*));
        link->receive_buffer_length = safe_malloc(link->receive_buffer_size * sizeof(int));

        memset(link->receive_buffer, 0, 
               link->receive_buffer_size * sizeof(char*)); // Set pointers to 0
        int i;
        for(i = 0; i < link->receive_buffer_size; i++) {
          link->receive_buffer_length[i] = 0;
        }

        link->sent_nak = safe_malloc(link->receive_buffer_size);
        if(link->receive_buffer == 0) {
          fprintf(stderr, "Not enough memory in l2_recv\n");
          return;
        }
        link->receiving = true;
      }
      // Put it in the buffer if it's not allready there.
      l3buf = buf + sizeof(struct L2Header);
      int l3buf_length = length - sizeof(struct L2Header);
      int buffer_index = seq_nr % link->receive_buffer_size;
      
      if(link->receive_buffer[buffer_index] == NULL) {
        link->receive_buffer[buffer_index] = safe_malloc(l3buf_length);
        memcpy(link->receive_buffer[buffer_index], l3buf, l3buf_length);
        
        link->receive_buffer_length[buffer_index] = l3buf_length; // The length of the buf 
      }
      
      buffer_index = link->receive_ack % link->receive_buffer_size;
      if(seq_nr > link->receive_ack && link->sent_nak[buffer_index] == false) { // Send NAK
        l2_send_nak(link, link->receive_ack);
        link->sent_nak[buffer_index] = true;

        return;
      }else if(seq_nr < link->receive_ack) {// If the seq_nr is older than the oldest excpected.
        l2_send_ack(link, link->receive_ack - 1);
        return;
      
      }else {
        int ack = seq_nr;
        boolean delivered = false;
        int buffer_index = link->receive_ack % link->receive_buffer_size;
        
        while(link->receive_buffer[buffer_index] != NULL && 
              link->receive_buffer_length[buffer_index] > sizeof(struct L2Header)) {
          // Try to deliver it to l3
          
          l3buf = link->receive_buffer[buffer_index];
          
          err = l3_recv(dst_mac_address, l3buf, link->receive_buffer_length[buffer_index]);
          if(err <= 0) {
            break;
          }else if(err > 0) {
            // Succsessfull delivery
            int buffer_index = link->receive_ack % link->receive_buffer_size;
            
            free(link->receive_buffer[buffer_index]);
            link->receive_buffer[buffer_index] = NULL;
            link->sent_nak[buffer_index] = false;
            link->receive_buffer_length[buffer_index] = 0;

            // Increment the seq_nr's
            increment_seq_nr(&link->receive_ack);
            increment_seq_nr(&link->receive_seq_nr);
            
            ack = link->receive_ack;
            delivered = true;
          }
        }
        if(delivered) {
          l2_send_ack(link, ack - 1);
          return;
        }else 
          return;
      }
    }       
  }else if(frame_type == 0x1) { // NAK frame
    // Send frame & restart timer
    struct L2Header *header;
    int buffer_index = seq_nr % link->sending_buffer_size;
    char *buf = link->sending_buffer[buffer_index];
    
    int total_size = link->sending_buffer_length[buffer_index] + sizeof(struct L2Header);
    
    char *l1buf = safe_malloc(total_size);
    memcpy(&l1buf[sizeof(struct L2Header)], buf, sizeof(buf));
    
    header = (struct L2Header*) l1buf;
    header->src_mac_address = htonl(l2_get_local_mac_address());
    header->dst_mac_address = htonl(src_mac_address);
    header->frame_type = 0x0;
    header->seq_nr = htonl(seq_nr);
    header->ack_nr = htonl(-1);
    
    l1_send(link->phys_device, l1buf, total_size);
    return;
    
  }else if(frame_type == 0x2) { // Buffer change alert-frame
    // Unused for now.
  }else if(frame_type == 0x3) { // Transmission finished frame
    // Unused for now.
  }
}
Beispiel #5
0
/**
 * Called by layer 3 - network, when it wants to send data to a
 * direct neighbour identified by the MAC address.
 * A positive return value means the number of bytes that have been
 * sent.
 * A negative return value means that an error has occured.
 *
 * NOTE:
 * You will need to split this function into many small helper
 * functions. In particular, you will need something that allows
 * you to perform retransmissions after a timeout.
 */
int l2_send( int dest_mac_addr, const char* buf, int length ) {

  link_entry_t *link;
  int src_mac_addr;
  
  int   i;
  for( i=0; i<MAX_ADDRESSES; i++ ) {
    if( mac_to_device_map[i].remote_mac_address == dest_mac_addr ) {
      link = &mac_to_device_map[i];
      src_mac_addr = l2_get_local_mac_address();
      break;
    }
  }
  if( i==MAX_ADDRESSES ) {
    fprintf( stderr, "MAC address not found in l2_send\n" );
    return -1;
  }

  //adjust the size of the buf if it is too big to fit in a frame
  if(length + sizeof(struct L2Header) > FRAME_MAX_SIZE) {
    length = FRAME_MAX_SIZE - sizeof(struct L2Header);
  }

  // Check if the link is "sending", and if not, alloc buffer space
  // and set it to "sending"
  if(link->sending == false) {
    link->sending_buffer = (char**) safe_malloc(link->sending_buffer_size * sizeof(char*));
    link->sending_buffer_length = (int*) safe_malloc(link->sending_buffer_size * sizeof(int));

    memset(link->sending_buffer, 0, link->sending_buffer_size * sizeof(char*)); // Set pointers to 0
    int i;
    for(i = 0; i < link->receive_buffer_size; i++) {
      link->sending_buffer_length[i] = 0;
    }
    link->sending = true;
  }
  
  /**
   * Check the linkentry for opening in the gliding window.
   * if there is, send the next frame, if theres not, return 0
   */
  if(link->sending_seq_nr - link->sending_ack_nr >= link->sending_buffer_size) {
    fprintf(stderr, "There is no more room in the reciever's gliding window.\n");
    return 0;
  }

  // Store the buf in the window
  int buffer_index = link->sending_seq_nr % link->sending_buffer_size;
  
  if(link->sending_buffer != NULL && link->sending_buffer[buffer_index] == NULL) {
    link->sending_buffer[buffer_index] = (char*) safe_malloc(length);
    memcpy(link->sending_buffer[buffer_index], buf, length);
    link->sending_buffer_length[buffer_index] = length;
  }

  char* l1buf;
  struct L2Header*  hdr_pointer;
  
  //fprintf(stderr, "Before l1buf malloc\n");
  //fprintf(stderr, "Trying to allocate: %d bytes.\n",length + sizeof(struct L2Header));
  l1buf = (char*) safe_malloc(length + sizeof(struct L2Header));
  memset(l1buf, 0, length + sizeof(struct L2Header));
  //fprintf(stderr, "After l1buf malloc\n");
  
  memcpy(&l1buf[sizeof(struct L2Header)], buf, length);
  
  hdr_pointer = (struct L2Header*) l1buf;
  hdr_pointer->src_mac_address = htonl(src_mac_addr);
  hdr_pointer->dst_mac_address = htonl(dest_mac_addr);
  hdr_pointer->frame_type = 0x0;
  hdr_pointer->seq_nr = htonl(link->sending_seq_nr); 
  hdr_pointer->ack_nr = htonl(-1); // Do possible piggybacking here. For now, unused.
    
  int retval = l1_send(link->phys_device, l1buf, length + sizeof(struct L2Header));
  free(l1buf);
  
  if(retval <= 0) {
    return -1;
  }

  // Turn on timeout timer.
  start_clock(link, link->sending_seq_nr);    
  increment_seq_nr(&link->sending_seq_nr);  // Increment the seq_nr
  
  return retval - sizeof(struct L2Header);
}