Beispiel #1
0
static void raw_send(const char *str, int payload_len) {
    uint16_t c;
    int len = 8 /* udp header */ + payload_len;

    /* IPv6 header → length */
    uip_buf[19] = len;

    /* UDP header → length */
    uip_buf[59] = len;

    /* initialize UDP checksum to zero */
    uip_buf[60] = 0x00;
    uip_buf[61] = 0x00;

    for (c = 0; c < payload_len; c++)
        uip_buf[62 + c] = str[c];

    /* calculate UDP checksum */
    uint16_t sum = 0;
    sum = len + 17;
    sum = chksum(sum, (uint8_t*)&uip_buf[22], 2 * 16);
    sum = chksum(sum, &uip_buf[54], len);
    sum = (sum == 0 ? 0xffff : ~sum);
    if (sum == 0)
        sum = 0xffff;

    uip_buf[60] = (sum & 0xFF00) >> 8;
    uip_buf[61] = (sum & 0x00FF);

    uip_len = 62 + payload_len;
    transmit_packet();
}
Beispiel #2
0
/*
 * this function is always called with interrupts off
 * this function also assumes that there is space to send in the Emaclite buffer
 */
static err_t
_unbuffered_low_level_output(XEmacLite *instancep, struct pbuf *p)
{
	struct pbuf *q;
	int total_len = 0;

#if ETH_PAD_SIZE
	pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */
#endif

	for(q = p, total_len = 0; q != NULL; q = q->next) {
		/* Send the data from the pbuf to the interface, one pbuf at a
		   time. The size of the data in each pbuf is kept in the ->len
		   variable. */
		memcpy(xemac_tx_frame + total_len, q->payload, q->len);
		total_len += q->len;
	}

	if (transmit_packet(instancep, xemac_tx_frame, total_len) < 0) {
#if LINK_STATS
		lwip_stats.link.drop++;
#endif
	}

#if ETH_PAD_SIZE
	pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */
#endif

#if LINK_STATS
	lwip_stats.link.xmit++;
#endif /* LINK_STATS */

	return ERR_OK;
}
Beispiel #3
0
/*  
Spoof Limit Checking: There is a known issue with the Vsense values, but 
we should at least get the framework set up for limit checking on arbitrary values.
The power board should have upper and lower limits for vsense and csense data, 
and turn off components if their voltage/current is too high. ONLY CHECKS
BATTERY 1 VOLTAGE LINE RIGHT NOW.
*/
void limit_check( void ) {
	unsigned char sw;
	SVIT_t *component;

	// turn off all switches and send ack_command w/ value of SAFE_MODE
	if (percent < SAFE_MODE) {
		safe_mode = 1;
		for (sw = 0; sw < sizeof(components); sw++) {
			component = &svit[components[sw]];
			switch_off( component->switch_num );
			component->switch_state = SW_OFF;
		}
		component = &svit[TORQUER_1];
		component->switch_state = SW_OFF;
		component = &svit[TORQUER_2];
		component->switch_state = SW_OFF;
		component = &svit[TORQUER_3];
		component->switch_state = SW_OFF;
		torquer_off(TORQUER_1);
		torquer_off(TORQUER_2);
		torquer_off(TORQUER_3);
		// Only transmit once
		if (!transmit_safe && !been_to_safe) { 
			transmit_packet( 0, VCP_ACK, SAFE_MODE);
			transmit_safe = 1;
		}
		else {}
		been_to_safe = 1;
		transmit_safe = 1;
	}
	else if (percent > SHUNT_MODE) {
	    safe_mode = 0;
		// turn on the maestro and send ack_command w/ value of SHUNT_MODE
		component = &svit[MAESTRO];
		switch_on( component->switch_num );
		component->switch_state = SW_ON;
		// Only transmit once
		if (!transmit_shunt && !been_to_shunt) {
			transmit_packet( 0, VCP_ACK, SHUNT_MODE);
		}
		else {}	
		been_to_shunt = 1;
		transmit_shunt = 1;	
	}
	else {} // To avoid annoying compile warning 
}
Beispiel #4
0
//Destroys minisockets
void minisocket_destroy(minisocket_t minisocket, int FIN) {
	int portNumber;
	int i, threads;
	interrupt_level_t prev_level;
	minisocket_error error;

	if (minisocket == NULL)
		return;

	portNumber = minisocket->port_number;

	semaphore_P(destroy_semaphore);

	minisocket->waiting = TCP_PORT_WAITING_TO_CLOSE;

	if (minisockets[portNumber] == NULL)
		return;

	semaphore_V(minisocket->packet_ready);

	semaphore_P(minisocket->mutex);

	if (minisockets[portNumber] == NULL)
		return;

	if (FIN == 1) {
		transmit_packet(minisocket, minisocket->destination_addr, minisocket->destination_port,
				1, MSG_FIN, 0, NULL, &error);
	}

	minisocket->status = TCP_PORT_CLOSING;

	prev_level = set_interrupt_level(DISABLED);
	threads = minisocket->num_waiting_on_mutex;

	for (i = 0; i < threads; i++)
	{
		semaphore_V(minisocket->mutex);
		i++;
	}
	set_interrupt_level(prev_level);

	minisockets[portNumber] = NULL;

	semaphore_destroy(minisocket->wait_for_ack_semaphore);
	semaphore_destroy(minisocket->mutex);
	semaphore_destroy(minisocket->packet_ready);

	if (minisocket->data_length != 0)
		free(minisocket->data_buffer);

	queue_free(minisocket->waiting_packets);

	free(minisocket);

	semaphore_V(destroy_semaphore);
}
/*---------------------------------------------------------------------------*/
static int
radio_send(const void *payload, unsigned short payload_len)
{
	prepare_packet(payload, payload_len);
	transmit_packet(payload_len);

  return RADIO_TX_OK;

}
void test_transmission() {
    kprintf("Testing transmission...\n");
	uint8_t data[50];
	int i, j;

	for (i = 0; i < 50; i++) {
		data[i] = i;
	}

	for (i = 0; i < 18; i++) {
        kprintf("buf %x size %x\n", data, 50);
        transmit_packet(data, 50);
        for (j = 0; j < 50; j++)
            data[j] += 50;
	}
}
Beispiel #7
0
/*
 * Do the actual transmission of the packet. The packet is contained
 * in the pbuf that is passed to the function. This pbuf might be chained.
 * Return 1 when the packet is succesfully queued for transmission.
 * Or return 0 if the packet is lost.
 */
static bool_t eth_output(eth_t *u, buf_t *p, small_uint_t prio) {
	mutex_lock(&u->netif.lock);
	/* debug_printf("From tcp out\n"); */
	/* Exit if link has failed */
	if (p->tot_len < 4 || p->tot_len > ETH_MTU /*||
	 ! (phy_read (u, PHY_STS) & PHY_STS_LINK)*/) {
		++u->netif.out_errors;
		mutex_unlock(&u->netif.lock);
		/*debug_printf ("output: transmit %d bytes, link failed\n", p->tot_len);*/
		netif_free_buf (&u->netif, p);
		return 0;
	}
	/*debug_printf ("output: transmit %d bytes\n", p->tot_len);*/

	if (ARM_ETH->STAT & ARM_ETH_X_EMPTY) {
		/* Смело отсылаем. */
		transmit_packet(u, p);
		mutex_unlock(&u->netif.lock);
		netif_free_buf (&u->netif, p);
		return 1;
	}

	/* Занято, ставим в очередь. */
	/*if (buf_queue_is_full(&u->outq)) {
	 // Нет места в очереди: теряем пакет.
	 ++u->netif.out_discards;
	 ++u->out_full_buf;
	 mutex_unlock(&u->netif.lock);
	 buf_free(p);
	 return 0;
	 }*/
	while (buf_queue_is_full(&u->outq))
		asm volatile ("nop;");
	buf_queue_put(&u->outq, p);
	mutex_unlock(&u->netif.lock);
	return 1;
}
Beispiel #8
0
/*
 * Kick the watchdog.
 * This is done by sending a heartbeat message to the board controller watchdog 
 * through drbcc-core.
 */
