+static void disable_device(void) {
+ logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info);
+
+ io_del(&device_read_io);
+
+ ULONG status = 0;
+ DWORD len;
+ DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
+
+ /* Note that we don't try to cancel ongoing I/O here - we just stop listening.
+ This is because some TAP-Win32 drivers don't seem to handle cancellation very well,
+ especially when combined with other events such as the computer going to sleep - cases
+ were observed where the GetOverlappedResult() would just block indefinitely and never
+ return in that case. */
+}
+
+static void close_device(void) {
+ CancelIo(device_handle);
+
+ /* According to MSDN, CancelIo() does not necessarily wait for the operation to complete.
+ To prevent race conditions, make sure the operation is complete
+ before we close the event it's referencing. */
+
+ DWORD len;
+
+ if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError()));
+ }
+
+ if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError()));
+ }
+
+ device_write_packet.len = 0;
+
+ CloseHandle(device_read_overlapped.hEvent);
+ CloseHandle(device_write_overlapped.hEvent);
+