void handle_tcp_syn_packet(ipv6_hdr_t *ipv6_header, tcp_hdr_t *tcp_header, socket_internal_t *tcp_socket) { msg_t m_send_tcp; if (tcp_socket->socket_values.tcp_control.state == TCP_LISTEN) { socket_internal_t *new_socket = new_tcp_queued_socket(ipv6_header, tcp_header); if (new_socket != NULL) { #ifdef TCP_HC update_tcp_hc_context(true, new_socket, tcp_header); #endif /* notify socket function destiny_socket_accept(..) that a new * connection request has arrived. No need to wait for an answer * because the server destiny_socket_accept() function isnt reading * from anything other than the queued sockets */ net_msg_send(&m_send_tcp, tcp_socket->recv_pid, 0, TCP_SYN); } else { printf("Dropped TCP SYN Message because an error occured while "\ "requesting a new queued socket!\n"); } } else { printf("Dropped TCP SYN Message because socket was not in state TCP_LISTEN!"); } }
void tcp_packet_handler(void) { msg_t m_recv_ip, m_send_ip; ipv6_hdr_t *ipv6_header; tcp_hdr_t *tcp_header; uint8_t *payload; socket_internal_t *tcp_socket = NULL; uint16_t chksum; while (1) { msg_receive(&m_recv_ip); ipv6_header = ((ipv6_hdr_t *)m_recv_ip.content.ptr); tcp_header = ((tcp_hdr_t *)(m_recv_ip.content.ptr + IPV6_HDR_LEN)); #ifdef TCP_HC tcp_socket = decompress_tcp_packet(ipv6_header); #else switch_tcp_packet_byte_order(tcp_header); tcp_socket = get_tcp_socket(ipv6_header, tcp_header); #endif chksum = tcp_csum(ipv6_header, tcp_header); payload = (uint8_t *)(m_recv_ip.content.ptr + IPV6_HDR_LEN + tcp_header->data_offset * 4); if ((chksum == 0xffff) && (tcp_socket != NULL)) { #ifdef TCP_HC update_tcp_hc_context(true, tcp_socket, tcp_header); #endif /* Remove reserved bits from tcp flags field */ uint8_t tcp_flags = tcp_header->reserved_flags; switch (tcp_flags) { case TCP_ACK: { /* only ACK Bit set */ uint8_t tcp_payload_len = NTOHS(ipv6_header->length) - TCP_HDR_LEN; uint8_t state = tcp_socket->socket_values.tcp_control.state; if ((tcp_payload_len > 0) && (state == TCP_ESTABLISHED)) { /* handle data segments only when the connection was established successfully */ handle_tcp_no_flags_packet(ipv6_header, tcp_header, tcp_socket, payload, tcp_payload_len); } else if (tcp_payload_len == 0 && (state == TCP_ESTABLISHED || state == TCP_SYN_RCVD || state == TCP_CLOSING || state == TCP_LAST_ACK)) { /* no payload, acknowledging data only */ handle_tcp_ack_packet(ipv6_header, tcp_header, tcp_socket); } break; } case TCP_RST: { printf("RST Bit set!\n"); /* only RST Bit set */ handle_tcp_rst_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_SYN: { /* only SYN Bit set, look for matching, listening socket * and request new queued socket */ printf("SYN Bit set!\n"); handle_tcp_syn_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_SYN_ACK: { /* only SYN and ACK Bit set, complete three way handshake * when socket in state TCP_SYN_SENT */ handle_tcp_syn_ack_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_FIN_ACK: { if (tcp_socket->socket_values.tcp_control.state == TCP_ESTABLISHED) { /* this is the first FIN */ printf("FIN ACK Bit set!\n"); handle_tcp_fin_packet(ipv6_header, tcp_header, tcp_socket); } else { /* this is the response to FIN */ handle_tcp_fin_ack_packet(ipv6_header, tcp_header, tcp_socket); } break; } default: { printf("Unable to process the incoming segment!\n"); } } } else { printf("Wrong checksum (%x) or no corresponding socket found!\n", chksum); printArrayRange(((uint8_t *)ipv6_header), IPV6_HDR_LEN + NTOHS(ipv6_header->length), "Incoming"); print_tcp_status(INC_PACKET, ipv6_header, tcp_header, &tcp_socket->socket_values); } msg_reply(&m_recv_ip, &m_send_ip); } }
uint16_t compress_tcp_packet(socket_internal_t *current_socket, uint8_t *current_tcp_packet, ipv6_hdr_t *temp_ipv6_header, uint8_t flags, uint8_t payload_length) { socket_t *current_tcp_socket = ¤t_socket->socket_values; tcp_hc_context_t *tcp_context = ¤t_tcp_socket->tcp_control.tcp_context; tcp_cb_t *tcp_cb = ¤t_tcp_socket->tcp_control; tcp_hdr_t full_tcp_header; uint16_t packet_size = 0; /* Connection establisment phase, use FULL_HEADER TCP */ if (tcp_context->hc_type == FULL_HEADER) { /* draft-aayadi-6lowpan-tcphc-01: 5.1 Full header TCP segment. * Establishing Connection */ /* Move tcp packet 3 bytes to add padding and Context ID */ memmove(current_tcp_packet + 3, current_tcp_packet, ((((tcp_hdr_t *)current_tcp_packet)->data_offset) * 4) + payload_length); /* 1 padding byte with value 0x01 to introduce full header TCP_HC * segment */ memset(current_tcp_packet, 0x01, 1); /* Adding Context ID */ uint16_t current_context = HTONS(tcp_context->context_id); memcpy(current_tcp_packet + 1, ¤t_context, 2); /* Return correct header length (+3) */ packet_size = ((((tcp_hdr_t *)(current_tcp_packet + 3))->data_offset) * 4) + 3 + payload_length; /* Update the tcp context fields */ update_tcp_hc_context(false, current_socket, (tcp_hdr_t *)(current_tcp_packet + 3)); /* Convert TCP packet to network byte order */ switch_tcp_packet_byte_order((tcp_hdr_t *)(current_tcp_packet + 3)); return packet_size; } /* Check for header compression type: COMPRESSED_HEADER */ else if (tcp_context->hc_type == COMPRESSED_HEADER) { /* draft-aayadi-6lowpan-tcphc-01: 5.1 Compressed header TCP segment. */ /* Temporary variable for TCP_HC_Header Bytes */ uint16_t tcp_hc_header = 0x0000; /* Save TCP_Header to refresh TCP Context values after compressing the * packet */ memcpy(&full_tcp_header, current_tcp_packet, TCP_HDR_LEN); /* Temporary variable for storing TCP header beginning */ uint8_t *tcp_packet_begin = current_tcp_packet; /* Position for first TCP header value, TCP_HC_Header and Context ID */ current_tcp_packet += 4; /* Packet size value */ packet_size += 4; /* 5.2. LOWPAN_TCPHC Format */ /* First 3 bits of TCP_HC_Header are not exactly specified. In this * implementation they are (1|1|0) * for compressed headers and the * CID is always 16 bits (1) */ /* (1|1|0|1) = D */ tcp_hc_header |= 0xD000; /*----------------------------------*/ /*| Sequence number handling |*/ /*----------------------------------*/ if (full_tcp_header.seq_nr == tcp_context->seq_snd) { /* Nothing to do, Seq = (0|0) */ } /* If the 24 most significant bits haven't changed from previous * packet, don't transmit them */ else if ((full_tcp_header.seq_nr & 0xFFFFFF00) == (tcp_context->seq_snd & 0xFFFFFF00)) { /* Seq = (0|1) */ tcp_hc_header |= 0x0400; /* Copy first 8 less significant bits of sequence number into * buffer */ *current_tcp_packet = (uint8_t)(full_tcp_header.seq_nr & 0x000000FF); current_tcp_packet += 1; packet_size += 1; } /* If the 16 most significant bits haven't changed from previous packet, * don't transmit them */ else if ((full_tcp_header.seq_nr & 0xFFFF0000) == (tcp_context->seq_snd & 0xFFFF0000)) { /* Seq = (1|0) */ tcp_hc_header |= 0x0800; /* Copy first 16 less significant bits of sequence number into buffer */ *((uint16_t *)current_tcp_packet) = HTONS((uint16_t)(full_tcp_header.seq_nr & 0x0000FFFF)); current_tcp_packet += 2; packet_size += 2; } /* Sending uncompressed sequence number */ else { /* Seq = (1|1) */ tcp_hc_header |= 0x0C00; /* Copy all bits of sequence number into buffer */ uint32_t cur_seq_no = HTONL(full_tcp_header.seq_nr); memcpy(current_tcp_packet, &cur_seq_no, 4); current_tcp_packet += 4; packet_size += 4; } /*----------------------------------*/ /*| Acknowledgment number handling |*/ /*----------------------------------*/ if ((IS_TCP_ACK(full_tcp_header.reserved_flags) && (tcp_cb->tcp_context.ack_snd == full_tcp_header.ack_nr))) { tcp_context->ack_snd = tcp_context->seq_rcv; } if (full_tcp_header.ack_nr == tcp_context->ack_snd) { /* Nothing to do, Ack = (0|0) */ } /* If the 24 most significant bits haven't changed from previous packet, * don't transmit them */ else if ((full_tcp_header.ack_nr & 0xFFFFFF00) == (tcp_context->ack_snd & 0xFFFFFF00)) { /* Ack = (0|1) */ tcp_hc_header |= 0x0100; /* Copy first 8 less significant bits of acknowledgment number into * buffer */ *current_tcp_packet = (uint8_t)(full_tcp_header.ack_nr & 0x000000FF); current_tcp_packet += 1; packet_size += 1; } /* If the 16 most significant bits haven't changed from previous packet, * don't transmit them */ else if ((full_tcp_header.ack_nr & 0xFFFF0000) == (tcp_context->ack_snd & 0xFFFF0000)) { /* Ack = (1|0) */ tcp_hc_header |= 0x0200; /* Copy first 16 less significant bits of acknowledgment number * into buffer */ *((uint16_t *)current_tcp_packet) = HTONS((uint16_t)(full_tcp_header.ack_nr & 0x0000FFFF)); current_tcp_packet += 2; packet_size += 2; } /* Sending uncompressed acknowledgment number */ else { /* Ack = (1|1) */ tcp_hc_header |= 0x0300; /* Copy all bits of acknowledgment number into buffer */ uint32_t cur_ack_nr = HTONL(full_tcp_header.ack_nr); memcpy(current_tcp_packet, &cur_ack_nr, 4); current_tcp_packet += 4; packet_size += 4; } /*----------------------------------*/ /*| Window handling |*/ /*----------------------------------*/ if (full_tcp_header.window == tcp_context->wnd_snd) { /* Nothing to do, Wnd = (0|0) */ } /* If the 8 most significant bits haven't changed from previous packet, * don't transmit them */ else if ((full_tcp_header.window & 0xFF00) == (tcp_context->wnd_snd & 0xFF00)) { /* Wnd = (0|1) */ tcp_hc_header |= 0x0040; /* Copy first 8 less significant bits of window size into buffer */ *current_tcp_packet = (uint8_t)(full_tcp_header.window & 0x00FF); current_tcp_packet += 1; packet_size += 1; } /* If the 8 less significant bits haven't changed from previous packet, * don't transmit them */ else if ((full_tcp_header.window & 0x00FF) == (tcp_context->wnd_snd & 0x00FF)) { /* Wnd = (1|0) */ tcp_hc_header |= 0x0080; /* Copy first 8 most significant bits of window size into buffer */ *current_tcp_packet = (uint8_t)(full_tcp_header.window & 0xFF00); current_tcp_packet += 1; packet_size += 1; } /* Sending uncompressed window */ else { /* Wnd = (1|1) */ tcp_hc_header |= 0x00C0; /* Copy all bits of window size into buffer */ uint16_t cur_window = HTONS(full_tcp_header.window); memcpy(current_tcp_packet, &cur_window, 2); current_tcp_packet += 2; packet_size += 2; } /* FIN flag */ if (IS_TCP_FIN(full_tcp_header.reserved_flags)) { /* F = (1) */ tcp_hc_header |= 0x0008; } /* Copy checksum into buffer */ uint16_t cur_chk_sum = HTONS(full_tcp_header.checksum); memcpy(current_tcp_packet, &cur_chk_sum, 2); current_tcp_packet += 2; packet_size += 2; /* Copy TCP_HC Bytes into buffer */ uint16_t cur_tcp_hc_header = HTONS(tcp_hc_header); memcpy(tcp_packet_begin, &cur_tcp_hc_header, 2); /* Copy TCP_HC Context ID into buffer */ uint16_t cur_context_id = HTONS(tcp_context->context_id); memcpy(tcp_packet_begin + 2, &cur_context_id, 2); /* Move payload to end of tcp header */ memmove(current_tcp_packet, tcp_packet_begin + TCP_HDR_LEN, payload_length); /* Adding TCP payload length to TCP_HC header length */ packet_size += payload_length; update_tcp_hc_context(false, current_socket, &full_tcp_header); return packet_size; } /* Check for header compression type: MOSTLY_COMPRESSED_HEADER */ else if (tcp_context->hc_type == MOSTLY_COMPRESSED_HEADER) { /* draft-aayadi-6lowpan-tcphc-01: 5.1 Compressed header TCP segment. */ /* Temporary variable for TCP_HC_Header Bytes */ uint16_t tcp_hc_header = 0x0000; /* Save TCP_Header to refresh TCP Context values after compressing the * packet */ memcpy(&full_tcp_header, current_tcp_packet, TCP_HDR_LEN); /* Temporary variable for storing TCP header beginning */ uint8_t *tcp_packet_begin = current_tcp_packet; /* Position for first TCP header value, TCP_HC_Header and Context ID */ current_tcp_packet += 4; /* Packet size value */ packet_size += 4; /* 5.2. LOWPAN_TCPHC Format */ /* First 3 bits of TCP_HC_Header are not exactly specified. In this * implementation they are (1|0|0) for mostly compressed headers and * the CID is always 16 bits (1) */ /* (1|0|0|1) = 9 */ tcp_hc_header |= 0x9000; /*----------------------------------*/ /*| Sequence number handling |*/ /*----------------------------------*/ /* Sending uncompressed sequence number */ /* Seq = (1|1) */ tcp_hc_header |= 0x0C00; /* Copy all bits of sequence number into buffer */ uint32_t cur_seq_no = HTONL(full_tcp_header.seq_nr); memcpy(current_tcp_packet, &cur_seq_no, 4); current_tcp_packet += 4; packet_size += 4; /*----------------------------------*/ /*| Acknowledgment number handling |*/ /*----------------------------------*/ /* Ack = (1|1) */ tcp_hc_header |= 0x0300; /* Copy all bits of acknowledgment number into buffer */ uint32_t cur_ack_nr = HTONL(full_tcp_header.ack_nr); memcpy(current_tcp_packet, &cur_ack_nr, 4); current_tcp_packet += 4; packet_size += 4; /*----------------------------------*/ /*| Window handling |*/ /*----------------------------------*/ /* Wnd = (1|1) */ tcp_hc_header |= 0x00C0; /* Copy all bits of window size into buffer */ uint16_t cur_window = HTONS(full_tcp_header.window); memcpy(current_tcp_packet, &cur_window, 2); current_tcp_packet += 2; packet_size += 2; /* FIN flag */ if (IS_TCP_FIN(full_tcp_header.reserved_flags)) { /* F = (1) */ tcp_hc_header |= 0x0008; } /* Copy checksum into buffer */ uint16_t cur_chk_sum = HTONS(full_tcp_header.checksum); memcpy(current_tcp_packet, &cur_chk_sum, 2); current_tcp_packet += 2; packet_size += 2; /* Copy TCP_HC Bytes into buffer */ uint16_t cur_tcp_hc_header = HTONS(tcp_hc_header); memcpy(tcp_packet_begin, &cur_tcp_hc_header, 2); /* Copy TCP_HC Context ID into buffer */ uint16_t cur_context_id = HTONS(tcp_context->context_id); memcpy(tcp_packet_begin + 2, &cur_context_id, 2); /* Move payload to end of tcp header */ memmove(current_tcp_packet, tcp_packet_begin + TCP_HDR_LEN, payload_length); /* Adding TCP payload length to TCP_HC header length */ packet_size += payload_length; update_tcp_hc_context(false, current_socket, &full_tcp_header); return packet_size; } return 0; }
void tcp_packet_handler(void) { msg_t m_recv_ip, m_send_ip; ipv6_hdr_t *ipv6_header; tcp_hdr_t *tcp_header; uint8_t *payload; socket_internal_t *tcp_socket = NULL; uint16_t chksum; while (1) { msg_receive(&m_recv_ip); ipv6_header = ((ipv6_hdr_t *)m_recv_ip.content.ptr); tcp_header = ((tcp_hdr_t *)(m_recv_ip.content.ptr + IPV6_HDR_LEN)); #ifdef TCP_HC tcp_socket = decompress_tcp_packet(ipv6_header); #else switch_tcp_packet_byte_order(tcp_header); tcp_socket = get_tcp_socket(ipv6_header, tcp_header); #endif chksum = tcp_csum(ipv6_header, tcp_header); payload = (uint8_t *)(m_recv_ip.content.ptr + IPV6_HDR_LEN + tcp_header->dataOffset_reserved * 4); if ((chksum == 0xffff) && (tcp_socket != NULL)) { #ifdef TCP_HC update_tcp_hc_context(true, tcp_socket, tcp_header); #endif /* Remove reserved bits from tcp flags field */ uint8_t tcp_flags = tcp_header->reserved_flags & REMOVE_RESERVED; switch(tcp_flags) { case TCP_ACK: { /* only ACK Bit set */ handle_tcp_ack_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_RST: { printf("RST Bit set!\n"); /* only RST Bit set */ handle_tcp_rst_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_SYN: { /* only SYN Bit set, look for matching, listening socket * and request new queued socket */ printf("SYN Bit set!\n"); handle_tcp_syn_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_SYN_ACK: { /* only SYN and ACK Bit set, complete three way handshake * when socket in state SYN_SENT */ handle_tcp_syn_ack_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_FIN: { printf("FIN Bit set!\n"); /* only FIN Bit set */ handle_tcp_fin_packet(ipv6_header, tcp_header, tcp_socket); break; } case TCP_FIN_ACK: { printf("FIN ACK Bit set!\n"); /* only FIN and ACK Bit set */ handle_tcp_fin_ack_packet(ipv6_header, tcp_header, tcp_socket); break; } default: { handle_tcp_no_flags_packet(ipv6_header, tcp_header, tcp_socket, payload); } } } else { printf("Wrong checksum (%x) or no corresponding socket found!\n", chksum); printArrayRange(((uint8_t *)ipv6_header), IPV6_HDR_LEN + ipv6_header->length, "Incoming"); print_tcp_status(INC_PACKET, ipv6_header, tcp_header, &tcp_socket->socket_values); } msg_reply(&m_recv_ip, &m_send_ip); } }