| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- //go:build linux
- /* SPDX-License-Identifier: MIT
- *
- * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
- */
- package conn
- import (
- "fmt"
- "unsafe"
- "golang.org/x/sys/unix"
- )
- const (
- sizeOfGSOData = 2
- )
- // getGSOSize parses control for UDP_GRO and if found returns its GSO size data.
- func getGSOSize(control []byte) (int, error) {
- var (
- hdr unix.Cmsghdr
- data []byte
- rem = control
- err error
- )
- for len(rem) > unix.SizeofCmsghdr {
- hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem)
- if err != nil {
- return 0, fmt.Errorf("error parsing socket control message: %w", err)
- }
- if hdr.Level == unix.SOL_UDP && hdr.Type == unix.UDP_GRO && len(data) >= sizeOfGSOData {
- var gso uint16
- copy(unsafe.Slice((*byte)(unsafe.Pointer(&gso)), sizeOfGSOData), data[:sizeOfGSOData])
- return int(gso), nil
- }
- }
- return 0, nil
- }
- // setGSOSize sets a UDP_SEGMENT in control based on gsoSize. It leaves existing
- // data in control untouched.
- func setGSOSize(control *[]byte, gsoSize uint16) {
- existingLen := len(*control)
- avail := cap(*control) - existingLen
- space := unix.CmsgSpace(sizeOfGSOData)
- if avail < space {
- return
- }
- *control = (*control)[:cap(*control)]
- gsoControl := (*control)[existingLen:]
- hdr := (*unix.Cmsghdr)(unsafe.Pointer(&(gsoControl)[0]))
- hdr.Level = unix.SOL_UDP
- hdr.Type = unix.UDP_SEGMENT
- hdr.SetLen(unix.CmsgLen(sizeOfGSOData))
- copy((gsoControl)[unix.CmsgLen(0):], unsafe.Slice((*byte)(unsafe.Pointer(&gsoSize)), sizeOfGSOData))
- *control = (*control)[:existingLen+space]
- }
- // gsoControlSize returns the recommended buffer size for pooling UDP
- // offloading control data.
- var gsoControlSize = unix.CmsgSpace(sizeOfGSOData)
|