[PATCH 3/4] ntdll: Support SOCK_RAW / IPPROTO_ICMP fallback over SOCK_DGRAM.
Zebediah Figura
zfigura at codeweavers.com
Tue Jul 12 21:58:40 CDT 2022
On 7/5/22 14:53, Paul Gofman wrote:
@@ -602,9 +623,68 @@ static NTSTATUS try_recv( int fd, struct
async_recv_ioctl *async, ULONG_PTR *siz
}
status = (hdr.msg_flags & MSG_TRUNC) ? STATUS_BUFFER_OVERFLOW :
STATUS_SUCCESS;
+ if (async->fixup_type == SOCK_PROT_FIXUP_ICMP_OVER_DGRAM)
+ {
+ unsigned int tot_len = sizeof(struct ip_hdr) + ret;
+ size_t len = hdr.msg_iov[0].iov_len;
+ char *buf = hdr.msg_iov[0].iov_base;
+ struct cmsghdr *cmsg;
+ struct ip_hdr ip_h;
+
+ if (ret + sizeof(ip_h) > len)
+ status = STATUS_BUFFER_OVERFLOW;
+
+ if (len < sizeof(ip_h))
+ {
+ ret = len;
+ }
+ else
+ {
+ ret = min( ret, len - sizeof(ip_h) );
+ memmove( buf + sizeof(ip_h), buf, ret );
+ ret += sizeof(ip_h);
+ }
+ memset( &ip_h, 0, sizeof(ip_h) );
+ ip_h.v_hl = (4 << 4) | (sizeof(ip_h) >> 2);
+ ip_h.tot_len = htons( tot_len );
+ ip_h.protocol = 1;
+ ip_h.saddr = unix_addr.in.sin_addr.s_addr;
+
+ for (cmsg = CMSG_FIRSTHDR( &hdr ); cmsg; cmsg = CMSG_NXTHDR(
&hdr, cmsg ))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP) continue;
+ switch (cmsg->cmsg_type)
+ {
+#if defined(IP_TTL)
+ case IP_TTL:
+ ip_h.ttl = *(BYTE *)CMSG_DATA( cmsg );
+ break;
+#endif
+#if defined(IP_TOS)
+ case IP_TOS:
+ ip_h.tos = *(BYTE *)CMSG_DATA( cmsg );
+ break;
+#endif
+#if defined(IP_PKTINFO)
+ case IP_PKTINFO:
+ {
+ struct in_pktinfo *info;
+
+ info = (struct in_pktinfo *)CMSG_DATA( cmsg );
+ ip_h.daddr = info->ipi_addr.s_addr;
+ break;
+ }
+#endif
+ }
+ }
+ memcpy( buf, &ip_h, min( sizeof(ip_h), len ));
+ }
Would you mind making this a helper function? try_recv() is already
large and this seems to be pretty self-contained logic.
> if (async->control)
> {
> + if (async->fixup_type == SOCK_PROT_FIXUP_ICMP_OVER_DGRAM)
> + FIXME( "May return extra control headers.\n" );
> +
What is this for?
> @@ -737,17 +818,26 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
> }
> }
>
> - SERVER_START_REQ( recv_socket )
> + do
> {
> - req->force_async = force_async;
> - req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) );
> - req->oob = !!(unix_flags & MSG_OOB);
> - status = wine_server_call( req );
> - wait_handle = wine_server_ptr_handle( reply->wait );
> - options = reply->options;
> - nonblocking = reply->nonblocking;
> - }
> - SERVER_END_REQ;
> + SERVER_START_REQ( recv_socket )
> + {
> + req->force_async = force_async;
> + req->async = server_async( handle, &async->io, event, apc, apc_user, iosb_client_ptr(io) );
> + req->oob = !!(unix_flags & MSG_OOB);
> + req->fixup_type = async->fixup_type;
> + status = wine_server_call( req );
> + if (status == STATUS_MORE_PROCESSING_REQUIRED)
> + {
> + async->fixup_type = reply->fixup_type;
> + continue;
> + }
> + wait_handle = wine_server_ptr_handle( reply->wait );
> + options = reply->options;
> + nonblocking = reply->nonblocking;
> + }
> + SERVER_END_REQ;
> + } while (status == STATUS_MORE_PROCESSING_REQUIRED);
>
> alerted = status == STATUS_ALERTED;
> if (alerted)
I'm missing something; why do we need to call this in a loop? Why does
the client needs to communicate the fixup type to the server in the
first place?
> diff --git a/server/protocol.def b/server/protocol.def
> index a8beccaf468..e1e5f3d9faa 100644
> --- a/server/protocol.def
> +++ b/server/protocol.def
> @@ -1446,17 +1446,23 @@ enum server_fd_type
> file_pos_t count; /* count of bytes to unlock */
> @END
>
> -
> /* Perform a recv on a socket */
> @REQ(recv_socket)
> int oob; /* are we receiving OOB data? */
> async_data_t async; /* async I/O parameters */
> int force_async; /* Force asynchronous mode? */
> + int fixup_type; /* protocol fixup type returned previously */
> @REPLY
> obj_handle_t wait; /* handle to wait on for blocking recv */
> unsigned int options; /* device open options */
> int nonblocking; /* is socket non-blocking? */
> + int fixup_type; /* protocol fixup type (see below) */
> @END
> +enum sock_prot_fixup_type
> +{
> + SOCK_PROT_FIXUP_NONE,
> + SOCK_PROT_FIXUP_ICMP_OVER_DGRAM,
> +};
Making this an enum strikes me as odd in general. A bitmask might make
more sense, but frankly I'd just leave it as a dedicated field until we
have something else that needs fixups.
Do you have any plans for introducing other types of fixups?
More information about the wine-devel
mailing list