static int wd_keepalive(void) 
{
	int ret;

	struct bcc_packet pkt = {
		.cmd        =  DRBCC_REQ_HEARTBEAT,
		.payloadlen = 2,
	};

	pkt.data[0] = timeout >> 8;
	pkt.data[1] = timeout;

	DBGF(BWD "Send timeout to board controller (current timeout: %d).", timeout);

	if ((ret = transmit_packet(&pkt)) < 0) {
		ERR(BWD "Error while trying to send heartbeat to board controller.");
		return -EFAULT;
	}

	if(pkt.cmd != cmd_responses[DRBCC_REQ_HEARTBEAT]) {
		if(pkt.cmd == DRBCC_TIMEOUT) {
			DBG("Waiting for ACK for HEARTBEAT message timed out.");
		} else {
			DBGF("Received message with wrong response type: %x", pkt.cmd);
		}
		return -EFAULT;
	}

	return ret;
}

static void blocking_wd_keepalive_thread(struct work_struct *work)
{
	wd_keepalive();
	queue_delayed_work(timeout_keepalive_wq, &tm_work, WD_KEEPALIVE_TIME*HZ);
}
Beispiel #9
0
 void network_handler(network_interrupt_arg_t* arg)
{
	// Used to extract the network address out of the interrupt argument
	//network_address_t addr;

	// The source port number - this is really the remote unbound port number
	int src_port_number;

	// The port number the packet was sent to
	int dst_port_number;

	// Used to store the header data for UDP/minimsgs
	mini_header_t header;

	// This is used to extract the sender's address from the header
	network_address_t src_addr;

	// This is used to extract the destination (our) address from the header
	network_address_t dst_addr;

	// Disable interrupts...
	interrupt_level_t prev_level = set_interrupt_level(DISABLED);

	// This is used to check our own address for sanity checks
	network_address_t my_addr;

	// This will store the total packet size
	int packet_size;

	// This will store the size of the data in the packet
	int data_len;

	// This will store the header of a TCP packet
	mini_header_reliable_t header_reliable;

	// This will store the ACK number of a TCP packet
	int ack_num;

	// This will store the Sequence number of a TCP packet
	int seq_num;

	// This will store the socket
	minisocket_t socket;

	// This will store the TCP error
	minisocket_error error;

	// This will be used to indicate whether the TCP packet is a duplicate or not
	int duplicate = 0;

	// This will tell us if we need to free the arg or not
	int enqueued;

	// Used for general for loops
	int i;

	// Used to check if we've already broadcasted a route discovery req
	int* last_seen_req_id;

	// Used for various tasks
	network_address_t tmp_addr;
	network_address_t tmp_addr2;

	// Used to handle routing and discovery requests
	route_request_t route_request;
	int current_req_id;
	int path_len;
	int ttl; 

	// Get the buffer without the routing header
	char* buffer_without_routing = (char*) (arg->buffer + sizeof(struct routing_header));

	// Used to get the data buffer
	char* data_buffer;

	// Handle the mini route stuff

	// Extract the information from the routing header
	routing_header_t routing_header = (routing_header_t) arg->buffer;
	char routing_packet_type = routing_header->routing_packet_type;
	unpack_address(routing_header->destination, dst_addr);
	current_req_id = unpack_unsigned_int(routing_header->id);
	ttl = unpack_unsigned_int(routing_header->ttl);
	path_len = unpack_unsigned_int(routing_header->path_len);

	// Get the data buffer & data length
	switch(buffer_without_routing[0])
	{
		case (char) PROTOCOL_MINISTREAM:
			data_buffer = (char*) (buffer_without_routing + sizeof(struct mini_header_reliable));
			data_len = arg->size - sizeof(struct routing_header) - sizeof(struct mini_header_reliable);
			break;

		//default: todo: put this back in, but leave w/o it for testing
		case (char) PROTOCOL_MINIDATAGRAM:
			data_buffer = (char*) (buffer_without_routing + sizeof(struct mini_header));
			data_len = arg->size - sizeof(struct routing_header) - sizeof(struct mini_header);
			break;	
	}

	network_get_my_address(my_addr);
	//if (network_compare_network_addresses(my_addr, dst_addr) == 0 && ttl == 0)
	if (my_addr[0] != dst_addr[0] && ttl == 0)
	{
		free(arg);
		set_interrupt_level(prev_level);
		return;
	}

	switch (routing_packet_type)
	{
		// If this is a data packet
		case ROUTING_DATA:
			// If the data packet is meant for us, then break and let the higher
			// protocols get the data
			unpack_address(routing_header->path[path_len-1], tmp_addr);
			if (network_compare_network_addresses(my_addr, tmp_addr) != 0)
			{
				break;
			}
			 else
			{
				// If it's not meant for us, we must pass it along

				// Go through the path and find the next node
				for (i = 0; i < path_len; i++)
				{
					unpack_address(routing_header->path[i], tmp_addr);

					// If this node is us, break - the node we need to send to is next
					if (network_compare_network_addresses(tmp_addr, my_addr) != 0)
					{
						break;
					}
				}

				// If we're the last node (i == path_len-1) or we weren't found in it, quit
				if (i >= path_len - 1)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// Now we'll forward the packet by reusing the headers we have

				// Get the next host in the path and set it as the packet's dst
				unpack_address(routing_header->path[i+1], tmp_addr);
				pack_unsigned_int(routing_header->ttl, ttl - 1);

				// Send the packet onward in the route
				network_send_pkt(tmp_addr, arg->size - data_len, 
								(char*) arg->buffer, data_len, data_buffer);

				// Revert the header back (not entirely necessary)
				//pack_unsigned_int(routing_header->ttl, ttl);
			}

			free(arg);
			set_interrupt_level(prev_level);
			return;
			break;

		case ROUTING_ROUTE_DISCOVERY:
			// We're not the dst, so just forward this packet along
			//if (network_compare_network_addresses(my_addr, dst_addr) == 0)
			if (my_addr[0] != dst_addr[0])
			{
				// Check if we're in the path, if so, no need to send again (no loops)
				for (i = 0; i < path_len; i++)
				{
					unpack_address(routing_header->path[i], tmp_addr);
					if (network_compare_network_addresses(tmp_addr, my_addr) != 0)
					{
						break;
					}
				}

				// If we were in the path, return - no need to do anything else
				if (i < path_len) 
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// todo: this next part w/ the discovery packets seen is probably wrong...
				// also, lookup the "explain" part in my txt

				// todo: need something to clean up old discovery packets

				// Check if we've already seen this discovery request - if so, don't resend
				last_seen_req_id = (int*) hashmap_get(discovery_packets_seen, current_req_id);
				if (last_seen_req_id != NULL)
				{
					// If this exists, then we've already seen this packet - no need to resend
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// Now we'll rebroadcast the discovery packet by reusing the header we have

				// Modify the header as needed
				pack_unsigned_int(routing_header->path_len, path_len+1);
				pack_address(routing_header->path[path_len], my_addr);
				pack_unsigned_int(routing_header->ttl, ttl - 1);

				// Broadcast this packet
				network_bcast_pkt(arg->size - data_len, (char*) arg->buffer, data_len, data_buffer);

				// Revert the header - dont need to actually remove from route
				/*pack_unsigned_int(routing_header->path_len, path_len);
				pack_unsigned_int(routing_header->ttl, ttl);

				// update already broadcasted hashmap - just put a garbage ptr in 
				hashmap_insert(discovery_packets_seen, current_req_id, (void*) 0x555555);
				*/
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}
			 else
			{
				// If we were the host being sought, send a reply packet back
				// and ensure the higher protocols get the data sent

				// reverse the path so we can send a packet back to the host
				// Don't forget to add ourselves to the route
				path_len++;
				pack_unsigned_int(routing_header->path_len, path_len);
				pack_address(routing_header->path[path_len-1], my_addr);

				for (i = 0; i < path_len/2; i++)
				{
					unpack_address(routing_header->path[path_len-1-i], tmp_addr);
					unpack_address(routing_header->path[i], tmp_addr2);
					pack_address(routing_header->path[i], tmp_addr);
					pack_address(routing_header->path[path_len-1-i], tmp_addr2);
				}

				// We'll start sending the packet back now by reusing the header we have

				// Prepare the headers
				pack_unsigned_int(routing_header->ttl, MAX_ROUTE_LENGTH);
				routing_header->routing_packet_type = ROUTING_ROUTE_REPLY;

				// send a route reply packet, starting from the next host in the reversed route
				unpack_address(routing_header->path[1], tmp_addr);
				pack_address(routing_header->destination, tmp_addr);

				network_send_pkt(tmp_addr, arg->size - data_len, 
								(char*) arg->buffer, 0, NULL);				

				// Revert the header
				/*pack_unsigned_int(routing_header->ttl, ttl);
				routing_header->routing_packet_type = ROUTING_ROUTE_DISCOVERY;

				// Reverse the path back
				for (i = 0; i < path_len/2; i++)
				{
					unpack_address(routing_header->path[path_len-1-i], tmp_addr);
					unpack_address(routing_header->path[i], tmp_addr2);
					pack_address(routing_header->path[i], tmp_addr);
					pack_address(routing_header->path[path_len-1-i], tmp_addr);
				}
				*/
				// DONT return, ensure that the higher protocols will get the data
				// ^ never mind. return, it will send a data packet later.
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			break;

		case ROUTING_ROUTE_REPLY:
			unpack_address(routing_header->path[path_len-1], tmp_addr);

			// If we were the initiator of the request and just got our response
			//if (network_compare_network_addresses(my_addr, tmp_addr) != 0)
			if (my_addr[0] == tmp_addr[0])
			{
				// Get the addr of the host we were trying to discover
				unpack_address(routing_header->path[0], tmp_addr);

				// find the discovery request struct for this dst addr
				//route_request = (route_request_t) hashmap_get(current_discovery_requests, hash_address(tmp_addr));
			route_request = (route_request_t) hashmap_get(current_discovery_requests, tmp_addr[0]);
				if (route_request == NULL)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
					// it could be we already got this path
					break;
				}
				// Check if we already got this path, but miniroute_send_pkt() hasn't deleted the req struct yet
				if (route_request->interrupt_arg != NULL)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
					break;
				}

				route_request->interrupt_arg = arg;
				semaphore_V(route_request->initiator_sem);
				set_interrupt_level(prev_level);
				return;
			}
			 else
			{
				// Find the next node in the route

				for (i = 0; i < path_len; i++)
				{
					unpack_address(routing_header->path[i], tmp_addr);

					// Stop if we found ourselves - we need to send to the next node
					if (network_compare_network_addresses(tmp_addr, my_addr) != 0)
					{
						break;
					}
				}

				// If we were the last node OR not in the route at all
				if (i >= path_len - 1)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// We'll forward the reply along by reusing the header

				// Get the next host in the path and set it as the packet's dst
				unpack_address(routing_header->path[i+1], tmp_addr);
				pack_unsigned_int(routing_header->ttl, ttl - 1);
				pack_address(routing_header->destination, tmp_addr);

				// Send the packet onward in the route
				network_send_pkt(tmp_addr, arg->size - data_len, 
								(char*) arg->buffer, 0, NULL);

				// Make sure we set the header back
				//pack_unsigned_int(routing_header->ttl, ttl);
			}

			free(arg);
			set_interrupt_level(prev_level);
			return;
			break;
	}

	// If we're here, the packet was meant for us
	// The "normal" packet without the routing header is in buffer_without_routing

	// Adjust arg->size in case something uses it
	arg->size -= sizeof(struct routing_header);

	// Check the protocol
	switch (buffer_without_routing[0])
	{
		case (char) PROTOCOL_MINIDATAGRAM:

			// Extract data from the network interrupt arg
			//network_address_copy(arg->addr, addr);

			// Get the header struct, unpack the parameters
			header = (mini_header_t) buffer_without_routing; 
			dst_port_number = (int) unpack_unsigned_short(header->destination_port);

			// Ensure the port number is valid
			if (dst_port_number < MIN_UNBOUND || dst_port_number > MAX_UNBOUND)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Then ensure the miniport exists
			if (miniports[dst_port_number] == NULL)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Add the arg to the queue
			queue_append(miniports[dst_port_number]->port_data.unbound.data_queue, arg);

			// Wake up thread that's waiting to receive - sem_V()
			semaphore_V(miniports[dst_port_number]->port_data.unbound.data_ready);

			// Ensure the argument isn't free'd
			enqueued = 1;
			set_interrupt_level(prev_level);
			return;
			break;

		case PROTOCOL_MINISTREAM:
			// Get the total size of the packet and data length
			packet_size = arg->size;
			data_len = packet_size - sizeof(struct mini_header_reliable);

			// Get the header and extract information
			header_reliable = (mini_header_reliable_t) buffer_without_routing;
			src_port_number = (int) unpack_unsigned_short(header_reliable->source_port);
			dst_port_number = (int) unpack_unsigned_short(header_reliable->destination_port);
			unpack_address(header_reliable->source_address, src_addr);
			unpack_address(header_reliable->destination_address, dst_addr);
			seq_num = (int) unpack_unsigned_int(header_reliable->seq_number);
			ack_num = (int) unpack_unsigned_int(header_reliable->ack_number);

			// Don't respond if socket doesn't exist - will trigger SOCKET_NOSERVER for client
			if (minisockets[dst_port_number] == NULL)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Get the socket in question
			socket = minisockets[dst_port_number];

			// Check if packet was meant for us - ignore if not
			network_get_my_address(my_addr);
			if (network_compare_network_addresses(my_addr, dst_addr) == 0)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_CLOSE)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Packet handling for established connections
			if (socket->status != TCP_PORT_LISTENING)
			{
				// Ensure source address is correct - ignore if not
				if (network_compare_network_addresses(src_addr, socket->dst_addr) == 0 
					|| src_port_number != socket->dst_port)
				{
					if (header_reliable->message_type == MSG_SYN)
					{
						// A client is trying to connect to an already-connected port
						// Send them a FIN, which will result in their client
						// returning a SOCKET_BUSY error
						transmit_packet(socket, src_addr, src_port_number, 0, 
											MSG_FIN, 0, NULL, &error);
					}

					free(arg);
					set_interrupt_level(prev_level);
					return;
				}


				/* We got a duplicate SYN and need to ensure that the host gets
				 * another SYNACK. The thread that sent the SYNACK will currently
				 * be retransmitting the SYNACKs, as it didn't get an ACK. If it 
				 * was done with the retransmission sequence, the socket would be
				 * closed, and this would therefore not have gotten this far.
				 * HOWEVER:
				 * If the retransmission sequence already sent its LAST 
				 * retransmission and was waiting on it, then this duplicate SYN 
				 * will NOT get a SYNACK, as the retransmission is just waiting
				 * out the last alarm before it ends. Therefore, if this is the case,
				 * reset the timeout to the last timeout value so it sends just
				 * one more SYNACK.
				 *
				 * Professor Sirer mentioned that this isn't even necessary,
				 * but this does seem to make the code follow the specs more.
				 */
				if (header_reliable->message_type == MSG_SYN)
				{
					// If the timeout is at 6400, then it's the last transmission
					// but it hasn't been doubled yet. If it's 12800, it's just
					// been doubled. In each case we want to keep it at 6400 
					// at the end of the while loop, so we set the timeout to half
					// it's current value.
					if (socket->timeout >= 6400)
					{
						socket->timeout /= 2;
					}

					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// If we were trying to connect and got a FIN, that means the socket's busy
				if (socket->status == TCP_PORT_CONNECTING && header_reliable->message_type == MSG_FIN)
				{
					// Not connected, got a FIN - that means we couldnt start connection b/c it was busy
					// This will let the client function infer that
					socket->status = TCP_PORT_COULDNT_CONNECT;

					// Wake it up so it can end the retransmission sequence
					semaphore_V(socket->wait_for_ack_sem);

					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				/* Note: the code below handles ACKs. It also inherently deals with
				 * duplicate ACKs. We have a status code that indicates whether the socket
				 * is waiting for an ACK or not. If it's set and we get an ACK (or any 
				 * packet) with the right ACK number, we can process it. However, if our 
				 * status indicates we're NOT waiting for an ACK, we can infer from the
				 * fact that window_size = 1 that we already got the only ACK we could've
				 * been expecting, and this new one is therefore a duplicate. 
				 */

				// If we're waiting on an ACK
				if (socket->waiting == TCP_PORT_WAITING_ACK /*|| socket->waiting == TCP_PORT_WAITING_ACK_WAKING*/)
				{
					// This can be an ACK or really any other data packet, we just
					// need the ACK number
					if (ack_num == socket->seq_num)
					{
						// Update our status to show we're no longer waiting for an ACK
						socket->waiting = TCP_PORT_WAITING_NONE;

						// Wake up the thread waiting for the ACK
						semaphore_V(socket->wait_for_ack_sem);
					}
					 else if (ack_num == socket->seq_num - 1)
					{
						// This follows the same logic from the comment block around
						// line 170. 
						if (socket->timeout >= 6400)
						{
							socket->timeout /= 2;
						}	
					}
				}

				// If it's an ACK, it requires no further processing
				if (header_reliable->message_type == MSG_ACK && data_len == 0)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// Check if it's a SYNACK we're waiting for
				if (socket->waiting == TCP_PORT_WAITING_SYNACK && header_reliable->message_type == MSG_SYNACK)
				{
					// We're now fully connected in our eyes, handshake complete
					socket->waiting = TCP_PORT_WAITING_NONE;
					semaphore_V(socket->wait_for_ack_sem);
				}

				// If we're here, the packet isnt an ACK or SYN, so we should ACK it

				// First check if we should increment our ack number
				if (seq_num == socket->ack_num + 1)
				{
					socket->ack_num++;
				}
				 else
				{
					// It's a duplicate, don't add to queue
					duplicate = 1;
				}

				// Next, perform the ACK, don't incr the seq#
				transmit_packet(socket, socket->dst_addr, socket->dst_port, 
								0, MSG_ACK, 0, NULL, &error);	

				/* Note: the code below handles FINs, and is also protected against
				 * duplicate FINs inherently. The seq_num == ack_num check doesn't
				 * guarantee it's not a duplicate; however, if we process one FIN,
				 * then the socket's status is set to TCP_PORT_CLOSING. Therefore, 
				 * if we get another FIN, we can tell that the port is already closing
				 * and we don't need to process it, which also ensures we don't 
				 * process duplicate FINs multiple times. We'll include the
				 * duplicate == 0 check just for good measure, however.
				 */

				// We're required to close the conn 15s after we ACK a FIN, so do that here
				if (seq_num == socket->ack_num
					&& header_reliable->message_type == MSG_FIN
					&& socket->status != TCP_PORT_CLOSING
					&& duplicate == 0)
				{
					socket->status = TCP_PORT_CLOSING;
					queue_append(sockets_to_delete, socket);
					semaphore_V(socket_needs_delete);			
				}
			}
			 else if (socket->status == TCP_PORT_LISTENING)
			{
				// Start a connection with the client
				if (header_reliable->message_type == MSG_SYN)
				{
					// Update socket's dst addr & dst port to the client's
					network_address_copy(src_addr, socket->dst_addr);
					socket->dst_port = src_port_number;

					// Set the status to connecting
					socket->status = TCP_PORT_CONNECTING;
					
					// Awake the create_server thread, it'll handle the rest
					semaphore_V(socket->wait_for_ack_sem);
				}
			}

			// Add the packet to the socket's packet queue if not duplicate & it's a data pkt
			if (duplicate == 0 && header_reliable->message_type == MSG_ACK && data_len != 0)
			{
				enqueued = 1;
				queue_append(socket->waiting_packets, arg);
				if (socket->data_len == 0)
					semaphore_V(socket->packet_ready);
			}

			// remember to free arg if we dont push this to the tcp recv queue
			break;
	}

	if (enqueued == 0)
	{
		free(arg);
	}

	// Restore the interrupt level
	set_interrupt_level(prev_level);

	return;
}
Beispiel #10
0
/* 
 * Listen for a connection from somebody else. When communication link is
 * created return a minisocket_t through which the communication can be made
 * from now on.
 *
 * The argument "port" is the port number on the local machine to which the
 * client will connect.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_server_create(int port, minisocket_error *error)
{
	minisocket_t minisocket;
	interrupt_level_t prev_level;
	int transmit_ret;
	int success = 0;

	if (error == NULL)
	{
		return NULL;
	}

	// Ensure the port is in the valid range
	if (port < TCP_MIN_SERVER || port > TCP_MAX_SERVER)
	{
		*error = SOCKET_INVALIDPARAMS;
		return NULL;
	}

	// We need to synchronize access to the server port range of the minisockets
	// pool, as we don't want another thread to try to create a socket on this port
	// concurrently
	semaphore_P(server_sem);

	// Ensure the port doesn't exist
	if (minisockets[port] != NULL)
	{
		*error = SOCKET_PORTINUSE;
		semaphore_V(server_sem);
		return NULL;
	}

	// Try to setup the socket struct
	minisocket = minisocket_setup_socket(port);
	if (minisocket == NULL)
	{
		*error = SOCKET_OUTOFMEMORY;
		semaphore_V(server_sem);
		return NULL;		
	}

	// Set the port type
	minisocket->port_type = TCP_PORT_TYPE_SERVER;

	// Insert the minisocket into the array
	minisockets[port] = minisocket;

	// Ensure we don't have with the server semaphore, so other servers
	// can be made while we wait for a client
	semaphore_V(server_sem);

	// Continuously wait for a successful connection
	while (success == 0)
	{
		// Wait for a connection
		prev_level = set_interrupt_level(DISABLED);
		semaphore_P(minisocket->wait_for_ack_sem);
		set_interrupt_level(prev_level);

		// When we're awoken and have a client, set the status
		minisocket->status = TCP_PORT_CONNECTING;

		// And send the SYNACK sequence
		minisocket->ack_num++; // we're acknowledging the SYN, and also sending a packet that increments seq#
		transmit_ret = transmit_packet(minisocket, minisocket->dst_addr, minisocket->dst_port, 
						1, MSG_SYNACK, 0, NULL, error);	

		if (transmit_ret == -1)
		{
			// This means we didn't get ACKs back, so this is a bad connection
			// Reset some port details and continue waiting
			minisocket->status = TCP_PORT_LISTENING;
			network_address_blankify(minisocket->dst_addr);
			minisocket->dst_port = 0;
			minisocket->ack_num--;
			minisocket->seq_num--;
		}
		 else
		{
			// Established connection successfully
			minisocket->status = TCP_PORT_CONNECTED;
			success = 1;
		}
	}

	*error = SOCKET_NOERROR;
	
	return minisocket;
}
Beispiel #11
0
/* 
 * Send a message to the other end of the socket.
 *
 * The send call should block until the remote host has ACKnowledged receipt of
 * the message.  This does not necessarily imply that the application has called
 * 'minisocket_receive', only that the packet is buffered pending a future
 * receive.
 *
 * It is expected that the order of calls to 'minisocket_send' implies the order
 * in which the concatenated messages will be received.
 *
 * 'minisocket_send' should block until the whole message is reliably
 * transmitted or an error/timeout occurs
 *
 * Arguments: the socket on which the communication is made (socket), the
 *            message to be transmitted (msg) and its length (len).
 * Return value: returns the number of successfully transmitted bytes. Sets the
 *               error code and returns -1 if an error is encountered.
 */
int minisocket_send(minisocket_t socket, minimsg_t msg, int len, minisocket_error *error)
{
	int portNumber;
	int sentLength;
	int sentData = 0;
	int maxDataSize;
	int check;
	//interrupt_level_t prev_level;

	if (error == NULL)
		return -1;

	if (socket == NULL || msg == NULL || len <= 0)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	portNumber = socket->port_number;

	if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_TO_CLOSE
			|| minisockets[portNumber] == NULL)
	{
		*error = SOCKET_SENDERROR;
		return -1;
	}

	/*prev_level = set_interrupt_level(DISABLED);
	socket->num_waiting_on_mutex++;

	semaphore_P(socket->mutex);

	socket->num_waiting_on_mutex--;
	set_interrupt_level(prev_level);
*/
	if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_TO_CLOSE
			|| minisockets[portNumber] == NULL)
	{
		*error = SOCKET_SENDERROR;
//		semaphore_V(socket->mutex);
		return -1;
	}

	maxDataSize = MAX_NETWORK_PKT_SIZE - sizeof(struct mini_header_reliable);
	while (len > 0)
	{
		sentLength = (maxDataSize > len ? len : maxDataSize);
		check = transmit_packet(socket, socket->destination_addr, socket->destination_port, 1,
				MSG_ACK, sentLength, (msg+sentData), error);

		if (check == -1)
		{
//			semaphore_V(socket->mutex);
			minisocket_destroy(socket, 0);
			return (sentData == 0 ? -1 : sentData);
		}
		len -= maxDataSize;
		sentData += sentLength;
	}

