unix: implement RFCOMM sockets on Linux
Add the SockaddrRFCOMM type and the ability to accept BTPROTO_L2CAP and BTPROTO_RFCOMM protocol sockets.
Fixes golang/go#22211
Change-Id: I580b526c5392b90663499af0f2ebe6f55b1f8154
Reviewed-on: https://go-review.googlesource.com/122457
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/linux/types.go b/unix/linux/types.go
index c45b4e7..aa2553c 100644
--- a/unix/linux/types.go
+++ b/unix/linux/types.go
@@ -191,6 +191,13 @@
uint8_t l2_bdaddr_type;
};
+// copied from /usr/include/net/bluetooth/rfcomm.h
+struct sockaddr_rc {
+ sa_family_t rc_family;
+ uint8_t rc_bdaddr[6];
+ uint8_t rc_channel;
+};
+
// copied from /usr/include/linux/un.h
struct my_sockaddr_un {
sa_family_t sun_family;
@@ -401,6 +408,8 @@
type RawSockaddrL2 C.struct_sockaddr_l2
+type RawSockaddrRFCOMM C.struct_sockaddr_rc
+
type RawSockaddrCAN C.struct_sockaddr_can
type RawSockaddrALG C.struct_sockaddr_alg
@@ -450,6 +459,7 @@
SizeofSockaddrNetlink = C.sizeof_struct_sockaddr_nl
SizeofSockaddrHCI = C.sizeof_struct_sockaddr_hci
SizeofSockaddrL2 = C.sizeof_struct_sockaddr_l2
+ SizeofSockaddrRFCOMM = C.sizeof_struct_sockaddr_rc
SizeofSockaddrCAN = C.sizeof_struct_sockaddr_can
SizeofSockaddrALG = C.sizeof_struct_sockaddr_alg
SizeofSockaddrVM = C.sizeof_struct_sockaddr_vm
diff --git a/unix/syscall_bsd.go b/unix/syscall_bsd.go
index 53fb851..33c8b5f 100644
--- a/unix/syscall_bsd.go
+++ b/unix/syscall_bsd.go
@@ -206,7 +206,7 @@
return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_LINK:
pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
@@ -286,7 +286,7 @@
Close(nfd)
return 0, nil, ECONNABORTED
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -306,7 +306,7 @@
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
}
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
@@ -356,7 +356,7 @@
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
diff --git a/unix/syscall_dragonfly.go b/unix/syscall_dragonfly.go
index b5072de..e34abe2 100644
--- a/unix/syscall_dragonfly.go
+++ b/unix/syscall_dragonfly.go
@@ -87,7 +87,7 @@
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
diff --git a/unix/syscall_freebsd.go b/unix/syscall_freebsd.go
index ba9df4a..5561a3e 100644
--- a/unix/syscall_freebsd.go
+++ b/unix/syscall_freebsd.go
@@ -89,7 +89,7 @@
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go
index 9908030..690c2c8 100644
--- a/unix/syscall_linux.go
+++ b/unix/syscall_linux.go
@@ -489,6 +489,47 @@
return unsafe.Pointer(&sa.raw), SizeofSockaddrL2, nil
}
+// SockaddrRFCOMM implements the Sockaddr interface for AF_BLUETOOTH type sockets
+// using the RFCOMM protocol.
+//
+// Server example:
+//
+// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
+// _ = unix.Bind(fd, &unix.SockaddrRFCOMM{
+// Channel: 1,
+// Addr: [6]uint8{0, 0, 0, 0, 0, 0}, // BDADDR_ANY or 00:00:00:00:00:00
+// })
+// _ = Listen(fd, 1)
+// nfd, sa, _ := Accept(fd)
+// fmt.Printf("conn addr=%v fd=%d", sa.(*unix.SockaddrRFCOMM).Addr, nfd)
+// Read(nfd, buf)
+//
+// Client example:
+//
+// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
+// _ = Connect(fd, &SockaddrRFCOMM{
+// Channel: 1,
+// Addr: [6]byte{0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc}, // CC:BB:AA:33:22:11
+// })
+// Write(fd, []byte(`hello`))
+type SockaddrRFCOMM struct {
+ // Addr represents a bluetooth address, byte ordering is little-endian.
+ Addr [6]uint8
+
+ // Channel is a designated bluetooth channel, only 1-30 are available for use.
+ // Since Linux 2.6.7 and further zero value is the first available channel.
+ Channel uint8
+
+ raw RawSockaddrRFCOMM
+}
+
+func (sa *SockaddrRFCOMM) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ sa.raw.Family = AF_BLUETOOTH
+ sa.raw.Channel = sa.Channel
+ sa.raw.Bdaddr = sa.Addr
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrRFCOMM, nil
+}
+
// SockaddrCAN implements the Sockaddr interface for AF_CAN type sockets.
// The RxID and TxID fields are used for transport protocol addressing in
// (CAN_TP16, CAN_TP20, CAN_MCNET, and CAN_ISOTP), they can be left with
@@ -651,7 +692,7 @@
return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_NETLINK:
pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
@@ -728,6 +769,30 @@
Port: pp.Port,
}
return sa, nil
+ case AF_BLUETOOTH:
+ proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+ if err != nil {
+ return nil, err
+ }
+ // only BTPROTO_L2CAP and BTPROTO_RFCOMM can accept connections
+ switch proto {
+ case BTPROTO_L2CAP:
+ pp := (*RawSockaddrL2)(unsafe.Pointer(rsa))
+ sa := &SockaddrL2{
+ PSM: pp.Psm,
+ CID: pp.Cid,
+ Addr: pp.Bdaddr,
+ AddrType: pp.Bdaddr_type,
+ }
+ return sa, nil
+ case BTPROTO_RFCOMM:
+ pp := (*RawSockaddrRFCOMM)(unsafe.Pointer(rsa))
+ sa := &SockaddrRFCOMM{
+ Channel: pp.Channel,
+ Addr: pp.Bdaddr,
+ }
+ return sa, nil
+ }
}
return nil, EAFNOSUPPORT
}
@@ -739,7 +804,7 @@
if err != nil {
return
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -757,7 +822,7 @@
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -771,7 +836,7 @@
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
}
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
@@ -960,7 +1025,7 @@
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
diff --git a/unix/syscall_solaris.go b/unix/syscall_solaris.go
index 820ef77..a05337d 100644
--- a/unix/syscall_solaris.go
+++ b/unix/syscall_solaris.go
@@ -112,7 +112,7 @@
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
}
// GetsockoptString returns the string value of the socket option opt for the
@@ -360,7 +360,7 @@
return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
@@ -411,7 +411,7 @@
if nfd == -1 {
return
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -448,7 +448,7 @@
oobn = int(msg.Accrightslen)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
diff --git a/unix/syscall_unix.go b/unix/syscall_unix.go
index b835bad..95b2180 100644
--- a/unix/syscall_unix.go
+++ b/unix/syscall_unix.go
@@ -219,7 +219,7 @@
if err = getpeername(fd, &rsa, &len); err != nil {
return
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
}
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
@@ -291,7 +291,7 @@
return
}
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
diff --git a/unix/ztypes_linux_386.go b/unix/ztypes_linux_386.go
index e89bc6b..4c25003 100644
--- a/unix/ztypes_linux_386.go
+++ b/unix/ztypes_linux_386.go
@@ -248,6 +248,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -401,6 +408,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_amd64.go b/unix/ztypes_linux_amd64.go
index d95372b..2e4d709 100644
--- a/unix/ztypes_linux_amd64.go
+++ b/unix/ztypes_linux_amd64.go
@@ -250,6 +250,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -405,6 +412,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_arm.go b/unix/ztypes_linux_arm.go
index 77875ba..bf38e5e 100644
--- a/unix/ztypes_linux_arm.go
+++ b/unix/ztypes_linux_arm.go
@@ -251,6 +251,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -404,6 +411,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_arm64.go b/unix/ztypes_linux_arm64.go
index 5a9df69..972c1b8 100644
--- a/unix/ztypes_linux_arm64.go
+++ b/unix/ztypes_linux_arm64.go
@@ -251,6 +251,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -406,6 +413,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_mips.go b/unix/ztypes_linux_mips.go
index dcb239d..783e70e 100644
--- a/unix/ztypes_linux_mips.go
+++ b/unix/ztypes_linux_mips.go
@@ -249,6 +249,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -402,6 +409,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_mips64.go b/unix/ztypes_linux_mips64.go
index 9cf85f7..5c6ea71 100644
--- a/unix/ztypes_linux_mips64.go
+++ b/unix/ztypes_linux_mips64.go
@@ -251,6 +251,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -406,6 +413,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_mips64le.go b/unix/ztypes_linux_mips64le.go
index 6fd66e7..93effc8 100644
--- a/unix/ztypes_linux_mips64le.go
+++ b/unix/ztypes_linux_mips64le.go
@@ -251,6 +251,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -406,6 +413,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_mipsle.go b/unix/ztypes_linux_mipsle.go
index faa5b3e..cc5ca24 100644
--- a/unix/ztypes_linux_mipsle.go
+++ b/unix/ztypes_linux_mipsle.go
@@ -249,6 +249,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -402,6 +409,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_ppc64.go b/unix/ztypes_linux_ppc64.go
index ad4c452..712f640 100644
--- a/unix/ztypes_linux_ppc64.go
+++ b/unix/ztypes_linux_ppc64.go
@@ -252,6 +252,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -407,6 +414,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_ppc64le.go b/unix/ztypes_linux_ppc64le.go
index 1fdb2f2..1be4532 100644
--- a/unix/ztypes_linux_ppc64le.go
+++ b/unix/ztypes_linux_ppc64le.go
@@ -252,6 +252,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -407,6 +414,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10
diff --git a/unix/ztypes_linux_s390x.go b/unix/ztypes_linux_s390x.go
index d32079d..932b655 100644
--- a/unix/ztypes_linux_s390x.go
+++ b/unix/ztypes_linux_s390x.go
@@ -250,6 +250,13 @@
_ [1]byte
}
+type RawSockaddrRFCOMM struct {
+ Family uint16
+ Bdaddr [6]uint8
+ Channel uint8
+ _ [1]byte
+}
+
type RawSockaddrCAN struct {
Family uint16
_ [2]byte
@@ -405,6 +412,7 @@
SizeofSockaddrNetlink = 0xc
SizeofSockaddrHCI = 0x6
SizeofSockaddrL2 = 0xe
+ SizeofSockaddrRFCOMM = 0xa
SizeofSockaddrCAN = 0x10
SizeofSockaddrALG = 0x58
SizeofSockaddrVM = 0x10