wiced_result_t wiced_tls_receive_packet( wiced_tcp_socket_t* socket, wiced_packet_t** packet, uint32_t timeout ) { wiced_result_t result; wiced_tls_context_t* context = &socket->tls_context->context; /* Check if we already have a record which should only happen if it was larger than a packet which means it's stored in the defragmentation buffer */ if ( context->current_record != NULL ) { wiced_assert( "Something wrong", (void*)context->current_record == context->defragmentation_buffer ); return tls_packetize_buffered_data( context, packet ); } else { tls_record_t* record; result = tls_get_next_record( context, &record, timeout, TLS_RECEIVE_PACKET_IF_NEEDED ); if ( result != WICED_SUCCESS ) { return result; } /* Check if this record has been defragmented */ if ( (void*)record == context->defragmentation_buffer ) { return tls_packetize_buffered_data( context, packet ); } else { tls_record_t* temp_record; uint8_t* packet_data; uint16_t length; uint16_t available; uint8_t* end_of_data; /* We have a pointer to the current record so we can move on */ tls_skip_current_record(context); /* Make sure we process every record in this packet */ end_of_data = record->message + htobe16( record->length ); while ( tls_get_next_record( context, &temp_record, timeout, TLS_AVOID_NEW_RECORD_PACKET_RECEIVE ) == TLS_SUCCESS ) { /* Make the record data contiguous with the previous record */ uint16_t temp_record_length = htobe16( temp_record->length ); end_of_data = MEMCAT( end_of_data, temp_record->message, temp_record_length ); record->length = htobe16( htobe16(record->length) + temp_record_length ); tls_skip_current_record( context ); } /* Set the packet start and end */ wiced_packet_get_data( (wiced_packet_t*)context->received_packet, 0, &packet_data, &length, &available ); tls_host_set_packet_start( context->received_packet, record->message ); wiced_packet_set_data_end( (wiced_packet_t*)context->received_packet, end_of_data ); *packet = (wiced_packet_t*)context->received_packet; context->received_packet = NULL; context->received_packet_length = 0; } } return WICED_SUCCESS; }
wiced_result_t wiced_tcp_stream_read_with_count( wiced_tcp_stream_t* tcp_stream, void* buffer, uint16_t buffer_length, uint32_t timeout, uint32_t* read_count ) { WICED_LINK_CHECK_TCP_SOCKET( tcp_stream->socket ); if ( read_count != NULL ) { *read_count = 0; } while ( buffer_length != 0 ) { uint16_t amount_to_read; uint16_t total_available; uint8_t* packet_data = NULL; uint16_t space_available = 0; /* Check if we don't have a packet */ if (tcp_stream->rx_packet == NULL) { wiced_result_t result; result = wiced_tcp_receive(tcp_stream->socket, &tcp_stream->rx_packet, timeout ); if ( result != WICED_TCPIP_SUCCESS) { if ( ( read_count != NULL ) && ( *read_count != 0 ) ) { result = WICED_TCPIP_SUCCESS; } return result; } } wiced_packet_get_data(tcp_stream->rx_packet, 0, &packet_data, &space_available, &total_available); /* Read data */ amount_to_read = MIN(buffer_length, space_available); buffer = MEMCAT((uint8_t*)buffer, packet_data, amount_to_read); if ( read_count != NULL ) { *read_count += amount_to_read; } /* Update buffer length */ buffer_length = (uint16_t)(buffer_length - amount_to_read); /* Check if we need a new packet */ if ( amount_to_read == space_available ) { wiced_packet_delete( tcp_stream->rx_packet ); tcp_stream->rx_packet = NULL; } else { /* Otherwise update the start of the data for the next read request */ wiced_packet_set_data_start(tcp_stream->rx_packet, packet_data + amount_to_read); } } return WICED_TCPIP_SUCCESS; }
/* * Flush any data not yet written */ tls_result_t ssl_flush_output( ssl_context *ssl, uint8_t* buffer, uint32_t length ) { if ( ssl->transport_protocol == TLS_TCP_TRANSPORT ) { if (ssl->outgoing_packet != NULL) { wiced_packet_set_data_end((wiced_packet_t*)ssl->outgoing_packet, buffer + length); tls_host_send_tcp_packet(ssl->send_context, ssl->outgoing_packet); ssl->outgoing_packet = NULL; ssl->out_buffer_size = 0; } else { uint16_t actual_packet_size; tls_packet_t* temp_packet; uint8_t* packet_buffer; uint8_t* data = buffer; while (length != 0) { uint16_t amount_to_copy; if ( wiced_packet_create_tcp( ssl->send_context, (uint16_t)length, (wiced_packet_t**) &temp_packet, &packet_buffer, &actual_packet_size ) != WICED_SUCCESS ) { tls_host_free(buffer); return 1; } if ( ssl->state == SSL_HANDSHAKE_OVER ) { /* this doesn't need the extra space for the encryption header that a normal TLS socket would use - remove it */ packet_buffer -= sizeof(tls_record_header_t); wiced_packet_set_data_start((wiced_packet_t*) temp_packet, packet_buffer); } amount_to_copy = (uint16_t) MIN(length, actual_packet_size); packet_buffer = MEMCAT(packet_buffer, data, amount_to_copy); data += amount_to_copy; length -= amount_to_copy; wiced_packet_set_data_end((wiced_packet_t*)temp_packet, packet_buffer ); tls_host_send_tcp_packet(ssl->send_context, temp_packet); } tls_host_free(buffer); } } #ifndef DISABLE_EAP_TLS else if ( ssl->transport_protocol == TLS_EAP_TRANSPORT ) { supplicant_host_send_eap_tls_fragments( (supplicant_workspace_t*) ssl->send_context, buffer, length ); ssl->out_buffer_size = 0; tls_host_free( buffer ); buffer = NULL; } #endif /* DISABLE_EAP_TLS */ return TLS_SUCCESS; }
wiced_result_t wiced_tcp_stream_write( wiced_tcp_stream_t* tcp_stream, const void* data, uint32_t data_length ) { wiced_assert("Bad args", tcp_stream != NULL); WICED_LINK_CHECK_TCP_SOCKET( tcp_stream->socket ); while ( data_length != 0 ) { uint16_t amount_to_write; /* Check if we don't have a packet */ if ( tcp_stream->tx_packet == NULL ) { wiced_result_t result; result = wiced_packet_create_tcp( tcp_stream->socket, (uint16_t) MIN( data_length, 0xffff ), &tcp_stream->tx_packet, &tcp_stream->tx_packet_data , &tcp_stream->tx_packet_space_available ); if ( result != WICED_TCPIP_SUCCESS ) { return result; } } /* Write data */ amount_to_write = (uint16_t) MIN( data_length, tcp_stream->tx_packet_space_available ); tcp_stream->tx_packet_data = MEMCAT( tcp_stream->tx_packet_data, data, amount_to_write ); /* Update variables */ data_length = (uint16_t)(data_length - amount_to_write); tcp_stream->tx_packet_space_available = (uint16_t) ( tcp_stream->tx_packet_space_available - amount_to_write ); data = (void*)((uint32_t)data + amount_to_write); /* Check if the packet is full */ if ( tcp_stream->tx_packet_space_available == 0 ) { wiced_result_t result; /* Send the packet */ wiced_packet_set_data_end( tcp_stream->tx_packet, (uint8_t*)tcp_stream->tx_packet_data ); result = wiced_tcp_send_packet( tcp_stream->socket, tcp_stream->tx_packet ); tcp_stream->tx_packet_data = NULL; tcp_stream->tx_packet_space_available = 0; if ( result != WICED_TCPIP_SUCCESS ) { wiced_packet_delete( tcp_stream->tx_packet ); tcp_stream->tx_packet = NULL; return result; } tcp_stream->tx_packet = NULL; } } return WICED_TCPIP_SUCCESS; }
wiced_result_t wiced_tcp_send_buffer( wiced_tcp_socket_t* socket, const void* buffer, uint16_t buffer_length ) { wiced_packet_t* packet = NULL; uint8_t* data_ptr = (uint8_t*)buffer; uint8_t* packet_data_ptr; uint16_t available_space; wiced_assert("Bad args", socket != NULL); WICED_LINK_CHECK_TCP_SOCKET( socket ); /* Create a packet, copy the data and send it off */ while ( buffer_length != 0 ) { uint16_t data_to_write; wiced_result_t result = wiced_packet_create_tcp( socket, buffer_length, &packet, &packet_data_ptr, &available_space ); if ( result != WICED_TCPIP_SUCCESS ) { return result; } /* Write data */ data_to_write = MIN(buffer_length, available_space); packet_data_ptr = MEMCAT(packet_data_ptr, data_ptr, data_to_write); wiced_packet_set_data_end( packet, packet_data_ptr ); /* Update variables */ data_ptr += data_to_write; buffer_length = (uint16_t) ( buffer_length - data_to_write ); available_space = (uint16_t) ( available_space - data_to_write ); result = wiced_tcp_send_packet( socket, packet ); if ( result != WICED_TCPIP_SUCCESS ) { wiced_packet_delete( packet ); return result; } } return WICED_TCPIP_SUCCESS; }
/* * Flush any data not yet written */ tls_result_t ssl_flush_output( ssl_context *ssl, uint8_t* buffer, uint32_t length ) { if (ssl->outgoing_packet != NULL) { wiced_packet_set_data_end((wiced_packet_t*)ssl->outgoing_packet, buffer + length); tls_host_send_packet(ssl->send_context, ssl->outgoing_packet); ssl->outgoing_packet = NULL; ssl->out_buffer_size = 0; } else { uint16_t actual_packet_size; tls_packet_t* temp_packet; uint8_t* packet_buffer; uint8_t* data = buffer; while (length != 0) { uint16_t amount_to_copy; if ( wiced_packet_create_tcp( ssl->send_context, (uint16_t)length, (wiced_packet_t**) &temp_packet, &packet_buffer, &actual_packet_size ) != WICED_SUCCESS ) { free(buffer); return 1; } amount_to_copy = (uint16_t) MIN(length, actual_packet_size); packet_buffer = MEMCAT(packet_buffer, data, amount_to_copy); data += amount_to_copy; length -= amount_to_copy; wiced_packet_set_data_end((wiced_packet_t*)temp_packet, packet_buffer ); tls_host_send_packet(ssl->send_context, temp_packet); } free(buffer); } return( 0 ); }
/** * Implements a very simple DHCP server. * * Server will always offer next available address to a DISCOVER command * Server will NAK any REQUEST command which is not requesting the next available address * Server will ACK any REQUEST command which is for the next available address, and then increment the next available address * * @param my_addr : local IP address for binding of server port. */ static void dhcp_thread( uint32_t thread_input ) { wiced_packet_t* received_packet; wiced_packet_t* transmit_packet; wiced_ip_address_t local_ip_address; wiced_ip_address_t netmask; uint32_t next_available_ip_addr; uint32_t ip_mask; uint32_t subnet; uint32_t netmask_htobe; char* option_ptr; wiced_dhcp_server_t* server = (wiced_dhcp_server_t*)thread_input; uint8_t subnet_mask_option_buff[] = { 1, 4, 0, 0, 0, 0 }; uint8_t server_ip_addr_option_buff[] = { 54, 4, 0, 0, 0, 0 }; uint32_t* server_ip_addr_ptr = (uint32_t*)&server_ip_addr_option_buff[2]; uint8_t wpad_option_buff[ 2 + sizeof(WPAD_SAMPLE_URL)-1 ] = { 252, sizeof(WPAD_SAMPLE_URL)-1 }; /* Save local IP address to be sent in DHCP packets */ wiced_ip_get_ipv4_address(server->interface, &local_ip_address); *server_ip_addr_ptr = htobe32( GET_IPV4_ADDRESS( local_ip_address ) ); /* Save the current netmask to be sent in DHCP packets as the 'subnet mask option' */ wiced_ip_get_netmask(server->interface, &netmask); netmask_htobe = htobe32( GET_IPV4_ADDRESS(netmask) ); memcpy(&subnet_mask_option_buff[2], &netmask_htobe, 4); /* Calculate the first available IP address which will be served - based on the netmask and the local IP */ ip_mask = ~( GET_IPV4_ADDRESS( netmask ) ); subnet = GET_IPV4_ADDRESS( local_ip_address ) & GET_IPV4_ADDRESS( netmask ); next_available_ip_addr = subnet | ( ( GET_IPV4_ADDRESS( local_ip_address ) + 1 ) & ip_mask ); /* Prepare the Web proxy auto discovery URL */ memcpy(&wpad_option_buff[2], WPAD_SAMPLE_URL, sizeof(WPAD_SAMPLE_URL)-1); ipv4_to_string( (char*)&wpad_option_buff[2 + 7], *server_ip_addr_ptr); /* Initialise the server quit flag */ server->quit = WICED_FALSE; /* Loop endlessly */ while ( server->quit == WICED_FALSE ) { uint16_t data_length; uint16_t available_data_length; dhcp_header_t* request_header; /* Sleep until data is received from socket. */ if ( wiced_udp_receive( &server->socket, &received_packet, WICED_WAIT_FOREVER ) != WICED_SUCCESS ) { continue; } /* Get a pointer to the data in the packet */ wiced_packet_get_data( received_packet, 0, (uint8_t**) &request_header, &data_length, &available_data_length ); /* Check DHCP command */ switch ( request_header->options[2] ) { case DHCPDISCOVER: { dhcp_header_t* reply_header; uint16_t available_space; wiced_mac_t client_mac_address; wiced_ip_address_t client_ip_address; uint32_t temp; /* Create reply packet */ if ( wiced_packet_create_udp( &server->socket, sizeof(dhcp_header_t), &transmit_packet, (uint8_t**) &reply_header, &available_space ) != WICED_SUCCESS ) { /* Cannot reply - release incoming packet */ wiced_packet_delete( received_packet ); break; } /* Copy in the DHCP header content from the received discover packet into the reply packet */ memcpy( reply_header, request_header, sizeof(dhcp_header_t) - sizeof(reply_header->options) ); /* Finished with the received discover packet - release it */ wiced_packet_delete( received_packet ); /* Now construct the OFFER response */ reply_header->opcode = BOOTP_OP_REPLY; /* Clear the DHCP options list */ memset( &reply_header->options, 0, sizeof( reply_header->options ) ); /* Record client MAC address */ memcpy( &client_mac_address, request_header->client_hardware_addr, sizeof( client_mac_address ) ); /* Check whether device is already cached */ if ( get_client_ip_address_from_cache( &client_mac_address, &client_ip_address ) != WICED_SUCCESS ) { /* Address not found in cache. Use next available IP address */ client_ip_address.version = WICED_IPV4; client_ip_address.ip.v4 = next_available_ip_addr; } /* Create the IP address for the Offer */ temp = htonl(client_ip_address.ip.v4); memcpy( reply_header->your_ip_addr, &temp, sizeof( temp ) ); /* Copy the magic DHCP number */ memcpy( reply_header->magic, dhcp_magic_cookie, 4 ); /* Add options */ option_ptr = (char *) &reply_header->options; option_ptr = MEMCAT( option_ptr, dhcp_offer_option_buff, 3 ); /* DHCP message type */ option_ptr = MEMCAT( option_ptr, server_ip_addr_option_buff, 6 ); /* Server identifier */ option_ptr = MEMCAT( option_ptr, lease_time_option_buff, 6 ); /* Lease Time */ option_ptr = MEMCAT( option_ptr, subnet_mask_option_buff, 6 ); /* Subnet Mask */ option_ptr = (char*)MEMCAT( option_ptr, wpad_option_buff, sizeof(wpad_option_buff) ); /* Web proxy auto discovery URL */ /* Copy the local IP into the Router & DNS server Options */ memcpy( option_ptr, server_ip_addr_option_buff, 6 ); /* Router (gateway) */ option_ptr[0] = 3; /* Router id */ option_ptr += 6; memcpy( option_ptr, server_ip_addr_option_buff, 6 ); /* DNS server */ option_ptr[0] = 6; /* DNS server id */ option_ptr += 6; option_ptr = MEMCAT( option_ptr, mtu_option_buff, 4 ); /* Interface MTU */ option_ptr[0] = (char) 0xff; /* end options */ option_ptr++; /* Send OFFER reply packet */ wiced_packet_set_data_end( transmit_packet, (uint8_t*) option_ptr ); if ( wiced_udp_send( &server->socket, WICED_IP_BROADCAST, IPPORT_DHCPC, transmit_packet ) != WICED_SUCCESS ) { wiced_packet_delete( transmit_packet ); } } break; case DHCPREQUEST: { /* REQUEST command - send back ACK or NAK */ uint32_t temp; uint32_t* server_id_req; dhcp_header_t* reply_header; uint16_t available_space; wiced_mac_t client_mac_address; wiced_ip_address_t given_ip_address; wiced_ip_address_t requested_ip_address; wiced_bool_t next_avail_ip_address_used = WICED_FALSE; /* Check that the REQUEST is for this server */ server_id_req = (uint32_t*) find_option( request_header, 54 ); if ( ( server_id_req != NULL ) && ( GET_IPV4_ADDRESS( local_ip_address ) != htobe32(*server_id_req) ) ) { break; /* Server ID does not match local IP address */ } /* Create reply packet */ if ( wiced_packet_create_udp( &server->socket, sizeof(dhcp_header_t), &transmit_packet, (uint8_t**) &reply_header, &available_space ) != WICED_SUCCESS ) { /* Cannot reply - release incoming packet */ wiced_packet_delete( received_packet ); break; } /* Copy in the DHCP header content from the received request packet into the reply packet */ memcpy( reply_header, request_header, sizeof(dhcp_header_t) - sizeof(reply_header->options) ); /* Record client MAC address */ memcpy( &client_mac_address, request_header->client_hardware_addr, sizeof( client_mac_address ) ); /* Locate the requested address in the options and keep requested address */ requested_ip_address.version = WICED_IPV4; requested_ip_address.ip.v4 = ntohl(*(uint32_t*)find_option( request_header, 50 )); /* Delete received packet. We don't need it anymore */ wiced_packet_delete( received_packet ); reply_header->opcode = BOOTP_OP_REPLY; /* Blank options list */ memset( &reply_header->options, 0, sizeof( reply_header->options ) ); /* Copy DHCP magic number into packet */ memcpy( reply_header->magic, dhcp_magic_cookie, 4 ); option_ptr = (char *) &reply_header->options; /* Check if device is cache. If it is, give the previous IP address. Otherwise give the next available IP address */ if ( get_client_ip_address_from_cache( &client_mac_address, &given_ip_address ) != WICED_SUCCESS ) { /* Address not found in cache. Use next available IP address */ next_avail_ip_address_used = WICED_TRUE; given_ip_address.version = WICED_IPV4; given_ip_address.ip.v4 = next_available_ip_addr; } /* Check if the requested IP address matches one we have assigned */ if ( memcmp( &requested_ip_address.ip.v4, &given_ip_address.ip.v4, sizeof( requested_ip_address.ip.v4 ) ) != 0 ) { /* Request is not for the assigned IP - force client to take next available IP by sending NAK */ /* Add appropriate options */ option_ptr = (char*)MEMCAT( option_ptr, dhcp_nak_option_buff, 3 ); /* DHCP message type */ option_ptr = (char*)MEMCAT( option_ptr, server_ip_addr_option_buff, 6 ); /* Server identifier */ memset( reply_header->your_ip_addr, 0, sizeof( reply_header->your_ip_addr ) ); /* Clear IP addr */ } else { /* Request is for next available IP */ /* Add appropriate options */ option_ptr = (char*)MEMCAT( option_ptr, dhcp_ack_option_buff, 3 ); /* DHCP message type */ option_ptr = (char*)MEMCAT( option_ptr, server_ip_addr_option_buff, 6 ); /* Server identifier */ option_ptr = (char*)MEMCAT( option_ptr, lease_time_option_buff, 6 ); /* Lease Time */ option_ptr = (char*)MEMCAT( option_ptr, subnet_mask_option_buff, 6 ); /* Subnet Mask */ option_ptr = (char*)MEMCAT( option_ptr, wpad_option_buff, sizeof(wpad_option_buff) ); /* Web proxy auto discovery URL */ /* Copy the local IP into the Router & DNS server Options */ memcpy( option_ptr, server_ip_addr_option_buff, 6 ); /* Router (gateway) */ option_ptr[0] = 3; /* Router id */ option_ptr += 6; memcpy( option_ptr, server_ip_addr_option_buff, 6 ); /* DNS server */ option_ptr[0] = 6; /* DNS server id */ option_ptr += 6; option_ptr = (char*)MEMCAT( option_ptr, mtu_option_buff, 4 ); /* Interface MTU */ /* Create the IP address for the Offer */ temp = htonl(given_ip_address.ip.v4); memcpy( reply_header->your_ip_addr, &temp, sizeof( temp ) ); /* Increment next available IP address only if not found in cache */ if ( next_avail_ip_address_used == WICED_TRUE ) { do { next_available_ip_addr = subnet | ( ( next_available_ip_addr + 1 ) & ip_mask ); } while ( next_available_ip_addr == GET_IPV4_ADDRESS(local_ip_address) ); } /* Cache client */ add_client_to_cache( &client_mac_address, &given_ip_address ); } option_ptr[0] = (char) 0xff; /* end options */ option_ptr++; /* Send reply packet */ wiced_packet_set_data_end( transmit_packet, (uint8_t*) option_ptr ); if ( wiced_udp_send( &server->socket, WICED_IP_BROADCAST, IPPORT_DHCPC, transmit_packet ) != WICED_SUCCESS ) { wiced_packet_delete( transmit_packet ); } } break; default: /* Unknown packet type - release received packet */ wiced_packet_delete( received_packet ); break; } } /* Server loop has exited due to quit flag */ /* Delete DHCP socket */ wiced_udp_delete_socket( &server->socket ); WICED_END_OF_CURRENT_THREAD( ); }