//	semaphore_V(socket->mutex);
	*error = SOCKET_NOERROR;

	return sentData;
}
Beispiel #12
0
inline void receive_message( uint8_t uart, uint8_t* message, uint8_t message_size )//was inline
{
  uint8_t command = message[VCP_COMMAND_FIELD];
  uint8_t payload = message[VCP_PAYLOAD_FIELD];

  switch(command)
  {
    case VCP_COMPONENT_ON:
	
	  // Reset CDH IB Heartbeat timer
	  
      if ( svit[payload].switch_num != SW_NULL )
      {
        switch_on( svit[payload].switch_num );
        svit[payload].switch_state = 1;
      }
      transmit_packet( uart, VCP_ACK, command );
      break;
    case VCP_COMPONENT_OFF:
      if ( svit[payload].switch_num != SW_NULL )
      {
        switch_off( svit[payload].switch_num );
        svit[payload].switch_state = 0;
      }
      transmit_packet( uart, VCP_ACK, command );
      break;
    case VCP_POWER_CYCLE:
      if ( svit[payload].switch_num != SW_NULL )
      {
        switch_off( svit[payload].switch_num );
        svit[payload].switch_state = 0;
      }
      _delay_us(1);
      if ( svit[payload].switch_num != SW_NULL )
      {
        switch_on( svit[payload].switch_num );
        svit[payload].switch_state = 1;
      }
      transmit_packet( uart, VCP_ACK, command );
      break;
    case VCP_TORQ_CTRL:
      transmit_packet( uart, VCP_ACK, command );
      break;
    case VCP_GET_TELEMETRY:
      transmit_packet( uart, VCP_POWER_TELEMETRY, 0);
      break;
    case VCP_FORCE_ON:
      if ( svit[payload].switch_num != SW_NULL )
      {
        switch_on( svit[payload].switch_num );
        svit[payload].switch_state = 1;
        svit[payload].force_on = 1;  
      }
      transmit_packet( uart, VCP_ACK, command );                                                            
      break;
    case VCP_CRIT_V_CHANGE:
      if ( svit[payload].switch_num != SW_NULL )
      {
        svit[payload].V_upper_limit = message[VCP_PAYLOAD_FIELD + 1];
        V_upper_val_change= message[VCP_PAYLOAD_FIELD + 1];
      }
      //transmit_packet( uart, VCP_ACK, 0);
      break;
        case VCP_CRIT_I_CHANGE:
      if ( svit[payload].switch_num != SW_NULL )
      {
        svit[payload].I_upper_limit = message[VCP_PAYLOAD_FIELD + 1];
        I_upper_val_change= message[VCP_PAYLOAD_FIELD + 1];
      }
      //transmit_packet( uart, VCP_ACK, 0);
      break;
    default:
      transmit_packet( uart, VCP_INVALID_COMMAND, 0 );
      break;
  }
}
Beispiel #13
0
void minisocket_destroy(minisocket_t minisocket, int send_FIN)
{
	int i;
	int threads_waiting;
	int port_number;
	minisocket_error error;
	interrupt_level_t prev_level;

	if (minisocket == NULL)
	{
		return;
	}
	port_number = minisocket->port_number;

	semaphore_P(destroy_sem);

	// Basically, we need the socket's mutex to perform close, as we don't
	// want to close while someone is reading from the buffer or sending something.
	// However, the ms_receive() function acquires the mutex, and then may end
	// up waiting on socket->packet_ready. Therefore, we need to first signal 
	// packet_ready before we can get the mutex in some cases. Only one thread 
	// at a time is ever waiting on socket ready - we may end up letting two
	// pass it as we call it again in minisocket_destroy(), but we set the waiting
	// status to a value that the receive & send functions will detect and cause
	// their function calls to return with a failure. Note that we couldn't set
	// socket->status to TCP_PORT_CLOSING just yet, as that would cause the FIN
	// transmit to fail in our transmit_packet() function. Therefore, we just 
	// created a new waiting status for it.
	minisocket->waiting = TCP_PORT_WAITING_CLOSE;

	// Check if this is already destroyed
	if (minisockets[port_number] == NULL)
	{
		return;
	}

	// Only one thread will ever be waiting on this (b/c it's in a mutex), so
	// just do it once to wake up any thread waiting on it in receive()
	semaphore_V(minisocket->packet_ready);	

	// Wait for the socket mutex
		// This ensures that any currently executing send() finishes
		// This also ensures that anyone who is currently receiving from buffer finishes
	semaphore_P(minisocket->mutex);

	// Another thread already ran destroy, so we can just return
	// Not needed, but won't remove since we're running low on time and don't
	// want to break anything, just in case....
	if (minisockets[port_number] == NULL)
	{
		return;
	}

	// Send a FIN if needed
	if (send_FIN == 1)
	{
		transmit_packet(minisocket, minisocket->dst_addr, minisocket->dst_port, 
							1, MSG_FIN, 0, NULL, &error);
	}

	// Eensure we have the status set correctly so the threads we wake know what
	// is happening
	minisocket->status = TCP_PORT_CLOSING;

	// Awake all threads waiting on mutex - they'll see we're closing and fail
	threads_waiting = minisocket->num_waiting_on_mutex;
	for (i = 0; i < threads_waiting; i++)
	{
		semaphore_V(minisocket->mutex);
	}

	// Remove the port from the minisockets pool
	minisockets[minisocket->port_number] = NULL;

	// NO NEED TO SYNCHRONIZE THIS STUFF WITH THE INTERRUPT HANDLER 
	// This is because, if we get interrupted here, the above line will tell
	// the IH that this socket is closed, so it won't access any of the stuff
	// we're about to free

	// Free all the sems
	prev_level = set_interrupt_level(DISABLED);
	semaphore_destroy(minisocket->wait_for_ack_sem);
	semaphore_destroy(minisocket->mutex);
	semaphore_destroy(minisocket->packet_ready);
	
	// Free the data buffer
	if (minisocket->data_len != 0)
		free(minisocket->data_buffer);

	// Free the queue
	queue_free(minisocket->waiting_packets);
	set_interrupt_level(prev_level);

	// Free the socket itself
	free(minisocket);

	semaphore_V(destroy_sem);
}
Beispiel #14
0
/* 
 * Send a message to the other end of the socket.
 *
 * The send call should block until the remote host has ACKnowledged receipt of
 * the message.  This does not necessarily imply that the application has called
 * 'minisocket_receive', only that the packet is buffered pending a future
 * receive.
 *
 * It is expected that the order of calls to 'minisocket_send' implies the order
 * in which the concatenated messages will be received.
 *
 * 'minisocket_send' should block until the whole message is reliably
 * transmitted or an error/timeout occurs
 *
 * Arguments: the socket on which the communication is made (socket), the
 *            message to be transmitted (msg) and its length (len).
 * Return value: returns the number of successfully transmitted bytes. Sets the
 *               error code and returns -1 if an error is encountered.
 */
