ioctl_linux.go

  1// Copyright 2021 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package unix
  6
  7import "unsafe"
  8
  9// IoctlRetInt performs an ioctl operation specified by req on a device
 10// associated with opened file descriptor fd, and returns a non-negative
 11// integer that is returned by the ioctl syscall.
 12func IoctlRetInt(fd int, req uint) (int, error) {
 13	ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0)
 14	if err != 0 {
 15		return 0, err
 16	}
 17	return int(ret), nil
 18}
 19
 20func IoctlGetUint32(fd int, req uint) (uint32, error) {
 21	var value uint32
 22	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
 23	return value, err
 24}
 25
 26func IoctlGetRTCTime(fd int) (*RTCTime, error) {
 27	var value RTCTime
 28	err := ioctlPtr(fd, RTC_RD_TIME, unsafe.Pointer(&value))
 29	return &value, err
 30}
 31
 32func IoctlSetRTCTime(fd int, value *RTCTime) error {
 33	return ioctlPtr(fd, RTC_SET_TIME, unsafe.Pointer(value))
 34}
 35
 36func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
 37	var value RTCWkAlrm
 38	err := ioctlPtr(fd, RTC_WKALM_RD, unsafe.Pointer(&value))
 39	return &value, err
 40}
 41
 42func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
 43	return ioctlPtr(fd, RTC_WKALM_SET, unsafe.Pointer(value))
 44}
 45
 46// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
 47// device specified by ifname.
 48func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
 49	ifr, err := NewIfreq(ifname)
 50	if err != nil {
 51		return nil, err
 52	}
 53
 54	value := EthtoolDrvinfo{Cmd: ETHTOOL_GDRVINFO}
 55	ifrd := ifr.withData(unsafe.Pointer(&value))
 56
 57	err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
 58	return &value, err
 59}
 60
 61// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC
 62// association for the network device specified by ifname.
 63func IoctlGetEthtoolTsInfo(fd int, ifname string) (*EthtoolTsInfo, error) {
 64	ifr, err := NewIfreq(ifname)
 65	if err != nil {
 66		return nil, err
 67	}
 68
 69	value := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO}
 70	ifrd := ifr.withData(unsafe.Pointer(&value))
 71
 72	err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
 73	return &value, err
 74}
 75
 76// IoctlGetHwTstamp retrieves the hardware timestamping configuration
 77// for the network device specified by ifname.
 78func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) {
 79	ifr, err := NewIfreq(ifname)
 80	if err != nil {
 81		return nil, err
 82	}
 83
 84	value := HwTstampConfig{}
 85	ifrd := ifr.withData(unsafe.Pointer(&value))
 86
 87	err = ioctlIfreqData(fd, SIOCGHWTSTAMP, &ifrd)
 88	return &value, err
 89}
 90
 91// IoctlSetHwTstamp updates the hardware timestamping configuration for
 92// the network device specified by ifname.
 93func IoctlSetHwTstamp(fd int, ifname string, cfg *HwTstampConfig) error {
 94	ifr, err := NewIfreq(ifname)
 95	if err != nil {
 96		return err
 97	}
 98	ifrd := ifr.withData(unsafe.Pointer(cfg))
 99	return ioctlIfreqData(fd, SIOCSHWTSTAMP, &ifrd)
100}
101
102// FdToClockID derives the clock ID from the file descriptor number
103// - see clock_gettime(3), FD_TO_CLOCKID macros. The resulting ID is
104// suitable for system calls like ClockGettime.
105func FdToClockID(fd int) int32 { return int32((int(^fd) << 3) | 3) }
106
107// IoctlPtpClockGetcaps returns the description of a given PTP device.
108func IoctlPtpClockGetcaps(fd int) (*PtpClockCaps, error) {
109	var value PtpClockCaps
110	err := ioctlPtr(fd, PTP_CLOCK_GETCAPS2, unsafe.Pointer(&value))
111	return &value, err
112}
113
114// IoctlPtpSysOffsetPrecise returns a description of the clock
115// offset compared to the system clock.
116func IoctlPtpSysOffsetPrecise(fd int) (*PtpSysOffsetPrecise, error) {
117	var value PtpSysOffsetPrecise
118	err := ioctlPtr(fd, PTP_SYS_OFFSET_PRECISE2, unsafe.Pointer(&value))
119	return &value, err
120}
121
122// IoctlPtpSysOffsetExtended returns an extended description of the
123// clock offset compared to the system clock. The samples parameter
124// specifies the desired number of measurements.
125func IoctlPtpSysOffsetExtended(fd int, samples uint) (*PtpSysOffsetExtended, error) {
126	value := PtpSysOffsetExtended{Samples: uint32(samples)}
127	err := ioctlPtr(fd, PTP_SYS_OFFSET_EXTENDED2, unsafe.Pointer(&value))
128	return &value, err
129}
130
131// IoctlPtpPinGetfunc returns the configuration of the specified
132// I/O pin on given PTP device.
133func IoctlPtpPinGetfunc(fd int, index uint) (*PtpPinDesc, error) {
134	value := PtpPinDesc{Index: uint32(index)}
135	err := ioctlPtr(fd, PTP_PIN_GETFUNC2, unsafe.Pointer(&value))
136	return &value, err
137}
138
139// IoctlPtpPinSetfunc updates configuration of the specified PTP
140// I/O pin.
141func IoctlPtpPinSetfunc(fd int, pd *PtpPinDesc) error {
142	return ioctlPtr(fd, PTP_PIN_SETFUNC2, unsafe.Pointer(pd))
143}
144
145// IoctlPtpPeroutRequest configures the periodic output mode of the
146// PTP I/O pins.
147func IoctlPtpPeroutRequest(fd int, r *PtpPeroutRequest) error {
148	return ioctlPtr(fd, PTP_PEROUT_REQUEST2, unsafe.Pointer(r))
149}
150
151// IoctlPtpExttsRequest configures the external timestamping mode
152// of the PTP I/O pins.
153func IoctlPtpExttsRequest(fd int, r *PtpExttsRequest) error {
154	return ioctlPtr(fd, PTP_EXTTS_REQUEST2, unsafe.Pointer(r))
155}
156
157// IoctlGetWatchdogInfo fetches information about a watchdog device from the
158// Linux watchdog API. For more information, see:
159// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
160func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) {
161	var value WatchdogInfo
162	err := ioctlPtr(fd, WDIOC_GETSUPPORT, unsafe.Pointer(&value))
163	return &value, err
164}
165
166// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For
167// more information, see:
168// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
169func IoctlWatchdogKeepalive(fd int) error {
170	// arg is ignored and not a pointer, so ioctl is fine instead of ioctlPtr.
171	return ioctl(fd, WDIOC_KEEPALIVE, 0)
172}
173
174// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the
175// range of data conveyed in value to the file associated with the file
176// descriptor destFd. See the ioctl_ficlonerange(2) man page for details.
177func IoctlFileCloneRange(destFd int, value *FileCloneRange) error {
178	return ioctlPtr(destFd, FICLONERANGE, unsafe.Pointer(value))
179}
180
181// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file
182// associated with the file description srcFd to the file associated with the
183// file descriptor destFd. See the ioctl_ficlone(2) man page for details.
184func IoctlFileClone(destFd, srcFd int) error {
185	return ioctl(destFd, FICLONE, uintptr(srcFd))
186}
187
188type FileDedupeRange struct {
189	Src_offset uint64
190	Src_length uint64
191	Reserved1  uint16
192	Reserved2  uint32
193	Info       []FileDedupeRangeInfo
194}
195
196type FileDedupeRangeInfo struct {
197	Dest_fd       int64
198	Dest_offset   uint64
199	Bytes_deduped uint64
200	Status        int32
201	Reserved      uint32
202}
203
204// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the
205// range of data conveyed in value from the file associated with the file
206// descriptor srcFd to the value.Info destinations. See the
207// ioctl_fideduperange(2) man page for details.
208func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error {
209	buf := make([]byte, SizeofRawFileDedupeRange+
210		len(value.Info)*SizeofRawFileDedupeRangeInfo)
211	rawrange := (*RawFileDedupeRange)(unsafe.Pointer(&buf[0]))
212	rawrange.Src_offset = value.Src_offset
213	rawrange.Src_length = value.Src_length
214	rawrange.Dest_count = uint16(len(value.Info))
215	rawrange.Reserved1 = value.Reserved1
216	rawrange.Reserved2 = value.Reserved2
217
218	for i := range value.Info {
219		rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
220			uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
221				uintptr(i*SizeofRawFileDedupeRangeInfo)))
222		rawinfo.Dest_fd = value.Info[i].Dest_fd
223		rawinfo.Dest_offset = value.Info[i].Dest_offset
224		rawinfo.Bytes_deduped = value.Info[i].Bytes_deduped
225		rawinfo.Status = value.Info[i].Status
226		rawinfo.Reserved = value.Info[i].Reserved
227	}
228
229	err := ioctlPtr(srcFd, FIDEDUPERANGE, unsafe.Pointer(&buf[0]))
230
231	// Output
232	for i := range value.Info {
233		rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
234			uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
235				uintptr(i*SizeofRawFileDedupeRangeInfo)))
236		value.Info[i].Dest_fd = rawinfo.Dest_fd
237		value.Info[i].Dest_offset = rawinfo.Dest_offset
238		value.Info[i].Bytes_deduped = rawinfo.Bytes_deduped
239		value.Info[i].Status = rawinfo.Status
240		value.Info[i].Reserved = rawinfo.Reserved
241	}
242
243	return err
244}
245
246func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error {
247	return ioctlPtr(fd, HIDIOCGRDESC, unsafe.Pointer(value))
248}
249
250func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) {
251	var value HIDRawDevInfo
252	err := ioctlPtr(fd, HIDIOCGRAWINFO, unsafe.Pointer(&value))
253	return &value, err
254}
255
256func IoctlHIDGetRawName(fd int) (string, error) {
257	var value [_HIDIOCGRAWNAME_LEN]byte
258	err := ioctlPtr(fd, _HIDIOCGRAWNAME, unsafe.Pointer(&value[0]))
259	return ByteSliceToString(value[:]), err
260}
261
262func IoctlHIDGetRawPhys(fd int) (string, error) {
263	var value [_HIDIOCGRAWPHYS_LEN]byte
264	err := ioctlPtr(fd, _HIDIOCGRAWPHYS, unsafe.Pointer(&value[0]))
265	return ByteSliceToString(value[:]), err
266}
267
268func IoctlHIDGetRawUniq(fd int) (string, error) {
269	var value [_HIDIOCGRAWUNIQ_LEN]byte
270	err := ioctlPtr(fd, _HIDIOCGRAWUNIQ, unsafe.Pointer(&value[0]))
271	return ByteSliceToString(value[:]), err
272}
273
274// IoctlIfreq performs an ioctl using an Ifreq structure for input and/or
275// output. See the netdevice(7) man page for details.
276func IoctlIfreq(fd int, req uint, value *Ifreq) error {
277	// It is possible we will add more fields to *Ifreq itself later to prevent
278	// misuse, so pass the raw *ifreq directly.
279	return ioctlPtr(fd, req, unsafe.Pointer(&value.raw))
280}
281
282// TODO(mdlayher): export if and when IfreqData is exported.
283
284// ioctlIfreqData performs an ioctl using an ifreqData structure for input
285// and/or output. See the netdevice(7) man page for details.
286func ioctlIfreqData(fd int, req uint, value *ifreqData) error {
287	// The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are
288	// identical so pass *IfreqData directly.
289	return ioctlPtr(fd, req, unsafe.Pointer(value))
290}
291
292// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an
293// existing KCM socket, returning a structure containing the file descriptor of
294// the new socket.
295func IoctlKCMClone(fd int) (*KCMClone, error) {
296	var info KCMClone
297	if err := ioctlPtr(fd, SIOCKCMCLONE, unsafe.Pointer(&info)); err != nil {
298		return nil, err
299	}
300
301	return &info, nil
302}
303
304// IoctlKCMAttach attaches a TCP socket and associated BPF program file
305// descriptor to a multiplexor.
306func IoctlKCMAttach(fd int, info KCMAttach) error {
307	return ioctlPtr(fd, SIOCKCMATTACH, unsafe.Pointer(&info))
308}
309
310// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor.
311func IoctlKCMUnattach(fd int, info KCMUnattach) error {
312	return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
313}
314
315// IoctlLoopGetStatus64 gets the status of the loop device associated with the
316// file descriptor fd using the LOOP_GET_STATUS64 operation.
317func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
318	var value LoopInfo64
319	if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
320		return nil, err
321	}
322	return &value, nil
323}
324
325// IoctlLoopSetStatus64 sets the status of the loop device associated with the
326// file descriptor fd using the LOOP_SET_STATUS64 operation.
327func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
328	return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
329}
330
331// IoctlLoopConfigure configures all loop device parameters in a single step
332func IoctlLoopConfigure(fd int, value *LoopConfig) error {
333	return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value))
334}