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