int minisocket_send(minisocket_t socket, minimsg_t msg, int len, minisocket_error *error)
{
	int ret;
	int max_data_size;
	int data_sent = 0;
	int len_sent;
	int port_number;

	if (socket == NULL)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (msg == NULL)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (len <= 0)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (error == NULL)
	{
		return -1;
	}

	port_number = socket->port_number;

	// First, check if the socket is closing
	if (socket->status == TCP_PORT_CLOSING 
		|| socket->waiting == TCP_PORT_WAITING_CLOSE
		|| minisockets[port_number] == NULL)
	{
		*error = SOCKET_SENDERROR;
		return -1;
	}

	socket->num_waiting_on_mutex++;
	semaphore_P(socket->mutex);
	socket->num_waiting_on_mutex--;

	// Check again - maybe we were awoken because it's now closing
	if (socket->status == TCP_PORT_CLOSING 
		|| socket->waiting == TCP_PORT_WAITING_CLOSE
		|| minisockets[port_number] == NULL)
	{
		*error = SOCKET_SENDERROR;
		semaphore_V(socket->mutex);
		return -1;
	}

	// Determine the max data size
	max_data_size = MAX_NETWORK_PKT_SIZE - sizeof(struct mini_header_reliable);

	if (len > max_data_size)
	{
		// Partition the large message into smaller packets
		while (len > 0)
		{
			// See how much we can fit into the next packet
			len_sent = (max_data_size > len ? len : max_data_size);
	
			// Send the packet
			ret = transmit_packet(socket, socket->dst_addr, socket->dst_port, 1, 
									MSG_ACK, len_sent, msg+data_sent, error);

			// Check for errors
			if (ret == -1)
			{
				// If we can't reach the host, close the connection
				semaphore_V(socket->mutex);
				minisocket_destroy(socket, 0);
				return (data_sent == 0 ? -1 : data_sent);
			}

			// Update the amount of data left to send
			len -= max_data_size; // can also be - len_sent, doesn't matter

			// Update the number of bytes we've sent - also used w/ msg as a ptr
			data_sent += len_sent;
		}
	}
	 else
	{
		// This can be transmitted as a single packet
		ret = transmit_packet(socket, socket->dst_addr, 
						socket->dst_port, 1, 
						MSG_ACK, len, msg, error);

		if (ret == -1)
		{
			// If we can't reach the host, close the connection
			semaphore_V(socket->mutex);
			minisocket_destroy(socket, 0);
			return -1;
		}

		data_sent = len;
	}

	semaphore_V(socket->mutex);
	*error = SOCKET_NOERROR;
	return data_sent;
}
Beispiel #15
0
/*
 * Initiate the communication with a remote site. When communication is
 * established create a minisocket through which the communication can be made
 * from now on.
 *
 * The first argument is the network address of the remote machine. 
 *
 * The argument "port" is the port number on the remote machine to which the
 * connection is made. The port number of the local machine is one of the free
 * port numbers.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_client_create(network_address_t addr, int port, minisocket_error *error)
{
	int port_number;
	int num_client_ports = TCP_MAX_CLIENT - TCP_MIN_CLIENT + 1;
	int adjusted_port;
	int found_port = 0;
	int i;
	int transmit_ret;
	minisocket_t minisocket;

	if (error == NULL)
	{
		return NULL;
	}

	// Synchornize access to the client port range of the minisocket pool
	semaphore_P(client_sem);

	// Find a free client port to use
	if (client_wrapped == 0)
	{
		// If we haven't wrapped around yet, just pick the next port
		port_number = current_client_port++;

		// Check if we need to wrap around
		if (current_client_port > TCP_MAX_CLIENT)
		{
			client_wrapped = 1;
			current_client_port = TCP_MIN_CLIENT;
		}
	}
	 else
	{
		for (i = 0; i < num_client_ports; i++)
		{
			// Sorry this goes over 80 characters, but it's easier to see on one line
			adjusted_port = (((current_client_port - TCP_MIN_CLIENT)+i) % num_client_ports) + TCP_MIN_CLIENT;

			if (minisockets[adjusted_port] == NULL)
			{
				current_client_port = adjusted_port;
				found_port = 1;
				break;
			}
		}

		// If we coulnd't find a port, return NULL
		if (found_port == 0)
		{
			*error = SOCKET_NOMOREPORTS;
			semaphore_V(client_sem);
			return NULL;			
		}

		// Set the port number
		port_number = current_client_port++;
	}

	// Create the socket
	minisocket = minisocket_setup_socket(port_number);
	if (minisocket == NULL)
	{
		*error = SOCKET_OUTOFMEMORY;
		semaphore_V(client_sem);
		return NULL;		
	}

	// Set the port type and client variables
	minisocket->port_type = TCP_PORT_TYPE_CLIENT;
	network_address_copy(addr, minisocket->dst_addr);
	minisocket->dst_port = port;
	
	// Set the port in the array
	minisockets[port_number] = minisocket;

	// Prepare to send a SYN and connect
	minisocket->status = TCP_PORT_CONNECTING;

	// Release the sem as soon as possible
	semaphore_V(client_sem);

	// Send the SYN - incr the seq # too, and do retransmission sequence pending SYNACK
	transmit_ret = transmit_packet(minisocket, addr, port, 1, MSG_SYN, 0, NULL, error);

	// Check if we got a FIN - which means the server is busy with another client
	if (minisocket->status == TCP_PORT_COULDNT_CONNECT)
	{
		// The packet process thread will make the status this value if we were
		// connecting and got a FIN
		minisockets[port] = NULL;
		free(minisocket);
		*error = SOCKET_BUSY;
		return NULL;
	}

	// Check if the server didn't respond
	if (transmit_ret == -1)
	{
		// The error code is set by transmit_packet(), so just clean up & return
		minisockets[port] = NULL;
		free(minisocket);
		return NULL;
	}

	minisocket->status = TCP_PORT_CONNECTED;

	*error = SOCKET_NOERROR;
	return minisocket;
}
Beispiel #16
0
/* 
 * Listen for a connection from somebody else. When communication link is
 * created return a minisocket_t through which the communication can be made
 * from now on.
 *
 * The argument "port" is the port number on the local machine to which the
 * client will connect.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_server_create(int port, minisocket_error *error)
{
	minisocket_t newMinisocket;
	int ack_check;
	int connected = 1;
	network_interrupt_arg_t *arg;
	mini_header_reliable_t header;

	if (error == NULL)
		return NULL;

	if (port < TCP_MINIMUM_SERVER || port > TCP_MAXIMUM_SERVER)
	{
		*error = SOCKET_INVALIDPARAMS;
		return NULL;
	}

	semaphore_P(server_mutex);

	//Checks if port already exists
	if (minisockets[port] != NULL)
	{
		*error = SOCKET_PORTINUSE;
		semaphore_V(server_mutex);
		return NULL;
	}

	newMinisocket = minisocket_create_socket(port);
	if (newMinisocket == NULL)
	{
		*error = SOCKET_OUTOFMEMORY;
		semaphore_V(server_mutex);
		return NULL;
	}

	newMinisocket->port_type = TCP_PORT_TYPE_SERVER;
	minisockets[port] = newMinisocket;

	semaphore_V(server_mutex);

	while (connected == 1)
	{
		semaphore_P(newMinisocket->packet_ready);
		
		queue_dequeue(newMinisocket->waiting_packets, (void **) &arg);
		header = (mini_header_reliable_t) arg->buffer;
		if (header->message_type != MSG_SYN)
			continue;

		newMinisocket->status = TCP_PORT_CONNECTING;

		unpack_address(header->source_address, newMinisocket->destination_addr);
		newMinisocket->destination_port = unpack_unsigned_short(header->source_port);
		ack_check = transmit_packet(newMinisocket, newMinisocket->destination_addr, 
				newMinisocket->destination_port, 1, MSG_SYNACK, 0, NULL, error);

		if (ack_check == -1)
		{
			newMinisocket->status = TCP_PORT_LISTENING;
			network_address_blankify(newMinisocket->destination_addr);
			newMinisocket->destination_port = 0;
		}	
		else
		{
			newMinisocket->status = TCP_PORT_CONNECTED;
			connected = 0;
		}
	}

	*error = SOCKET_NOERROR;
	return newMinisocket;
}
Beispiel #17
0
/*
 * Initiate the communication with a remote site. When communication is
 * established create a minisocket through which the communication can be made
 * from now on.
 *
 * The first argument is the network address of the remote machine. 
 *
 * The argument "port" is the port number on the remote machine to which the
 * connection is made. The port number of the local machine is one of the free
 * port numbers.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_client_create(network_address_t addr, int port, minisocket_error *error)
{
	minisocket_t newMinisocket;
	int totalClientPorts = TCP_MAXIMUM_CLIENT - TCP_MINIMUM_CLIENT + 1;
	int convertedPortNumber = (currentClientPort % totalClientPorts) + TCP_MINIMUM_CLIENT;
	int i = 1;
	int transmitCheck;

	if (error == NULL)
		return NULL;

	semaphore_P(client_mutex);

	while (i < totalClientPorts && (minisockets[convertedPortNumber] != NULL))
	{
		convertedPortNumber = ((currentClientPort + i) % totalClientPorts) + TCP_MINIMUM_CLIENT;
		i++;
	}
	currentClientPort += (i-1);

	if (minisockets[convertedPortNumber] != NULL)
	{
		*error = SOCKET_NOMOREPORTS;
		semaphore_V(client_mutex);
		return NULL;		
	}

	newMinisocket = minisocket_create_socket(convertedPortNumber);
	if (newMinisocket == NULL)
	{
		*error = SOCKET_OUTOFMEMORY;
		semaphore_V(client_mutex);
		return NULL;
	}

	newMinisocket->port_type = TCP_PORT_TYPE_CLIENT;
	network_address_copy(addr, newMinisocket->destination_addr);
	newMinisocket->destination_port = convertedPortNumber;

	minisockets[convertedPortNumber] = newMinisocket;
	newMinisocket->status = TCP_PORT_CONNECTING;

	semaphore_V(client_mutex);

	transmitCheck = transmit_packet(newMinisocket, addr, port, 1, MSG_SYN, 0, NULL, error);
	if (transmitCheck == -1)
	{
		//*error set by transmit_packet()
		minisockets[convertedPortNumber] = NULL;
		free(newMinisocket);
		return NULL;
	}
	newMinisocket->ack_number++;
	//newMinisocket->waiting = TCP_PORT_WAITING_SYNACK;
	//semaphore_P(newMinisocket->wait_for_ack_semaphore);

	transmitCheck = transmit_packet(newMinisocket, addr, port, 1, MSG_ACK, 0, NULL, error);
	if (transmitCheck == -1)
	{
		minisockets[convertedPortNumber] = NULL;
		free(newMinisocket);
		return NULL;
	}
	newMinisocket->status = TCP_PORT_CONNECTED;

	*error = SOCKET_NOERROR;
	return newMinisocket;
}
Beispiel #18
0
/*
 * Process an interrupt.
 * Return nonzero when there was some activity.
 */
