diff --git a/headers/private/net/NetBufferUtilities.h b/headers/private/net/NetBufferUtilities.h index 7d8b467c02..349d15c926 100644 --- a/headers/private/net/NetBufferUtilities.h +++ b/headers/private/net/NetBufferUtilities.h @@ -22,56 +22,49 @@ class NetBufferFieldReader { public: NetBufferFieldReader(net_buffer *buffer) : - fBuffer(buffer), - fStatus(B_BAD_VALUE) + fBuffer(buffer) { - if ((Offset + sizeof(Type)) <= buffer->size) { - fStatus = Module::Get()->direct_access(fBuffer, Offset, - sizeof(Type), (void **)&fData); - if (fStatus != B_OK) { - fData = NULL; - fStatus = Module::Get()->read(fBuffer, Offset, - &fDataBuffer, sizeof(Type)); - } + fStatus = Module::Get()->direct_access(fBuffer, Offset, + sizeof(Type), (void **)&fData); + if (fStatus != B_OK) { + fStatus = Module::Get()->read(fBuffer, Offset, + &fDataBuffer, sizeof(Type)); + fData = &fDataBuffer; } } status_t - Status() + Status() const { return fStatus; } Type & - Data() + Data() const { - if (fData != NULL) - return *fData; - - return fDataBuffer; + return *fData; } Type * - operator->() + operator->() const { - return &Data(); + return fData; } Type & - operator*() + operator*() const { - return Data(); + return *fData; } void Sync() { - if (fBuffer == NULL) + if (fBuffer == NULL || fStatus < B_OK) return; - if (fData == NULL) - Module::Get()->write(fBuffer, Offset, &fDataBuffer, - sizeof(Type)); + if (fData == &fDataBuffer) + Module::Get()->write(fBuffer, Offset, fData, sizeof(Type)); fBuffer = NULL; } @@ -138,15 +131,14 @@ class NetBufferHeaderRemover : public NetBufferHeaderReader { template class NetBufferPrepend : public NetBufferFieldReader { public: - NetBufferPrepend(net_buffer *buffer, size_t size = 0) + NetBufferPrepend(net_buffer *buffer, size_t size = sizeof(Type)) { fBuffer = buffer; - fData = NULL; - if (size == 0) - size = sizeof(Type); - - fStatus = Module::Get()->prepend_size(buffer, size, (void **)&fData); + fStatus = Module::Get()->prepend_size(buffer, size, + (void **)&fData); + if (fStatus == B_OK && fData == NULL) + fData = &fDataBuffer; } ~NetBufferPrepend() diff --git a/headers/private/net/net_datalink.h b/headers/private/net/net_datalink.h index 2f324a912e..b93adc972d 100644 --- a/headers/private/net/net_datalink.h +++ b/headers/private/net/net_datalink.h @@ -79,6 +79,8 @@ struct net_datalink_module_info { const struct net_route *route); struct net_route *(*get_route)(struct net_domain *domain, const struct sockaddr *address); + status_t (*get_buffer_route)(struct net_domain *domain, + struct net_buffer *buffer, struct net_route **_route); void (*put_route)(struct net_domain *domain, struct net_route *route); status_t (*register_route_info)(struct net_domain *domain, @@ -118,6 +120,8 @@ struct net_address_module_info { status_t (*set_to)(sockaddr *address, const sockaddr *from); status_t (*set_to_empty_address)(sockaddr *address); + status_t (*update_to)(sockaddr *address, const sockaddr *from); + uint32 (*hash_address_pair)(const sockaddr *ourAddress, const sockaddr *peerAddress); diff --git a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp index 7299466831..15b866d2a9 100644 --- a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp +++ b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp @@ -257,8 +257,8 @@ icmp_receive_data(net_buffer *buffer) header.Sync(); - ICMPChecksumField checksum(reply); - *checksum = gBufferModule->checksum(reply, 0, reply->size, true); + *ICMPChecksumField(reply) = gBufferModule->checksum(reply, 0, + reply->size, true); status_t status = domain->module->send_data(NULL, reply); if (status < B_OK) { diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index c56e792585..1a083d012b 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -671,15 +671,6 @@ receiving_protocol(uint8 protocol) } -static void -update_checksum(net_buffer *buffer) -{ - IPChecksumField checksum(buffer); - - *checksum = gBufferModule->checksum(buffer, 0, sizeof(ipv4_header), true); -} - - // #pragma mark - @@ -928,49 +919,31 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route, TRACE(("someone tries to send some actual routed data!\n")); sockaddr_in &source = *(sockaddr_in *)&buffer->source; - if (source.sin_addr.s_addr == INADDR_ANY && route->interface->address != NULL) { - // replace an unbound source address with the address of the interface - // TODO: couldn't we replace all addresses here? - source.sin_addr.s_addr = ((sockaddr_in *)route->interface->address)->sin_addr.s_addr; - } + sockaddr_in &destination = *(sockaddr_in *)&buffer->destination; - bool headerIncluded = false; + bool headerIncluded = false, checksumNeeded = true; if (protocol != NULL) headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0; // Add IP header (if needed) if (!headerIncluded) { - NetBufferPrepend bufferHeader(buffer); - if (bufferHeader.Status() < B_OK) - return bufferHeader.Status(); + NetBufferPrepend header(buffer); + if (header.Status() < B_OK) + return header.Status(); - ipv4_header &header = bufferHeader.Data(); - - header.version = IP_VERSION; - header.header_length = sizeof(ipv4_header) >> 2; - header.service_type = protocol ? protocol->service_type : 0; - header.total_length = htons(buffer->size); - header.id = htons(atomic_add(&sPacketID, 1)); - header.fragment_offset = 0; - header.time_to_live = protocol ? protocol->time_to_live : 254; - header.protocol = protocol ? protocol->socket->protocol : buffer->protocol; - header.checksum = 0; - if (route->interface->address != NULL) { - header.source = ((sockaddr_in *)route->interface->address)->sin_addr.s_addr; - // always use the actual used source address - } else - header.source = 0; - - header.destination = ((sockaddr_in *)&buffer->destination)->sin_addr.s_addr; - - bufferHeader.Sync(); - // make sure the IP-header is already written to the - // buffer at this point - - update_checksum(buffer); - //dump_ipv4_header(header); + header->version = IP_VERSION; + header->header_length = sizeof(ipv4_header) / 4; + header->service_type = protocol ? protocol->service_type : 0; + header->total_length = htons(buffer->size); + header->id = htons(atomic_add(&sPacketID, 1)); + header->fragment_offset = 0; + header->time_to_live = protocol ? protocol->time_to_live : 254; + header->protocol = protocol ? protocol->socket->protocol : buffer->protocol; + header->checksum = 0; + header->source = source.sin_addr.s_addr; + header->destination = destination.sin_addr.s_addr; } else { // if IP_HDRINCL, check if the source address is set NetBufferHeaderReader header(buffer); @@ -980,22 +953,24 @@ ipv4_send_routed_data(net_protocol *_protocol, struct net_route *route, if (header->source == 0) { header->source = source.sin_addr.s_addr; header->checksum = 0; - header.Sync(); - - update_checksum(buffer); - } + } else + checksumNeeded = false; } if (buffer->size > 0xffff) return EMSGSIZE; + if (checksumNeeded) + *IPChecksumField(buffer) = gBufferModule->checksum(buffer, 0, + sizeof(ipv4_header), true); + TRACE(("header chksum: %ld, buffer checksum: %ld\n", gBufferModule->checksum(buffer, 0, sizeof(ipv4_header), true), gBufferModule->checksum(buffer, 0, buffer->size, true))); TRACE(("destination-IP: buffer=%p addr=%p %08lx\n", buffer, &buffer->destination, - ntohl(((sockaddr_in *)&buffer->destination)->sin_addr.s_addr))); + ntohl(destination->sin_addr.s_addr))); uint32 mtu = route->mtu ? route->mtu : interface->mtu; if (buffer->size > mtu) { @@ -1012,14 +987,13 @@ ipv4_send_data(net_protocol *protocol, net_buffer *buffer) { TRACE(("someone tries to send some actual data!\n")); - // find route - struct net_route *route = sDatalinkModule->get_route(sDomain, - (sockaddr *)&buffer->destination); - if (route == NULL) - return ENETUNREACH; - - status_t status = ipv4_send_routed_data(protocol, route, buffer); - sDatalinkModule->put_route(sDomain, route); + net_route *route = NULL; + status_t status = sDatalinkModule->get_buffer_route(sDomain, buffer, + &route); + if (status >= B_OK) { + status = ipv4_send_routed_data(protocol, route, buffer); + sDatalinkModule->put_route(sDomain, route); + } return status; } diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp index 5e3cc99353..e9cc2b297b 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -251,24 +251,35 @@ ipv4_check_mask(const sockaddr *_mask) \return B_NO_MEMORY if the buffer could not be allocated */ static status_t -ipv4_print_address(const sockaddr *address, char **_buffer, bool printPort) +ipv4_print_address(const sockaddr *_address, char **_buffer, bool printPort) { + const sockaddr_in *address = (const sockaddr_in *)_address; + if (_buffer == NULL) return B_BAD_VALUE; - int bufLen = printPort ? 15 : 9; - char *buffer = (char *)malloc(bufLen); - if (buffer == NULL) - return B_NO_MEMORY; + char tmp[64]; if (address == NULL) - strcpy(buffer, ""); - else if (printPort) { - sprintf(buffer, "%08lx:%u", ntohl(((sockaddr_in *)address)->sin_addr.s_addr), - ntohs(((sockaddr_in *)address)->sin_port)); - } else - sprintf(buffer, "%08lx", ntohl(((sockaddr_in *)address)->sin_addr.s_addr)); - *_buffer = buffer; + strcpy(tmp, ""); + else { + unsigned int addr = ntohl(address->sin_addr.s_addr); + + if (printPort) + sprintf(tmp, "%u.%u.%u.%u:%u", (addr >> 24) & 0xff, + (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff, + ntohs(address->sin_port)); + else + sprintf(tmp, "%u.%u.%u.%u", (addr >> 24) & 0xff, + (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); + } + + *_buffer = strdup(tmp); + if (*_buffer == NULL) + return B_NO_MEMORY; + + + return B_OK; } @@ -324,6 +335,31 @@ ipv4_set_to(sockaddr *address, const sockaddr *from) } +static status_t +ipv4_update_to(sockaddr *_address, const sockaddr *_from) +{ + sockaddr_in *address = (sockaddr_in *)_address; + const sockaddr_in *from = (const sockaddr_in *)_from; + + if (address == NULL || from == NULL) + return B_BAD_VALUE; + + if (from->sin_family != AF_INET) + return B_BAD_VALUE; + + address->sin_family = AF_INET; + address->sin_len = sizeof(sockaddr_in); + + if (address->sin_port == 0) + address->sin_port = from->sin_port; + + if (address->sin_addr.s_addr == INADDR_ANY) + address->sin_addr.s_addr = from->sin_addr.s_addr; + + return B_OK; +} + + /*! Sets \a address to the empty address (0.0.0.0). \return B_OK if \a address has been set @@ -394,6 +430,7 @@ net_address_module_info gIPv4AddressModule = { ipv4_set_port, ipv4_set_to, ipv4_set_to_empty_address, + ipv4_update_to, ipv4_hash_address_pair, ipv4_checksum_address, NULL // ipv4_matches_broadcast_address, diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index 2ea58b91e1..3e476f3c3c 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -170,8 +170,7 @@ add_tcp_header(tcp_segment_header &segment, net_buffer *buffer) << (uint16)htons(buffer->size) << Checksum::BufferHelper(buffer, gBufferModule); - TCPChecksumField checksumField(buffer); - *checksumField = checksum; + *TCPChecksumField(buffer) = checksum; return B_OK; } diff --git a/src/add-ons/kernel/network/protocols/udp/udp.cpp b/src/add-ons/kernel/network/protocols/udp/udp.cpp index 6f73a4ab0b..966be9bb01 100644 --- a/src/add-ons/kernel/network/protocols/udp/udp.cpp +++ b/src/add-ons/kernel/network/protocols/udp/udp.cpp @@ -47,6 +47,10 @@ struct udp_header { } _PACKED; +typedef NetBufferField + UDPChecksumField; + + class UdpEndpoint : public net_protocol { public: UdpEndpoint(net_socket *socket); @@ -766,43 +770,44 @@ UdpEndpoint::SendData(net_buffer *buffer, net_route *route) { if (buffer->size > (0xffff - sizeof(udp_header))) return EMSGSIZE; - + buffer->protocol = IPPROTO_UDP; - { // scope for lifetime of bufferHeader + // add and fill UDP-specific header: + NetBufferPrepend header(buffer); + if (header.Status() < B_OK) + return header.Status(); - // add and fill UDP-specific header: - NetBufferPrepend bufferHeader(buffer); - if (bufferHeader.Status() < B_OK) - return bufferHeader.Status(); - - udp_header &header = bufferHeader.Data(); - - header.source_port = sAddressModule->get_port((sockaddr *)&buffer->source); - header.destination_port = sAddressModule->get_port( - (sockaddr *)&buffer->destination); - header.udp_length = htons(buffer->size); - // the udp-header is already included in the buffer-size - header.udp_checksum = 0; + header->source_port = sAddressModule->get_port((sockaddr *)&buffer->source); + header->destination_port = sAddressModule->get_port( + (sockaddr *)&buffer->destination); + header->udp_length = htons(buffer->size); + // the udp-header is already included in the buffer-size + header->udp_checksum = 0; + + header.Sync(); + + // generate UDP-checksum (simulating a so-called "pseudo-header"): + Checksum udpChecksum; + sAddressModule->checksum_address(&udpChecksum, + (sockaddr *)route->interface->address); + sAddressModule->checksum_address(&udpChecksum, + (sockaddr *)&buffer->destination); + udpChecksum + << (uint16)htons(IPPROTO_UDP) + << (uint16)htons(buffer->size) + // peculiar but correct: UDP-len is used twice for checksum + // (as it is already contained in udp_header) + << Checksum::BufferHelper(buffer, gBufferModule); + + uint16 calculatedChecksum = udpChecksum; + if (calculatedChecksum == 0) + calculatedChecksum = 0xffff; + + *UDPChecksumField(buffer) = calculatedChecksum; + + TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: ")); - // generate UDP-checksum (simulating a so-called "pseudo-header"): - Checksum udpChecksum; - sAddressModule->checksum_address(&udpChecksum, - (sockaddr *)route->interface->address); - sAddressModule->checksum_address(&udpChecksum, - (sockaddr *)&buffer->destination); - udpChecksum - << (uint16)htons(IPPROTO_UDP) - << (uint16)htons(buffer->size) - // peculiar but correct: UDP-len is used twice for checksum - // (as it is already contained in udp_header) - << Checksum::BufferHelper(buffer, gBufferModule); - header.udp_checksum = udpChecksum; - if (header.udp_checksum == 0) - header.udp_checksum = 0xFFFF; - - TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: ")); - } return next->module->send_routed_data(next, route, buffer); } @@ -966,8 +971,8 @@ udp_send_routed_data(net_protocol *protocol, struct net_route *route, net_buffer *buffer) { TRACE(("udp_send_routed_data(%p) size=%lu\n", protocol, buffer->size)); - UdpEndpoint *udpEndpoint = (UdpEndpoint *)protocol; - return udpEndpoint->SendData(buffer, route); + + return ((UdpEndpoint *)protocol)->SendData(buffer, route); } @@ -976,14 +981,14 @@ udp_send_data(net_protocol *protocol, net_buffer *buffer) { TRACE(("udp_send_data(%p) size=%lu\n", protocol, buffer->size)); - struct net_route *route = sDatalinkModule->get_route(sDomain, - (sockaddr *)&buffer->destination); - if (route == NULL) - return ENETUNREACH; + net_route *route = NULL; + status_t status = sDatalinkModule->get_buffer_route(sDomain, buffer, + &route); + if (status >= B_OK) { + status = udp_send_routed_data(protocol, route, buffer); + sDatalinkModule->put_route(sDomain, route); + } - UdpEndpoint *udpEndpoint = (UdpEndpoint *)protocol; - status_t status = udpEndpoint->SendData(buffer, route); - sDatalinkModule->put_route(sDomain, route); return status; } diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index aed13c4d8b..aa37a445b4 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -749,6 +749,7 @@ net_datalink_module_info gNetDatalinkModule = { add_route, remove_route, get_route, + get_buffer_route, put_route, register_route_info, unregister_route_info, diff --git a/src/add-ons/kernel/network/stack/routes.cpp b/src/add-ons/kernel/network/stack/routes.cpp index 552b804775..ad7b27e9f5 100644 --- a/src/add-ons/kernel/network/stack/routes.cpp +++ b/src/add-ons/kernel/network/stack/routes.cpp @@ -535,6 +535,43 @@ get_route(struct net_domain *_domain, const struct sockaddr *address) } +status_t +get_buffer_route(net_domain *_domain, net_buffer *buffer, net_route **_route) +{ + net_domain_private *domain = (net_domain_private *)_domain; + + BenaphoreLocker _(domain->lock); + + net_route *route = get_route_internal(domain, + (sockaddr *)&buffer->destination); + if (route == NULL) + return ENETUNREACH; + + status_t status = B_OK; + sockaddr *source = (sockaddr *)&buffer->source; + + // TODO we are quite relaxed in the address checking here + // as we might proceed with srcaddr=INADDR_ANY. + + if (route->interface && route->interface->address) { + sockaddr *interfaceAddress = route->interface->address; + net_address_module_info *addressModule = domain->address_module; + + if (addressModule->is_empty_address(source, true)) + addressModule->set_to(source, interfaceAddress); + else + status = addressModule->update_to(source, interfaceAddress); + } + + if (status != B_OK) + put_route_internal(domain, route); + else + *_route = route; + + return status; +} + + void put_route(struct net_domain *_domain, net_route *route) { diff --git a/src/add-ons/kernel/network/stack/routes.h b/src/add-ons/kernel/network/stack/routes.h index e41c98e655..7c171cf8d4 100644 --- a/src/add-ons/kernel/network/stack/routes.h +++ b/src/add-ons/kernel/network/stack/routes.h @@ -42,6 +42,8 @@ status_t get_route_information(struct net_domain *domain, void *buffer, void invalidate_routes(net_domain *, net_interface *); struct net_route *get_route(struct net_domain *domain, const struct sockaddr *address); +status_t get_buffer_route(struct net_domain *domain, + struct net_buffer *buffer, struct net_route **_route); void put_route(struct net_domain *domain, struct net_route *route); status_t register_route_info(struct net_domain *domain,