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); }
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)); }
/* * 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); } }
/** * 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. } }
/** * 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); }