static unsigned handle_interrupt(eth_t *u) {
	unsigned active = 0;

	ARM_NVIC_ICPR(0) = 1 << ETH_IRQ;
	u->intr_flags = ARM_ETH->IFR;
	if (u->intr_flags & ARM_ETH_XF_UNDF) {
		ARM_ETH->R_CFG &= ~ARM_ETH_EN;
		ARM_ETH->X_CFG &= ~ARM_ETH_EN;
		ARM_ETH->G_CFG_HI |= ARM_ETH_XRST;
		ARM_ETH->X_TAIL = ARM_ETH->X_HEAD;
		ARM_ETH->G_CFG_HI &= ~ARM_ETH_XRST;
		ARM_ETH->X_CFG |= ARM_ETH_EN;
		ARM_ETH->R_CFG |= ARM_ETH_EN;
	}
	/* Обработка приёма пакета */
	//if (ARM_ETH->X_TAIL != ARM_ETH->X_HEAD) {
	//	/* Если есть данные, прочитать пакет */
	//	receive_packet(u);
	//	active++;
	//}
	if (ARM_ETH->R_TAIL != ARM_ETH->R_HEAD) {
		/* Если есть данные, прочитать пакет */
		while (ARM_ETH->STAT & 0xE0) {
			receive_packet(u);
			ARM_ETH->IFR |= ARM_ETH_RF_OK;
		}
		active++;
	}
	u->intr_flags = ARM_ETH->IFR;
	if (u->intr_flags & ARM_ETH_MISSED_F) {
		ARM_ETH->IFR |= ARM_ETH_MISSED_F;
		//ARM_ETH->R_HEAD = ARM_ETH->R_TAIL;
		//if (ARM_ETH->STAT & 0xE0){
		//	ARM_ETH->STAT -= 0x20;
		//	++u->in_missed_and_rx;
		//}
		//if(ARM_ETH->STAT & ~0xE0)
		//	ARM_ETH->R_HEAD = ARM_ETH->R_TAIL;
		//chip_read_rxfifo(u, ARM_ETH_PKT_LENGTH(ARM_ETH_RX_FIFO));
		++u->netif.in_discards;
		++u->in_missed;
		//ARM_NVIC_ICPR(0) = 1 << ETH_IRQ;
		//return 0;
	}
	/* успешная отправка */
	if (u->intr_flags & ARM_ETH_XF_OK) {
		ARM_ETH->IFR |= ARM_ETH_XF_OK;
		/* debug_printf("Transmot ok. ARM_ETH->IFR = <0x%04x>\n", u->intr_flags); */
//#ifdef ETH_FIFO
//		unsigned tmp = ARM_ETH_TX_FIFO;
//#endif
		/* Извлекаем следующий пакет из очереди. */
		buf_t *p = buf_queue_get(&u->outq);
		if (p) {
			/* Передаём следующий пакет. */
			transmit_packet(u, p);
			netif_free_buf (&u->netif, p);
		}
		active++;
	}
	if (u->intr_flags & ARM_ETH_XF_ERR) {
		ARM_ETH->IFR |= ARM_ETH_XF_ERR;
		++u->netif.out_errors;
//#ifdef ETH_FIFO
//		unsigned tmp = ARM_ETH_TX_FIFO;
//#endif
		/* debug_printf("Error Tx on transmiteARM_ETH->IFR = <0x%04x>\n", u->intr_flags); */
	}
	/* Подсчитываем коллизии. */
	if (u->intr_flags & ARM_ETH_LC) {
		ARM_ETH->IFR |= ARM_ETH_LC;
		++u->netif.out_collisions;
		/* debug_printf("Error collisions\n"); */
	}
	//ARM_NVIC_ICPR(0) = 1 << ETH_IRQ;
	return active;
}
Beispiel #19
0
static int
sys_trans_pkt(void *va, size_t len)
{
	user_mem_assert(curenv, va, len, PTE_P | PTE_U);
	return transmit_packet(va, len);
}
Beispiel #20
0
 void network_handler(network_interrupt_arg_t* arg)
{
	// Used to extract the network address out of the interrupt argument
	//network_address_t addr;

	// The source port number - this is really the remote unbound port number
	int src_port_number;

	// The port number the packet was sent to
	int dst_port_number;

	// Used to store the header data for UDP/minimsgs
	mini_header_t header;

	// This is used to extract the sender's address from the header
	network_address_t src_addr;

	// This is used to extract the destination (our) address from the header
	network_address_t dst_addr;

	// Disable interrupts...
	interrupt_level_t prev_level = set_interrupt_level(DISABLED);

	// This is used to check our own address for sanity checks
	network_address_t my_addr;

	// This will store the total packet size
	int packet_size;

	// This will store the size of the data in the packet
	int data_len;

	// This will store the header of a TCP packet
	mini_header_reliable_t header_reliable;

	// This will store the ACK number of a TCP packet
	int ack_num;

	// This will store the Sequence number of a TCP packet
	int seq_num;

	// This will store the socket
	minisocket_t socket;

	// This will store the TCP error
	minisocket_error error;

	// This will be used to indicate whether the TCP packet is a duplicate or not
	int duplicate = 0;

	// Check the protocol
	switch (arg->buffer[0])
	{
		case (char) PROTOCOL_MINIDATAGRAM:
			// Extract data from the network interrupt arg
			//network_address_copy(arg->addr, addr);

			// Get the header struct, unpack the parameters
			header = (mini_header_t) &arg->buffer;
			dst_port_number = (int) unpack_unsigned_short(header->destination_port);

			// Ensure the port number is valid
			if (dst_port_number < MIN_UNBOUND || dst_port_number > MAX_UNBOUND)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Then ensure the miniport exists
			if (miniports[dst_port_number] == NULL)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Add the arg to the queue
			queue_append(miniports[dst_port_number]->port_data.unbound.data_queue, arg);

			// Wake up thread that's waiting to receive - sem_V()
			semaphore_V(miniports[dst_port_number]->port_data.unbound.data_ready);
			break;

		case PROTOCOL_MINISTREAM:
			// Get the total size of the packet and data length
			packet_size = arg->size;
			data_len = packet_size - sizeof(struct mini_header_reliable);

			// Get the header and extract information
			header_reliable = (mini_header_reliable_t) arg->buffer;
			src_port_number = (int) unpack_unsigned_short(header_reliable->source_port);
			dst_port_number = (int) unpack_unsigned_short(header_reliable->destination_port);
			unpack_address(header_reliable->source_address, src_addr);
			unpack_address(header_reliable->destination_address, dst_addr);
			seq_num = (int) unpack_unsigned_int(header_reliable->seq_number);
			ack_num = (int) unpack_unsigned_int(header_reliable->ack_number);

			// Don't respond if socket doesn't exist - will trigger SOCKET_NOSERVER for client
			if (minisockets[dst_port_number] == NULL)
			{
				set_interrupt_level(prev_level);
				return;
			}

			// Get the socket in question
			socket = minisockets[dst_port_number];

			// Check if packet was meant for us - ignore if not
			network_get_my_address(my_addr);
			if (network_compare_network_addresses(my_addr, dst_addr) == 0)
			{
				set_interrupt_level(prev_level);
				return;
			}

			if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_CLOSE)
			{
				set_interrupt_level(prev_level);
				return;
			}

			// Packet handling for established connections
			if (socket->status != TCP_PORT_LISTENING)
			{
				// Ensure source address is correct - ignore if not
				if (network_compare_network_addresses(src_addr, socket->dst_addr) == 0 
					|| src_port_number != socket->dst_port)
				{
					if (header_reliable->message_type == MSG_SYN)
					{
						// A client is trying to connect to an already-connected port
						// Send them a FIN, which will result in their client
						// returning a SOCKET_BUSY error
						transmit_packet(socket, src_addr, src_port_number, 0, 
											MSG_FIN, 0, NULL, &error);
					}

					set_interrupt_level(prev_level);
					return;
				}


				/* We got a duplicate SYN and need to ensure that the host gets
				 * another SYNACK. The thread that sent the SYNACK will currently
				 * be retransmitting the SYNACKs, as it didn't get an ACK. If it 
				 * was done with the retransmission sequence, the socket would be
				 * closed, and this would therefore not have gotten this far.
				 * HOWEVER:
				 * If the retransmission sequence already sent its LAST 
				 * retransmission and was waiting on it, then this duplicate SYN 
				 * will NOT get a SYNACK, as the retransmission is just waiting
				 * out the last alarm before it ends. Therefore, if this is the case,
				 * reset the timeout to the last timeout value so it sends just
				 * one more SYNACK.
				 *
				 * Professor Sirer mentioned that this isn't even necessary,
				 * but this does seem to make the code follow the specs more.
				 */
				if (header_reliable->message_type == MSG_SYN)
				{
					// If the timeout is at 6400, then it's the last transmission
					// but it hasn't been doubled yet. If it's 12800, it's just
					// been doubled. In each case we want to keep it at 6400 
					// at the end of the while loop, so we set the timeout to half
					// it's current value.
					if (socket->timeout >= 6400)
					{
						socket->timeout /= 2;
					}

					set_interrupt_level(prev_level);
					return;
				}

				// If we were trying to connect and got a FIN, that means the socket's busy
				if (socket->status == TCP_PORT_CONNECTING && header_reliable->message_type == MSG_FIN)
				{
					// Not connected, got a FIN - that means we couldnt start connection b/c it was busy
					// This will let the client function infer that
					socket->status = TCP_PORT_COULDNT_CONNECT;

					// Wake it up so it can end the retransmission sequence
					semaphore_V(socket->wait_for_ack_sem);

					set_interrupt_level(prev_level);
					return;
				}

				/* Note: the code below handles ACKs. It also inherently deals with
				 * duplicate ACKs. We have a status code that indicates whether the socket
				 * is waiting for an ACK or not. If it's set and we get an ACK (or any 
				 * packet) with the right ACK number, we can process it. However, if our 
				 * status indicates we're NOT waiting for an ACK, we can infer from the
				 * fact that window_size = 1 that we already got the only ACK we could've
				 * been expecting, and this new one is therefore a duplicate. 
				 */

				// If we're waiting on an ACK
				if (socket->waiting == TCP_PORT_WAITING_ACK /*|| socket->waiting == TCP_PORT_WAITING_ACK_WAKING*/)
				{
					// This can be an ACK or really any other data packet, we just
					// need the ACK number
					if (ack_num == socket->seq_num)
					{
						// Update our status to show we're no longer waiting for an ACK
						socket->waiting = TCP_PORT_WAITING_NONE;

						// Wake up the thread waiting for the ACK
						semaphore_V(socket->wait_for_ack_sem);
					}
					 else if (ack_num == socket->seq_num - 1)
					{
						// This follows the same logic from the comment block around
						// line 170. 
						if (socket->timeout >= 6400)
						{
							socket->timeout /= 2;
						}	
					}
				}

				// If it's an ACK, it requires no further processing
				if (header_reliable->message_type == MSG_ACK && data_len == 0)
				{
					set_interrupt_level(prev_level);
					return;
				}

				// Check if it's a SYNACK we're waiting for
				if (socket->waiting == TCP_PORT_WAITING_SYNACK && header_reliable->message_type == MSG_SYNACK)
				{
					// We're now fully connected in our eyes, handshake complete
					socket->waiting = TCP_PORT_WAITING_NONE;
					semaphore_V(socket->wait_for_ack_sem);
				}

				// If we're here, the packet isnt an ACK or SYN, so we should ACK it

				// First check if we should increment our ack number
				if (seq_num == socket->ack_num + 1)
				{
					socket->ack_num++;
				}
				 else
				{
					// It's a duplicate, don't add to queue
					duplicate = 1;
				}

				// Next, perform the ACK, don't incr the seq#
				transmit_packet(socket, socket->dst_addr, socket->dst_port, 
								0, MSG_ACK, 0, NULL, &error);	

				/* Note: the code below handles FINs, and is also protected against
				 * duplicate FINs inherently. The seq_num == ack_num check doesn't
				 * guarantee it's not a duplicate; however, if we process one FIN,
				 * then the socket's status is set to TCP_PORT_CLOSING. Therefore, 
				 * if we get another FIN, we can tell that the port is already closing
				 * and we don't need to process it, which also ensures we don't 
				 * process duplicate FINs multiple times. We'll include the
				 * duplicate == 0 check just for good measure, however.
				 */

				// We're required to close the conn 15s after we ACK a FIN, so do that here
				if (seq_num == socket->ack_num
					&& header_reliable->message_type == MSG_FIN
					&& socket->status != TCP_PORT_CLOSING
					&& duplicate == 0)
				{
					socket->status = TCP_PORT_CLOSING;
					queue_append(sockets_to_delete, socket);
					semaphore_V(socket_needs_delete);			
				}
			}
			 else if (socket->status == TCP_PORT_LISTENING)
			{
				// Start a connection with the client
				if (header_reliable->message_type == MSG_SYN)
				{
					// Update socket's dst addr & dst port to the client's
					network_address_copy(src_addr, socket->dst_addr);
					socket->dst_port = src_port_number;

					// Set the status to connecting
					socket->status = TCP_PORT_CONNECTING;

					// Awake the create_server thread, it'll handle the rest
					semaphore_V(socket->wait_for_ack_sem);
				}
			}

			// Add the packet to the socket's packet queue if not duplicate & it's a data pkt
			if (duplicate == 0 && header_reliable->message_type == MSG_ACK && data_len != 0)
			{
				queue_append(socket->waiting_packets, arg);
				if (socket->data_len == 0)
					semaphore_V(socket->packet_ready);
			}

			// remember to free arg if we dont push this to the tcp recv queue
			break;
	}

	// Restore the interrupt level
	set_interrupt_level(prev_level);

	return;
}