github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/tun/wintun/session_windows.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package wintun 7 8 import ( 9 "syscall" 10 "unsafe" 11 12 "golang.org/x/sys/windows" 13 ) 14 15 type Session struct { 16 handle uintptr 17 } 18 19 const ( 20 PacketSizeMax = 0xffff // Maximum packet size 21 RingCapacityMin = 0x20000 // Minimum ring capacity (128 kiB) 22 RingCapacityMax = 0x4000000 // Maximum ring capacity (64 MiB) 23 ) 24 25 // Packet with data 26 type Packet struct { 27 Next *Packet // Pointer to next packet in queue 28 Size uint32 // Size of packet (max WINTUN_MAX_IP_PACKET_SIZE) 29 Data *[PacketSizeMax]byte // Pointer to layer 3 IPv4 or IPv6 packet 30 } 31 32 var ( 33 procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket") 34 procWintunEndSession = modwintun.NewProc("WintunEndSession") 35 procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent") 36 procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket") 37 procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket") 38 procWintunSendPacket = modwintun.NewProc("WintunSendPacket") 39 procWintunStartSession = modwintun.NewProc("WintunStartSession") 40 ) 41 42 func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error) { 43 r0, _, e1 := syscall.Syscall(procWintunStartSession.Addr(), 2, uintptr(wintun.handle), uintptr(capacity), 0) 44 if r0 == 0 { 45 err = e1 46 } else { 47 session = Session{r0} 48 } 49 return 50 } 51 52 func (session Session) End() { 53 syscall.Syscall(procWintunEndSession.Addr(), 1, session.handle, 0, 0) 54 session.handle = 0 55 } 56 57 func (session Session) ReadWaitEvent() (handle windows.Handle) { 58 r0, _, _ := syscall.Syscall(procWintunGetReadWaitEvent.Addr(), 1, session.handle, 0, 0) 59 handle = windows.Handle(r0) 60 return 61 } 62 63 func (session Session) ReceivePacket() (packet []byte, err error) { 64 var packetSize uint32 65 r0, _, e1 := syscall.Syscall(procWintunReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packetSize)), 0) 66 if r0 == 0 { 67 err = e1 68 return 69 } 70 unsafeSlice(unsafe.Pointer(&packet), unsafe.Pointer(r0), int(packetSize)) 71 return 72 } 73 74 func (session Session) ReleaseReceivePacket(packet []byte) { 75 syscall.Syscall(procWintunReleaseReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) 76 } 77 78 func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) { 79 r0, _, e1 := syscall.Syscall(procWintunAllocateSendPacket.Addr(), 2, session.handle, uintptr(packetSize), 0) 80 if r0 == 0 { 81 err = e1 82 return 83 } 84 unsafeSlice(unsafe.Pointer(&packet), unsafe.Pointer(r0), int(packetSize)) 85 return 86 } 87 88 func (session Session) SendPacket(packet []byte) { 89 syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0) 90 } 91 92 // unsafeSlice updates the slice slicePtr to be a slice 93 // referencing the provided data with its length & capacity set to 94 // lenCap. 95 // 96 // TODO: when Go 1.16 or Go 1.17 is the minimum supported version, 97 // update callers to use unsafe.Slice instead of this. 98 func unsafeSlice(slicePtr, data unsafe.Pointer, lenCap int) { 99 type sliceHeader struct { 100 Data unsafe.Pointer 101 Len int 102 Cap int 103 } 104 h := (*sliceHeader)(slicePtr) 105 h.Data = data 106 h.Len = lenCap 107 h.Cap = lenCap 108 }