From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/socket.c | 8 +++++- dlls/ws2_32/tests/sock.c | 6 ++--- server/sock.c | 53 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 8a87805815c..b51f05e3b5c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1173,7 +1173,13 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) return -1; } break; - + case AF_BTH: + if (len < sizeof(SOCKADDR_BTH)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; default: FIXME( "unknown protocol %u\n", addr->sa_family ); SetLastError( WSAEAFNOSUPPORT ); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 2aaa64d47b2..38cb9eafc6c 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -12827,19 +12827,19 @@ static void test_bind_bluetooth(void) ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); err = WSAGetLastError(); ok(ret == -1, "expected bind to fail\n"); - todo_wine ok(err == WSAEADDRNOTAVAIL || err == WSAENETDOWN, "got error %d\n", err); + ok(err == WSAEADDRNOTAVAIL || err == WSAENETDOWN, "got error %d\n", err);
addr.port = 20; ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); err = WSAGetLastError(); - todo_wine ok(!ret || err == WSAENETDOWN, "got error %d\n", err); + ok(!ret || err == WSAENETDOWN, "got error %d\n", err);
sock2 = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); ok(sock2 != INVALID_SOCKET, "got error %d\n", WSAGetLastError()); addr.port = BT_PORT_ANY; ret = bind(sock2, (struct sockaddr *)&addr, sizeof(addr)); err = WSAGetLastError(); - todo_wine ok(!ret || err == WSAENETDOWN, "got error %d\n", err); + ok(!ret || err == WSAENETDOWN, "got error %d\n", err);
closesocket(sock); closesocket(sock2); diff --git a/server/sock.c b/server/sock.c index 909b10fed49..181e4af8646 100644 --- a/server/sock.c +++ b/server/sock.c @@ -680,6 +680,24 @@ static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrl } #endif
+#ifdef HAS_BLUETOOTH + case WS_AF_BTH: + { + SOCKADDR_BTH win = {0}; + BLUETOOTH_ADDRESS addr = {0}; + + if (wsaddrlen != sizeof(win)) return 0; + memcpy( &win, wsaddr, sizeof(win) ); + addr.ullLong = win.btAddr; + + uaddr->rfcomm.rc_family = AF_BLUETOOTH; + memcpy( &uaddr->rfcomm.rc_bdaddr, addr.rgBytes, sizeof( addr.rgBytes ) ); + /* There can only be a maximum of 30 RFCOMM channels, so UINT8_MAX is safe to use here. */ + uaddr->rfcomm.rc_channel = win.port == BT_PORT_ANY ? UINT8_MAX : win.port; + return sizeof(uaddr->rfcomm); + } +#endif + case WS_AF_UNSPEC: switch (wsaddrlen) { @@ -3065,6 +3083,41 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (check_addr_usage( sock, &bind_addr, v6only )) return;
+#ifdef HAS_BLUETOOTH + if (unix_addr.rfcomm.rc_family == AF_BLUETOOTH + && !(unix_addr.rfcomm.rc_channel >= 1 && unix_addr.rfcomm.rc_channel <= 30)) + { + int i; + if (unix_addr.rfcomm.rc_channel != UINT8_MAX) + { + set_error( sock_get_ntstatus( EADDRNOTAVAIL ) ); + return; + } + /* If the RFCOMM channel was set to BT_PORT_ANY, we need to find an available RFCOMM + * channel. The Linux kernel has a similar mechanism, but the channel is only assigned + * on listen(), which we cannot call yet. The other, albeit hacky/race-y way to find an available + * channel is to loop through all valid channel values (1 to 30) until bind() succeeds. + */ + for (i = 1; i <= 30; i++) + { + bind_addr.rfcomm.rc_channel = i; + if (!bind( unix_fd, &bind_addr.addr, unix_len )) + break; + if (errno != EADDRINUSE) + { + set_error( sock_get_ntstatus( errno ) ); + return; + } + } + if (i > 30) + { + + set_error( sock_get_ntstatus( EADDRINUSE ) ); + return; + } + } + else +#endif if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0) { if (errno == EADDRINUSE && sock->reuseaddr)