netinet/in.h: Add IP_DONTFRAG socket option, and implement for IPv4.
To allow consumers to cause the "don't fragment" bit to be set in all IPv4 packet headers. There is no standard way of doing this, and different OSes expose this option in different ways. Linux has "IP_MTU_DISCOVER", but it takes an enum, not a boolean. NetBSD and OpenBSD appear to have no socket option, instead they have "IP_MTUDISC", an option for the "ip_output()" kernel-level network stack method. "IP_DONTFRAG" sockopt originates on FreeBSD, and it seems macOS now also supports it in version 11+. Windows has "IP_DONTFRAGMENT", which, at a glance, appears to do the same thing. So this looks like the one that makes the most sense to adopt. This doesn't add any code to process MTU changes yet, though. Change-Id: I492d22dbd0ee5f4ab35c600396ad3d3ec9f4f200 Reviewed-on: https://review.haiku-os.org/c/haiku/+/9401 Reviewed-by: waddlesplash <[email protected]> Tested-by: Commit checker robot <[email protected]> Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
d31febdefa
commit
83aa27ada6
@@ -164,6 +164,8 @@ struct group_source_req {
|
|||||||
#define IPV6_DSTOPTS 36 /* struct ip6_dest */
|
#define IPV6_DSTOPTS 36 /* struct ip6_dest */
|
||||||
#define IPV6_RTHDR 37 /* struct ip6_rthdr */
|
#define IPV6_RTHDR 37 /* struct ip6_rthdr */
|
||||||
|
|
||||||
|
#define IP_DONTFRAG 38 /* bool; don't fragment */
|
||||||
|
|
||||||
|
|
||||||
#define INADDR_ANY ((in_addr_t)0x00000000)
|
#define INADDR_ANY ((in_addr_t)0x00000000)
|
||||||
#define INADDR_LOOPBACK ((in_addr_t)0x7f000001)
|
#define INADDR_LOOPBACK ((in_addr_t)0x7f000001)
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ struct ipv4_protocol : net_protocol {
|
|||||||
// protocol flags
|
// protocol flags
|
||||||
#define IP_FLAG_HEADER_INCLUDED 0x01
|
#define IP_FLAG_HEADER_INCLUDED 0x01
|
||||||
#define IP_FLAG_RECEIVE_DEST_ADDR 0x02
|
#define IP_FLAG_RECEIVE_DEST_ADDR 0x02
|
||||||
|
#define IP_FLAG_DONT_FRAGMENT 0x04
|
||||||
|
|
||||||
|
|
||||||
static const int kDefaultTTL = 254;
|
static const int kDefaultTTL = 254;
|
||||||
@@ -1203,6 +1204,10 @@ ipv4_getsockopt(net_protocol* _protocol, int level, int option, void* value,
|
|||||||
return get_int_option(value, *_length,
|
return get_int_option(value, *_length,
|
||||||
(protocol->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0);
|
(protocol->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0);
|
||||||
}
|
}
|
||||||
|
if (option == IP_DONTFRAG) {
|
||||||
|
return get_int_option(value, *_length,
|
||||||
|
(protocol->flags & IP_FLAG_DONT_FRAGMENT) != 0);
|
||||||
|
}
|
||||||
if (option == IP_TTL)
|
if (option == IP_TTL)
|
||||||
return get_int_option(value, *_length, protocol->time_to_live);
|
return get_int_option(value, *_length, protocol->time_to_live);
|
||||||
if (option == IP_TOS)
|
if (option == IP_TOS)
|
||||||
@@ -1302,6 +1307,21 @@ ipv4_setsockopt(net_protocol* _protocol, int level, int option,
|
|||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
if (option == IP_DONTFRAG) {
|
||||||
|
int headerIncluded;
|
||||||
|
if (length != sizeof(int))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (user_memcpy(&headerIncluded, value, sizeof(headerIncluded))
|
||||||
|
!= B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
if (headerIncluded)
|
||||||
|
protocol->flags |= IP_FLAG_DONT_FRAGMENT;
|
||||||
|
else
|
||||||
|
protocol->flags &= ~IP_FLAG_DONT_FRAGMENT;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
if (option == IP_TTL)
|
if (option == IP_TTL)
|
||||||
return set_int_option(protocol->time_to_live, value, length);
|
return set_int_option(protocol->time_to_live, value, length);
|
||||||
if (option == IP_TOS)
|
if (option == IP_TOS)
|
||||||
@@ -1521,7 +1541,9 @@ ipv4_send_routed_data(net_protocol* _protocol, struct net_route* route,
|
|||||||
header->total_length = htons(buffer->size);
|
header->total_length = htons(buffer->size);
|
||||||
header->id = htons(atomic_add(&sPacketID, 1));
|
header->id = htons(atomic_add(&sPacketID, 1));
|
||||||
header->fragment_offset = 0;
|
header->fragment_offset = 0;
|
||||||
if (protocol) {
|
if (protocol != NULL) {
|
||||||
|
if ((protocol->flags & IP_FLAG_DONT_FRAGMENT) != 0)
|
||||||
|
header->fragment_offset |= htons(IP_DONT_FRAGMENT);
|
||||||
header->time_to_live = (buffer->msg_flags & MSG_MCAST) != 0
|
header->time_to_live = (buffer->msg_flags & MSG_MCAST) != 0
|
||||||
? protocol->multicast_time_to_live : protocol->time_to_live;
|
? protocol->multicast_time_to_live : protocol->time_to_live;
|
||||||
} else {
|
} else {
|
||||||
@@ -1602,6 +1624,9 @@ ipv4_send_routed_data(net_protocol* _protocol, struct net_route* route,
|
|||||||
|
|
||||||
uint32 mtu = route->mtu ? route->mtu : interface->device->mtu;
|
uint32 mtu = route->mtu ? route->mtu : interface->device->mtu;
|
||||||
if (buffer->size > mtu) {
|
if (buffer->size > mtu) {
|
||||||
|
if (protocol != NULL && (protocol->flags & IP_FLAG_DONT_FRAGMENT) != 0)
|
||||||
|
return EMSGSIZE;
|
||||||
|
|
||||||
// we need to fragment the packet
|
// we need to fragment the packet
|
||||||
return send_fragments(protocol, route, buffer, mtu);
|
return send_fragments(protocol, route, buffer, mtu);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user