Exemple #1
0
status_t
ethernet_frame_send_data(net_datalink_protocol* protocol, net_buffer* buffer)
{
	struct sockaddr_dl& source = *(struct sockaddr_dl*)buffer->source;
	struct sockaddr_dl& destination = *(struct sockaddr_dl*)buffer->destination;

	if (source.sdl_family != AF_LINK || source.sdl_type != IFT_ETHER)
		return B_ERROR;

	NetBufferPrepend<ether_header> bufferHeader(buffer);
	if (bufferHeader.Status() != B_OK)
		return bufferHeader.Status();

	ether_header &header = bufferHeader.Data();

	header.type = source.sdl_e_type;
	memcpy(header.source, LLADDR(&source), ETHER_ADDRESS_LENGTH);
	if ((buffer->flags & MSG_BCAST) != 0)
		memcpy(header.destination, kBroadcastAddress, ETHER_ADDRESS_LENGTH);
	else
		memcpy(header.destination, LLADDR(&destination), ETHER_ADDRESS_LENGTH);

	bufferHeader.Sync();
		// make sure the framing is already written to the buffer at this point

	return protocol->next->module->send_data(protocol->next, buffer);
}
Exemple #2
0
static void
AddL2capHeader(L2capFrame* frame)
{
    NetBufferPrepend<l2cap_hdr_t> bufferHeader(frame->buffer);
    status_t status = bufferHeader.Status();

    if (status < B_OK) {
        debugf("header could not be prepended! code=%d\n", frame->code);
        return;
    }

    // fill
    bufferHeader->length = htole16(frame->buffer->size - sizeof(l2cap_hdr_t));
    switch (frame->type) {
    case L2CAP_C_FRAME:
        bufferHeader->dcid = L2CAP_SIGNAL_CID;
        break;
    case L2CAP_G_FRAME:
        bufferHeader->dcid = L2CAP_CLT_CID;
        break;
    default:
        bufferHeader->dcid = frame->channel->dcid;
        break;
    }
}
Exemple #3
0
static status_t
arp_receive(void *cookie, net_device *device, net_buffer *buffer)
{
	TRACE(("ARP receive\n"));

	NetBufferHeaderReader<arp_header> bufferHeader(buffer);
	if (bufferHeader.Status() < B_OK)
		return bufferHeader.Status();

	arp_header &header = bufferHeader.Data();
	uint16 opcode = ntohs(header.opcode);

#ifdef TRACE_ARP
	dprintf("  hw sender: %02x:%02x:%02x:%02x:%02x:%02x\n",
		header.hardware_sender[0], header.hardware_sender[1], header.hardware_sender[2],
		header.hardware_sender[3], header.hardware_sender[4], header.hardware_sender[5]);
	dprintf("  proto sender: %ld.%ld.%ld.%ld\n", header.protocol_sender >> 24, (header.protocol_sender >> 16) & 0xff,
		(header.protocol_sender >> 8) & 0xff, header.protocol_sender & 0xff);
	dprintf("  hw target: %02x:%02x:%02x:%02x:%02x:%02x\n",
		header.hardware_target[0], header.hardware_target[1], header.hardware_target[2],
		header.hardware_target[3], header.hardware_target[4], header.hardware_target[5]);
	dprintf("  proto target: %ld.%ld.%ld.%ld\n", header.protocol_target >> 24, (header.protocol_target >> 16) & 0xff,
		(header.protocol_target >> 8) & 0xff, header.protocol_target & 0xff);
#endif

	if (ntohs(header.protocol_type) != ETHER_TYPE_IP
		|| ntohs(header.hardware_type) != ARP_HARDWARE_TYPE_ETHER)
		return B_BAD_TYPE;

	// check if the packet is okay

	if (header.hardware_length != ETHER_ADDRESS_LENGTH
		|| header.protocol_length != sizeof(in_addr_t))
		return B_BAD_DATA;

	// handle packet

	switch (opcode) {
		case ARP_OPCODE_REQUEST:
			TRACE(("  got ARP request\n"));
			if (handle_arp_request(buffer, header) == B_OK) {
				// the function will take care of the buffer if everything
				// went well
				return B_OK;
			}
			break;
		case ARP_OPCODE_REPLY:
			TRACE(("  got ARP reply\n"));
			handle_arp_reply(buffer, header);
			break;

		default:
			dprintf("unknown ARP opcode %d\n", opcode);
			return B_ERROR;
	}

	gBufferModule->free(buffer);
	return B_OK;
}
Exemple #4
0
int32
ethernet_deframe(net_device* device, net_buffer* buffer)
{
	//dprintf("asked to deframe buffer for device %s\n", device->name);

	NetBufferHeaderRemover<ether_header> bufferHeader(buffer);
	if (bufferHeader.Status() != B_OK)
		return bufferHeader.Status();

	ether_header& header = bufferHeader.Data();
	uint16 type = B_BENDIAN_TO_HOST_INT16(header.type);

	struct sockaddr_dl& source = *(struct sockaddr_dl*)buffer->source;
	struct sockaddr_dl& destination = *(struct sockaddr_dl*)buffer->destination;

	source.sdl_len = sizeof(sockaddr_dl);
	source.sdl_family = AF_LINK;
	source.sdl_index = device->index;
	source.sdl_type = IFT_ETHER;
	source.sdl_e_type = header.type;
	source.sdl_nlen = source.sdl_slen = 0;
	source.sdl_alen = ETHER_ADDRESS_LENGTH;
	memcpy(source.sdl_data, header.source, ETHER_ADDRESS_LENGTH);

	destination.sdl_len = sizeof(sockaddr_dl);
	destination.sdl_family = AF_LINK;
	destination.sdl_index = device->index;
	destination.sdl_type = IFT_ETHER;
	destination.sdl_e_type = header.type;
	destination.sdl_nlen = destination.sdl_slen = 0;
	destination.sdl_alen = ETHER_ADDRESS_LENGTH;
	memcpy(destination.sdl_data, header.destination, ETHER_ADDRESS_LENGTH);

	// Mark buffer if it was a broadcast/multicast packet
	if (!memcmp(header.destination, kBroadcastAddress, ETHER_ADDRESS_LENGTH))
		buffer->flags |= MSG_BCAST;
	else if ((header.destination[0] & 0x01) != 0)
		buffer->flags |= MSG_MCAST;

	// Translate the ethernet specific type to a generic one if possible
	switch (type) {
		case ETHER_TYPE_IP:
			buffer->type = B_NET_FRAME_TYPE_IPV4;
			break;
		case ETHER_TYPE_IPV6:
			buffer->type = B_NET_FRAME_TYPE_IPV6;
			break;
		case ETHER_TYPE_IPX:
			buffer->type = B_NET_FRAME_TYPE_IPX;
			break;

		default:
			buffer->type = B_NET_FRAME_TYPE(IFT_ETHER, type);
			break;
	}

	return B_OK;
}
Exemple #5
0
static uint8
tcp_segment_flags(net_buffer* buffer)
{
	NetBufferHeaderReader<tcp_header> bufferHeader(buffer);
	if (bufferHeader.Status() < B_OK)
		return bufferHeader.Status();

	tcp_header &header = bufferHeader.Data();
	return header.flags;
}
Exemple #6
0
/*!	Constructs a TCP header on \a buffer with the specified values
	for \a flags, \a seq \a ack and \a advertisedWindow.
*/
status_t
add_tcp_header(net_address_module_info* addressModule,
	tcp_segment_header& segment, net_buffer* buffer)
{
	buffer->protocol = IPPROTO_TCP;

	uint8 optionsBuffer[kMaxOptionSize];
	uint32 optionsLength = add_options(segment, optionsBuffer,
		sizeof(optionsBuffer));

	NetBufferPrepend<tcp_header> bufferHeader(buffer,
		sizeof(tcp_header) + optionsLength);
	if (bufferHeader.Status() != B_OK)
		return bufferHeader.Status();

	tcp_header& header = bufferHeader.Data();

	header.source_port = addressModule->get_port(buffer->source);
	header.destination_port = addressModule->get_port(buffer->destination);
	header.sequence = htonl(segment.sequence);
	header.acknowledge = (segment.flags & TCP_FLAG_ACKNOWLEDGE)
		? htonl(segment.acknowledge) : 0;
	header.reserved = 0;
	header.header_length = (sizeof(tcp_header) + optionsLength) >> 2;
	header.flags = segment.flags;
	header.advertised_window = htons(segment.advertised_window);
	header.checksum = 0;
	header.urgent_offset = htons(segment.urgent_offset);

	// we must detach before calculating the checksum as we may
	// not have a contiguous buffer.
	bufferHeader.Sync();

	if (optionsLength > 0) {
		gBufferModule->write(buffer, sizeof(tcp_header), optionsBuffer,
			optionsLength);
	}

	TRACE(("add_tcp_header(): buffer %p, flags 0x%x, seq %lu, ack %lu, up %u, "
		"win %u\n", buffer, segment.flags, segment.sequence,
		segment.acknowledge, segment.urgent_offset, segment.advertised_window));

	*TCPChecksumField(buffer) = Checksum::PseudoHeader(addressModule,
		gBufferModule, buffer, IPPROTO_TCP);

	return B_OK;
}
Exemple #7
0
status_t
icmp6_receive_data(net_buffer *buffer)
{
	TRACE(("ICMPv6 received some data, buffer length %" B_PRIu32 "\n",
		buffer->size));

	net_domain* domain = get_domain(buffer);
	if (domain == NULL)
		return B_ERROR;

	NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
	if (bufferHeader.Status() < B_OK)
		return bufferHeader.Status();

	icmp6_hdr &header = bufferHeader.Data();

	TRACE(("  got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
			header.icmp6_code, header.icmp6_cksum));

	net_address_module_info* addressModule = domain->address_module;

	// compute and check the checksum
 	if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
 			IPPROTO_ICMPV6) != 0)
 		return B_BAD_DATA;

	switch (header.icmp6_type) {
		case ICMP6_ECHO_REPLY:
			break;

		case ICMP6_ECHO_REQUEST:
		{
			if (buffer->interface_address != NULL) {
				// We only reply to echo requests of our local interface; we
				// don't reply to broadcast requests
				if (!domain->address_module->equal_addresses(
						buffer->interface_address->local, buffer->destination))
					break;
			}

			net_buffer *reply = gBufferModule->duplicate(buffer);
			if (reply == NULL)
				return B_NO_MEMORY;

			gBufferModule->swap_addresses(reply);

			// There already is an ICMP header, and we'll reuse it
			NetBufferHeaderReader<icmp6_hdr> header(reply);

			header->icmp6_type = ICMP6_ECHO_REPLY;
			header->icmp6_code = 0;
			header->icmp6_cksum = 0;

			header.Sync();

			*ICMP6ChecksumField(reply) = Checksum::PseudoHeader(addressModule,
				gBufferModule, buffer, IPPROTO_ICMPV6);

			status_t status = domain->module->send_data(NULL, reply);
			if (status < B_OK) {
				gBufferModule->free(reply);
				return status;
			}
		}

		default:
			// unrecognized messages go to neighbor discovery protocol handler
			return sIPv6NDPModule->receive_data(buffer);
	}

	gBufferModule->free(buffer);
	return B_OK;
}
Exemple #8
0
/*!	Address resolver function: prepares and triggers the ARP request necessary
	to retrieve the hardware address for \a address.

	You need to have the sCacheLock held when calling this function.
*/
static status_t
arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address,
	arp_entry **_entry)
{
	ASSERT_LOCKED_MUTEX(&sCacheLock);

	// create an unresolved ARP entry as a placeholder
	arp_entry *entry = arp_entry::Add(address, NULL, 0);
	if (entry == NULL)
		return B_NO_MEMORY;

	// prepare ARP request

	entry->request_buffer = gBufferModule->create(256);
	if (entry->request_buffer == NULL) {
		entry->ScheduleRemoval();
		return B_NO_MEMORY;
	}

	NetBufferPrepend<arp_header> bufferHeader(entry->request_buffer);
	status_t status = bufferHeader.Status();
	if (status < B_OK) {
		entry->ScheduleRemoval();
		return status;
	}

	// prepare ARP header

	net_device *device = protocol->interface->device;
	arp_header &header = bufferHeader.Data();

	header.hardware_type = htons(ARP_HARDWARE_TYPE_ETHER);
	header.protocol_type = htons(ETHER_TYPE_IP);
	header.hardware_length = ETHER_ADDRESS_LENGTH;
	header.protocol_length = sizeof(in_addr_t);
	header.opcode = htons(ARP_OPCODE_REQUEST);

	memcpy(header.hardware_sender, device->address.data, ETHER_ADDRESS_LENGTH);
	if (protocol->interface->address != NULL) {
		header.protocol_sender
			= ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
	} else {
		header.protocol_sender = 0;
			// TODO: test if this actually works - maybe we should use
			// INADDR_BROADCAST instead
	}

	memset(header.hardware_target, 0, ETHER_ADDRESS_LENGTH);
	header.protocol_target = address;

	// prepare source and target addresses

	struct sockaddr_dl &source = *(struct sockaddr_dl *)
		entry->request_buffer->source;
	source.sdl_len = sizeof(sockaddr_dl);
	source.sdl_family = AF_LINK;
	source.sdl_index = device->index;
	source.sdl_type = IFT_ETHER;
	source.sdl_e_type = ETHER_TYPE_ARP;
	source.sdl_nlen = source.sdl_slen = 0;
	source.sdl_alen = ETHER_ADDRESS_LENGTH;
	memcpy(source.sdl_data, device->address.data, ETHER_ADDRESS_LENGTH);

	entry->request_buffer->flags = MSG_BCAST;
		// this is a broadcast packet, we don't need to fill in the destination

	entry->protocol = protocol;
	entry->timer_state = ARP_STATE_REQUEST;
	sStackModule->set_timer(&entry->timer, 0);
		// start request timer

	*_entry = entry;
	return B_OK;
}
Exemple #9
0
status_t
l2cap_receive(HciConnection* conn, net_buffer* buffer)
{
    status_t error = B_OK;
    uint16 dcid;
    uint16 length;

#ifdef DUMP_L2CAP_FRAME
    flowf("DUMP:");
    for (uint i = 0; i < buffer->size; i++) {
        uint8 c = 0;
        gBufferModule->read(buffer, i, &c, 1);
        dprintf("[%x]", c);
    }
    dprintf("\n");
#endif
    // Check packet
    if (buffer->size < sizeof(l2cap_hdr_t)) {
        debugf("invalid L2CAP packet. Packet too small, len=%ld\n", buffer->size);
        gBufferModule->free(buffer);
        return EMSGSIZE;

    }

    // Get L2CAP header
    NetBufferHeaderReader<l2cap_hdr_t> bufferHeader(buffer);
    status_t status = bufferHeader.Status();
    if (status < B_OK) {
        return ENOBUFS;
    }

    length = bufferHeader->length = le16toh(bufferHeader->length);
    dcid = bufferHeader->dcid = le16toh(bufferHeader->dcid);

    debugf("len=%d cid=%x\n", length, dcid);

    bufferHeader.Remove(); // pulling

    // Check payload size
    if (length != buffer->size ) {
        debugf("Payload length mismatch, packetlen=%d, bufferlen=%ld\n",
               length, buffer->size);
        gBufferModule->free(buffer);
        return EMSGSIZE;
    }

    // Process packet
    switch (dcid) {
    case L2CAP_SIGNAL_CID: // L2CAP command
        error = l2cap_process_signal_cmd(conn, buffer);
        break;

    case L2CAP_CLT_CID: // Connectionless packet
        // error = l2cap_cl_receive(buffer);
        flowf("CL FRAME!!\n");
        break;

    default: // Data packet
        error = l2cap_co_receive(conn, buffer, dcid);
        break;
    }

    return (error);

}
/*!	Fragments the incoming buffer and send all fragments via the specified
	\a route.
*/
static status_t
send_fragments(ipv6_protocol* protocol, struct net_route* route,
	net_buffer* buffer, uint32 mtu)
{
	TRACE_SK(protocol, "SendFragments(%lu bytes, mtu %lu)", buffer->size, mtu);

	NetBufferHeaderReader<IPv6Header> originalHeader(buffer);
	if (originalHeader.Status() != B_OK)
		return originalHeader.Status();

	// TODO: currently FragHeader goes always as the last one, but in theory
	// ext. headers like AuthHeader and DestOptions should go after it.
	uint16 headersLength = originalHeader->GetHeaderOffset(buffer);
	uint16 extensionHeadersLength = headersLength
		- sizeof(ip6_hdr) + sizeof(ip6_frag);
	uint32 bytesLeft = buffer->size - headersLength;
	uint32 fragmentOffset = 0;
	status_t status = B_OK;

	// TODO: this is rather inefficient
	net_buffer* headerBuffer = gBufferModule->clone(buffer, false);
	if (headerBuffer == NULL)
		return B_NO_MEMORY;

	status = gBufferModule->remove_trailer(headerBuffer, bytesLeft);
	if (status != B_OK)
		return status;

	uint8 data[bytesLeft];
	status = gBufferModule->read(buffer, headersLength, data, bytesLeft);
	if (status != B_OK)
		return status;

	// TODO (from ipv4): we need to make sure all header space is contiguous or
	// use another construct.
	NetBufferHeaderReader<IPv6Header> bufferHeader(headerBuffer);

	// Adapt MTU to be a multiple of 8 (fragment offsets can only be specified
	// this way)
	mtu -= headersLength + sizeof(ip6_frag);
	mtu &= ~7;
	TRACE("  adjusted MTU to %ld, bytesLeft %ld", mtu, bytesLeft);

	while (bytesLeft > 0) {
		uint32 fragmentLength = min_c(bytesLeft, mtu);
		bytesLeft -= fragmentLength;
		bool lastFragment = bytesLeft == 0;

		bufferHeader->header.ip6_nxt = IPPROTO_FRAGMENT;
		bufferHeader->header.ip6_plen
			= htons(fragmentLength + extensionHeadersLength);
		bufferHeader.Sync();

		ip6_frag fragmentHeader;
		fragmentHeader.ip6f_nxt = originalHeader->NextHeader();
		fragmentHeader.ip6f_reserved = 0;
		fragmentHeader.ip6f_offlg = htons(fragmentOffset) & IP6F_OFF_MASK;
		if (!lastFragment)
			fragmentHeader.ip6f_offlg |= IP6F_MORE_FRAG;
		fragmentHeader.ip6f_ident = htonl(atomic_add(&sFragmentID, 1));

		TRACE("  send fragment of %ld bytes (%ld bytes left)", fragmentLength,
			bytesLeft);

		net_buffer* fragmentBuffer;
		if (!lastFragment)
			fragmentBuffer = gBufferModule->clone(headerBuffer, false);
		else
			fragmentBuffer = buffer;

		if (fragmentBuffer == NULL) {
			status = B_NO_MEMORY;
			break;
		}

		// copy data to fragment
		do {
			status = gBufferModule->append(
				fragmentBuffer, &fragmentHeader, sizeof(ip6_frag));
			if (status != B_OK)
				break;

			status = gBufferModule->append(
				fragmentBuffer, &data[fragmentOffset], fragmentLength);
			if (status != B_OK)
				break;

			// send fragment
			status = sDatalinkModule->send_routed_data(route, fragmentBuffer);
		} while (false);

		if (lastFragment) {
			// we don't own the last buffer, so we don't have to free it
			break;
		}

		if (status != B_OK) {
			gBufferModule->free(fragmentBuffer);
			break;
		}

		fragmentOffset += fragmentLength;
	}

	gBufferModule->free(headerBuffer);
	return status;
}
status_t
ipv6_receive_data(net_buffer* buffer)
{
	TRACE("ReceiveData(%p [%ld bytes])", buffer, buffer->size);

	NetBufferHeaderReader<IPv6Header> bufferHeader(buffer);
	if (bufferHeader.Status() != B_OK)
		return bufferHeader.Status();

	IPv6Header &header = bufferHeader.Data();
	// dump_ipv6_header(header);

	if (header.ProtocolVersion() != IPV6_VERSION)
		return B_BAD_TYPE;

	uint16 packetLength = header.PayloadLength() + sizeof(ip6_hdr);
	if (packetLength > buffer->size)
		return B_BAD_DATA;

	// lower layers notion of Broadcast or Multicast have no relevance to us
	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);

	sockaddr_in6 destination;
	fill_sockaddr_in6(&destination, header.Dst());

	if (IN6_IS_ADDR_MULTICAST(&destination.sin6_addr)) {
		buffer->flags |= MSG_MCAST;
	} else {
		uint32 matchedAddressType = 0;

		// test if the packet is really for us
		if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
				&buffer->interface_address, &matchedAddressType)
			&& !sDatalinkModule->is_local_link_address(sDomain, true,
				buffer->destination, &buffer->interface_address)) {

			char srcbuf[INET6_ADDRSTRLEN];
			char dstbuf[INET6_ADDRSTRLEN];
			ip6_sprintf(&header.Src(), srcbuf);
			ip6_sprintf(&header.Dst(), dstbuf);
			TRACE("  ipv6_receive_data(): packet was not for us %s -> %s",
				srcbuf, dstbuf);

			// TODO: Send ICMPv6 error: Host unreachable
			return B_ERROR;
		}

		// copy over special address types (MSG_BCAST or MSG_MCAST):
		buffer->flags |= matchedAddressType;
	}

	// set net_buffer's source/destination address
	fill_sockaddr_in6((struct sockaddr_in6*)buffer->source, header.Src());
	memcpy(buffer->destination, &destination, sizeof(sockaddr_in6));

	// get the transport protocol and transport header offset
	uint16 transportHeaderOffset = header.GetHeaderOffset(buffer);
	uint8 protocol = buffer->protocol;

	// remove any trailing/padding data
	status_t status = gBufferModule->trim(buffer, packetLength);
	if (status != B_OK)
		return status;

	// check for fragmentation
	uint16 fragmentHeaderOffset
		= header.GetHeaderOffset(buffer, IPPROTO_FRAGMENT);

	if (fragmentHeaderOffset != 0) {
		// this is a fragment
		TRACE("  ipv6_receive_data(): Found a Fragment!");
		status = reassemble_fragments(header, &buffer, fragmentHeaderOffset);
		TRACE("  ipv6_receive_data():  -> %s", strerror(status));
		if (status != B_OK)
			return status;

		if (buffer == NULL) {
			// buffer was put into fragment packet
			TRACE("  ipv6_receive_data(): Not yet assembled.");
			return B_OK;
		}
	}

	// tell the buffer to preserve removed ipv6 header - may need it later
	gBufferModule->store_header(buffer);

	// remove ipv6 headers for now
	gBufferModule->remove_header(buffer, transportHeaderOffset);

	// deliver the data to raw sockets
	raw_receive_data(buffer);

	net_protocol_module_info* module = receiving_protocol(protocol);
	if (module == NULL) {
		// no handler for this packet
		return EAFNOSUPPORT;
	}

	if ((buffer->flags & MSG_MCAST) != 0) {
		// Unfortunately historical reasons dictate that the IP multicast
		// model be a little different from the unicast one. We deliver
		// this frame directly to all sockets registered with interest
		// for this multicast group.
		return deliver_multicast(module, buffer, false);
	}

	return module->receive_data(buffer);
}
Exemple #12
0
status_t
tcp_receive_data(net_buffer* buffer)
{
	TRACE(("TCP: Received buffer %p\n", buffer));

	if (buffer->interface_address == NULL
		|| buffer->interface_address->domain == NULL)
		return B_ERROR;

	net_domain* domain = buffer->interface_address->domain;
	net_address_module_info* addressModule = domain->address_module;

	NetBufferHeaderReader<tcp_header> bufferHeader(buffer);
	if (bufferHeader.Status() < B_OK)
		return bufferHeader.Status();

	tcp_header& header = bufferHeader.Data();

	uint16 headerLength = header.HeaderLength();
	if (headerLength < sizeof(tcp_header))
		return B_BAD_DATA;

	if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer,
			IPPROTO_TCP) != 0)
		return B_BAD_DATA;

	addressModule->set_port(buffer->source, header.source_port);
	addressModule->set_port(buffer->destination, header.destination_port);

	TRACE(("  Looking for: peer %s, local %s\n",
		AddressString(domain, buffer->source, true).Data(),
		AddressString(domain, buffer->destination, true).Data()));
	//dump_tcp_header(header);
	//gBufferModule->dump(buffer);

	tcp_segment_header segment(header.flags);
	segment.sequence = header.Sequence();
	segment.acknowledge = header.Acknowledge();
	segment.advertised_window = header.AdvertisedWindow();
	segment.urgent_offset = header.UrgentOffset();
	process_options(segment, buffer, headerLength - sizeof(tcp_header));

	bufferHeader.Remove(headerLength);
		// we no longer need to keep the header around

	EndpointManager* endpointManager = endpoint_manager_for(domain);
	if (endpointManager == NULL) {
		TRACE(("  No endpoint manager!\n"));
		return B_ERROR;
	}

	int32 segmentAction = DROP;

	TCPEndpoint* endpoint = endpointManager->FindConnection(
		buffer->destination, buffer->source);
	if (endpoint != NULL) {
		segmentAction = endpoint->SegmentReceived(segment, buffer);
		gSocketModule->release_socket(endpoint->socket);
	} else if ((segment.flags & TCP_FLAG_RESET) == 0)
		segmentAction = DROP | RESET;

	if ((segmentAction & RESET) != 0) {
		// send reset
		endpointManager->ReplyWithReset(segment, buffer);
	}
	if ((segmentAction & DROP) != 0)
		gBufferModule->free(buffer);

	return B_OK;
}
Exemple #13
0
status_t
domain_receive_data(net_buffer *buffer)
{
	static bigtime_t lastTime = 0;

	uint32 packetNumber = atomic_add(&sPacketNumber, 1);

	bool drop = false;
	if (sDropList.find(packetNumber) != sDropList.end()
		|| (sRandomDrop > 0.0 && (1.0 * rand() / RAND_MAX) > sRandomDrop))
		drop = true;

	if (!drop && (sRoundTripTime > 0 || sRandomRoundTrip || sIncreasingRoundTrip)) {
		bigtime_t add = 0;
		if (sRandomRoundTrip)
			add = (bigtime_t)(1.0 * rand() / RAND_MAX * 500000) - 250000;
		if (sIncreasingRoundTrip)
			sRoundTripTime += (bigtime_t)(1.0 * rand() / RAND_MAX * 150000);

		snooze(sRoundTripTime / 2 + add);
	}

	if (sTCPDump) {
		NetBufferHeaderReader<tcp_header> bufferHeader(buffer);
		if (bufferHeader.Status() < B_OK)
			return bufferHeader.Status();

		tcp_header &header = bufferHeader.Data();

		bigtime_t now = system_time();
		if (lastTime == 0)
			lastTime = now;

		printf("\33[0m% 3ld %8.6f (%8.6f) ", packetNumber, (now - sStartTime) / 1000000.0,
			(now - lastTime) / 1000000.0);
		lastTime = now;

		if (is_server((sockaddr *)buffer->source))
			printf("\33[31mserver > client: ");
		else
			printf("client > server: ");

		int32 length = buffer->size - header.HeaderLength();

		if ((header.flags & TCP_FLAG_PUSH) != 0)
			putchar('P');
		if ((header.flags & TCP_FLAG_SYNCHRONIZE) != 0)
			putchar('S');
		if ((header.flags & TCP_FLAG_FINISH) != 0)
			putchar('F');
		if ((header.flags & TCP_FLAG_RESET) != 0)
			putchar('R');
		if ((header.flags
			& (TCP_FLAG_SYNCHRONIZE | TCP_FLAG_FINISH | TCP_FLAG_PUSH | TCP_FLAG_RESET)) == 0)
			putchar('.');

		printf(" %lu:%lu (%lu)", header.Sequence(), header.Sequence() + length, length);
		if ((header.flags & TCP_FLAG_ACKNOWLEDGE) != 0)
			printf(" ack %lu", header.Acknowledge());

		printf(" win %u", header.AdvertisedWindow());

		if (header.HeaderLength() > sizeof(tcp_header)) {
			int32 size = header.HeaderLength() - sizeof(tcp_header);

			tcp_option *option;
			uint8 optionsBuffer[1024];
			if (gBufferModule->direct_access(buffer, sizeof(tcp_header),
					size, (void **)&option) != B_OK) {
				if (size > 1024) {
					printf("options too large to take into account (%ld bytes)\n", size);
					size = 1024;
				}

				gBufferModule->read(buffer, sizeof(tcp_header), optionsBuffer, size);
				option = (tcp_option *)optionsBuffer;
			}

			while (size > 0) {
				uint32 length = 1;
				switch (option->kind) {
					case TCP_OPTION_END:
					case TCP_OPTION_NOP:
						break;
					case TCP_OPTION_MAX_SEGMENT_SIZE:
						printf(" <mss %u>", ntohs(option->max_segment_size));
						length = 4;
						break;
					case TCP_OPTION_WINDOW_SHIFT:
						printf(" <ws %u>", option->window_shift);
						length = 3;
						break;
					case TCP_OPTION_TIMESTAMP:
						printf(" <ts %lu:%lu>", option->timestamp.value, option->timestamp.reply);
						length = 10;
						break;

					default:
						length = option->length;
						// make sure we don't end up in an endless loop
						if (length == 0)
							size = 0;
						break;
				}

				size -= length;
				option = (tcp_option *)((uint8 *)option + length);
			}
		}

		if (drop)
			printf(" <DROPPED>");
		printf("\33[0m\n");
	} else if (drop)
		printf("<**** DROPPED %ld ****>\n", packetNumber);

	if (drop) {
		gNetBufferModule.free(buffer);
		return B_OK;
	}

	return gTCPModule->receive_data(buffer);
}