1 /* libusb-win32, Generic Windows USB Library
2 * Copyright (c) 2010 Travis Robinson <libusbdotnet@gmail.com>
3 * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 
21 #include "libusb_driver.h"
22 #include "libusb-win32_version.h"
23 
24 // used but all transfer functions to get a valid libusb_endpoint_t *
25 // for the request.
26 //
27 #define TRANSFER_IOCTL_GET_PIPEINFO()										\
28 	/* check if the pipe exists and get the pipe information */				\
29 	if (!get_pipe_info(dev, request->endpoint.endpoint,&pipe_info))			\
30 	{																		\
31 	USBERR("%s: failed getting pipe info for endpoint: %02Xh\n",		\
32 	dispCtlCode, request->endpoint.endpoint);						\
33 	status = STATUS_INVALID_PARAMETER;									\
34 	goto IOCTL_Done;													\
35 	}
36 
37 // warns if receive buffer is not an interval of the maximum packet size.
38 #define TRANSFER_IOCTL_CHECK_READ_BUFFER()									\
39 	/* read buffer lengthd must be equal to or an interval of the max */	\
40 	/* packet size */														\
41 	if (!pipe_info->maximum_packet_size)									\
42 	{																		\
43 	USBWRN("%s: wMaxPacketSize=0 for endpoint %02Xh.\n",				\
44 	dispCtlCode, request->endpoint.endpoint);							\
45 	status = STATUS_INVALID_PARAMETER;									\
46 	goto IOCTL_Done;													\
47 	}																		\
48 	else if (transfer_buffer_length % pipe_info->maximum_packet_size)		\
49 	{																		\
50 	USBWRN("%s: buffer length %d is not an interval wMaxPacketSize "	\
51 	"for endpoint %02Xh.\n",										\
52 	dispCtlCode, transfer_buffer_length, request->endpoint.endpoint);	\
53 	}
54 
55 // validates the urb function and direction against libusb_endpoint_t
56 #define TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION()						\
57 	if (urbFunction   != UrbFunctionFromEndpoint(pipe_info) ||				\
58 	usbdDirection != UsbdDirectionFromEndpoint(pipe_info))				\
59 	{																		\
60 	USBERR("%s: not compatible with endpoint %02Xh.\n"					\
61 	"\turbFunction  =%Xh usbdDirection  =%Xh\n"						\
62 	"\tpipeFunction =%Xh pipeDirection  =%Xh\n",					\
63 	dispCtlCode,													\
64 	pipe_info->address,												\
65 	urbFunction,usbdDirection,										\
66 	UrbFunctionFromEndpoint(pipe_info),								\
67 	UsbdDirectionFromEndpoint(pipe_info));							\
68 	status = STATUS_INVALID_PARAMETER;									\
69 	goto IOCTL_Done;													\
70 	}
71 
72 // calls the transfer function and returns NTSTATUS
73 #define TRANSFER_IOCTL_EXECUTE()										\
74 	if (transfer_buffer_length > (ULONG)(maxTransferSize))				\
75 	/* split large transfers */											\
76 	return large_transfer(dev, irp,					\
77 	usbdDirection,									\
78 	urbFunction,									\
79 	pipe_info,										\
80 	request->endpoint.packet_size,					\
81 	maxTransferSize,								\
82 	request->endpoint.transfer_flags,				\
83 	request->endpoint.iso_start_frame_latency,		\
84 	transfer_buffer_mdl,							\
85 	transfer_buffer_length);						\
86 	else											\
87 	/* normal transfer */							\
88 	return transfer(dev, irp,						\
89 	usbdDirection,									\
90 	urbFunction,									\
91 	pipe_info,										\
92 	request->endpoint.packet_size,					\
93 	request->endpoint.transfer_flags,				\
94 	request->endpoint.iso_start_frame_latency,		\
95 	transfer_buffer_mdl,							\
96 	transfer_buffer_length);
97 
dispatch_ioctl(libusb_device_t * dev,IRP * irp)98 NTSTATUS dispatch_ioctl(libusb_device_t *dev, IRP *irp)
99 {
100 	int maxTransferSize;
101 	int ret = 0;
102 	NTSTATUS status = STATUS_SUCCESS;
103 
104 	IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
105 
106 	ULONG control_code			 = stack_location->Parameters.DeviceIoControl.IoControlCode;
107 
108 	ULONG input_buffer_length	 = stack_location->Parameters.DeviceIoControl.InputBufferLength;
109 	ULONG output_buffer_length	 = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
110 	ULONG transfer_buffer_length = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
111 
112 	libusb_request *request		 = (libusb_request *)irp->AssociatedIrp.SystemBuffer;
113 	char *output_buffer			 = (char *)irp->AssociatedIrp.SystemBuffer;
114 	char *input_buffer			 = (char *)irp->AssociatedIrp.SystemBuffer;
115 	MDL *transfer_buffer_mdl	 = irp->MdlAddress;
116 	libusb_endpoint_t* pipe_info = NULL;
117 	const char* dispCtlCode		 = NULL;
118 	int urbFunction				 = -1;
119 	int usbdDirection			 = -1;
120 
121 	status = remove_lock_acquire(dev);
122 
123 	if (!NT_SUCCESS(status))
124 	{
125 		status = complete_irp(irp, status, 0);
126 		remove_lock_release(dev);
127 		return status;
128 	}
129 
130 	///////////////////////////////////
131 	// DIRECT control codes          //
132 	///////////////////////////////////
133 	switch(control_code)
134 	{
135 	case LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ:
136 
137 		dispCtlCode = "INTERRUPT_OR_BULK_READ";
138 
139 		// check if the request and buffer is valid
140 		if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
141 		{
142 			USBERR("%s: invalid transfer request\n",
143 				dispCtlCode);
144 			status = STATUS_INVALID_PARAMETER;
145 			goto IOCTL_Done;
146 		}
147 
148 		// check if the pipe exists and get the pipe information
149 		TRANSFER_IOCTL_GET_PIPEINFO();
150 
151 		// must be a bulk or interrupt pipe
152 		if (!IS_BULK_PIPE(pipe_info) && !IS_INTR_PIPE(pipe_info))
153 		{
154 			goto IoctlIsochronousRead;
155 			/*
156 			USBERR("%s: incorrect pipe type: %02Xh\n",
157 				dispCtlCode, pipe_info->pipe_type);
158 			status = STATUS_INVALID_PARAMETER;
159 			goto IOCTL_Done;
160 			*/
161 		}
162 
163 		// read buffer length must be equal to or an interval of the max packet size
164 		TRANSFER_IOCTL_CHECK_READ_BUFFER();
165 
166 		urbFunction = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
167 		usbdDirection = USBD_TRANSFER_DIRECTION_IN;
168 		maxTransferSize = GetMaxTransferSize(pipe_info, request->endpoint.max_transfer_size);
169 
170 		// ensure that the urb function and direction we set matches the
171 		// pipe information
172 		//
173 		TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
174 
175 		// calls the transfer function and returns NTSTATUS
176 		TRANSFER_IOCTL_EXECUTE();
177 
178 	case LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE:
179 
180 		dispCtlCode = "INTERRUPT_OR_BULK_WRITE";
181 
182 		/* we don't check 'transfer_buffer_mdl' here because it might be NULL */
183 		/* if the DLL requests to send a zero-length packet */
184 		if (!request || input_buffer_length < sizeof(libusb_request))
185 		{
186 			USBERR("%s: invalid transfer request\n", dispCtlCode);
187 			status = STATUS_INVALID_PARAMETER;
188 			goto IOCTL_Done;
189 		}
190 
191 		// check if the pipe exists and get the pipe information
192 		TRANSFER_IOCTL_GET_PIPEINFO();
193 
194 		// must be a bulk or interrupt pipe
195 		if (!IS_BULK_PIPE(pipe_info) && !IS_INTR_PIPE(pipe_info))
196 		{
197 			goto IoctlIsochronousWrite;
198 			/*
199 			USBERR("%s: incorrect pipe type: %02Xh\n",
200 				dispCtlCode, pipe_info->pipe_type);
201 			status = STATUS_INVALID_PARAMETER;
202 			goto IOCTL_Done;
203 			*/
204 		}
205 
206 		urbFunction = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
207 		usbdDirection = USBD_TRANSFER_DIRECTION_OUT;
208 		maxTransferSize = GetMaxTransferSize(pipe_info, request->endpoint.max_transfer_size);
209 
210 		// ensure that the urb function and direction we set matches the
211 		// pipe information
212 		//
213 		//TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
214 
215 		// calls the transfer function and returns NTSTATUS
216 		TRANSFER_IOCTL_EXECUTE();
217 
218 	case LIBUSB_IOCTL_ISOCHRONOUS_READ:
219 
220 		dispCtlCode = "ISOCHRONOUS_READ";
221 
222 		// check if the request and buffer is valid
223 		if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
224 		{
225 			USBERR("%s: invalid transfer request\n", dispCtlCode);
226 			status = STATUS_INVALID_PARAMETER;
227 			goto IOCTL_Done;
228 		}
229 
230 		// check if the pipe exists and get the pipe information
231 		TRANSFER_IOCTL_GET_PIPEINFO();
232 
233 IoctlIsochronousRead:
234 		dispCtlCode = "ISOCHRONOUS_READ";
235 		// must be an isochronous endpoint
236 		if (!IS_ISOC_PIPE(pipe_info))
237 		{
238 			USBERR("%s: incorrect pipe type: %02Xh\n",
239 				dispCtlCode, pipe_info->pipe_type);
240 			status = STATUS_INVALID_PARAMETER;
241 			goto IOCTL_Done;
242 		}
243 
244 		// read buffer length must be equal to or an interval of the max packet size
245 		TRANSFER_IOCTL_CHECK_READ_BUFFER();
246 
247 		urbFunction = URB_FUNCTION_ISOCH_TRANSFER;
248 		usbdDirection = USBD_TRANSFER_DIRECTION_IN;
249 
250 		// Do not use large transfers/splitting for ISO.
251 		maxTransferSize = 0x7fffffff;
252 
253 		// ensure that the urb function and direction we set matches the
254 		// pipe information
255 		//
256 		TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
257 
258 		// calls the transfer function and returns NTSTATUS
259 		TRANSFER_IOCTL_EXECUTE();
260 
261 	case LIBUSB_IOCTL_ISOCHRONOUS_WRITE:
262 
263 		dispCtlCode = "ISOCHRONOUS_WRITE";
264 
265 		// check if the request and buffer is valid
266 		if (!transfer_buffer_mdl || !request || input_buffer_length < sizeof(libusb_request))
267 		{
268 			USBERR("%s: invalid transfer request\n", dispCtlCode);
269 			status = STATUS_INVALID_PARAMETER;
270 			goto IOCTL_Done;
271 		}
272 
273 		// check if the pipe exists and get the pipe information
274 		TRANSFER_IOCTL_GET_PIPEINFO();
275 
276 IoctlIsochronousWrite:
277 		dispCtlCode = "ISOCHRONOUS_WRITE";
278 		// must be an isochronous endpoint
279 		if (!IS_ISOC_PIPE(pipe_info))
280 		{
281 			USBERR("%s: incorrect pipe type: %02Xh\n",
282 				dispCtlCode, pipe_info->pipe_type);
283 			status = STATUS_INVALID_PARAMETER;
284 			goto IOCTL_Done;
285 		}
286 
287 		urbFunction = URB_FUNCTION_ISOCH_TRANSFER;
288 		usbdDirection = USBD_TRANSFER_DIRECTION_OUT;
289 		TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
290 
291 		// Do not use large transfers/splitting for ISO.
292 		maxTransferSize = 0x7fffffff;
293 
294 		// ensure that the urb function and direction we set matches the
295 		// pipe information
296 		//
297 		TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
298 
299 		TRANSFER_IOCTL_EXECUTE();
300 	}
301 
302 	///////////////////////////////////
303 	// METHOD_BUFFERED control codes //
304 	///////////////////////////////////
305 	if (!request || input_buffer_length < sizeof(libusb_request)
306 		|| input_buffer_length > LIBUSB_MAX_READ_WRITE
307 		|| output_buffer_length > LIBUSB_MAX_READ_WRITE
308 		|| transfer_buffer_length > LIBUSB_MAX_READ_WRITE)
309 	{
310 		USBERR0("invalid input or output buffer\n");
311 
312 		status = complete_irp(irp, STATUS_INVALID_PARAMETER, 0);
313 		remove_lock_release(dev);
314 		return status;
315 	}
316 
317 	switch(control_code)
318 	{
319 	case LIBUSB_IOCTL_SET_CONFIGURATION:
320 
321 		status = set_configuration(dev,
322 			request->configuration.configuration,
323 			request->timeout);
324 		break;
325 
326 	case LIBUSB_IOCTL_GET_CACHED_CONFIGURATION:
327 	case LIBUSB_IOCTL_GET_CONFIGURATION:
328 
329 		if (!output_buffer || output_buffer_length < 1)
330 		{
331 			USBERR0("get_configuration: invalid output buffer\n");
332 			status = STATUS_INVALID_PARAMETER;
333 			break;
334 		}
335 		if (control_code == LIBUSB_IOCTL_GET_CACHED_CONFIGURATION)
336 		{
337 			ret = 0;
338 			if (dev->config.value >= 0)
339 			{
340 				*output_buffer = (char)dev->config.value;
341 				ret = 1;
342 			}
343 			status = STATUS_SUCCESS;
344 		}
345 		else
346 		{
347 			status = get_configuration(dev, output_buffer, &ret, request->timeout);
348 		}
349 		break;
350 
351 	case LIBUSB_IOCTL_SET_INTERFACE:
352 
353 		status = set_interface(
354 			dev,
355 			request->intf.interface_number,
356 			request->intf.altsetting_number,
357 			request->timeout);
358 
359 		break;
360 
361 	case LIBUSB_IOCTL_GET_INTERFACE:
362 
363 		if (!output_buffer || output_buffer_length < 1)
364 		{
365 			USBERR0("get_interface: invalid output buffer\n");
366 			status =  STATUS_INVALID_PARAMETER;
367 			break;
368 		}
369 
370 		status = get_interface(
371 			dev,
372 			request->intf.interface_number,
373 			output_buffer,
374 			request->timeout);
375 
376 		if (NT_SUCCESS(status))
377 			ret = 1;
378 
379 		break;
380 
381 	case LIBUSB_IOCTL_SET_FEATURE:
382 
383 		status = set_feature(dev, request->feature.recipient,
384 			request->feature.index, request->feature.feature,
385 			request->timeout);
386 
387 		break;
388 
389 	case LIBUSB_IOCTL_CLEAR_FEATURE:
390 
391 		status = clear_feature(dev, request->feature.recipient,
392 			request->feature.index, request->feature.feature,
393 			request->timeout);
394 
395 		break;
396 
397 	case LIBUSB_IOCTL_GET_STATUS:
398 
399 		if (!output_buffer || output_buffer_length < 2)
400 		{
401 			USBERR0("get_status: invalid output buffer\n");
402 			status = STATUS_INVALID_PARAMETER;
403 			break;
404 		}
405 
406 		status = get_status(dev, request->status.recipient,
407 			request->status.index, output_buffer,
408 			&ret, request->timeout);
409 
410 		break;
411 
412 	case LIBUSB_IOCTL_SET_DESCRIPTOR:
413 
414 		if (input_buffer_length <= sizeof(libusb_request))
415 		{
416 			USBERR0("set_descriptor: invalid input buffer\n");
417 			status = STATUS_INVALID_PARAMETER;
418 			break;
419 		}
420 
421 		status = set_descriptor(dev,
422 			input_buffer + sizeof(libusb_request),
423 			input_buffer_length - sizeof(libusb_request),
424 			request->descriptor.type,
425 			request->descriptor.recipient,
426 			request->descriptor.index,
427 			request->descriptor.language_id,
428 			&ret, request->timeout);
429 
430 		break;
431 
432 	case LIBUSB_IOCTL_GET_DESCRIPTOR:
433 
434 		if (!output_buffer || !output_buffer_length)
435 		{
436 			USBERR0("get_descriptor: invalid output buffer\n");
437 			status = STATUS_INVALID_PARAMETER;
438 			break;
439 		}
440 
441 		status = get_descriptor(dev, output_buffer,
442 			output_buffer_length,
443 			request->descriptor.type,
444 			request->descriptor.recipient,
445 			request->descriptor.index,
446 			request->descriptor.language_id,
447 			&ret, request->timeout);
448 
449 		break;
450 
451 	case LIBUSB_IOCTL_VENDOR_READ:
452 
453 		if (output_buffer_length && !output_buffer)
454 		{
455 			USBERR0("vendor_read: invalid output buffer\n");
456 			status = STATUS_INVALID_PARAMETER;
457 			break;
458 		}
459 
460 		status = vendor_class_request(dev,
461 			request->vendor.type,
462 			request->vendor.recipient,
463 			request->vendor.request,
464 			request->vendor.value,
465 			request->vendor.index,
466 			output_buffer,
467 			output_buffer_length,
468 			USBD_TRANSFER_DIRECTION_IN,
469 			&ret, request->timeout);
470 		break;
471 
472 	case LIBUSB_IOCTL_VENDOR_WRITE:
473 
474 		status =
475 			vendor_class_request(dev,
476 			request->vendor.type,
477 			request->vendor.recipient,
478 			request->vendor.request,
479 			request->vendor.value,
480 			request->vendor.index,
481 			input_buffer_length == sizeof(libusb_request) ?
482 NULL : input_buffer + sizeof(libusb_request),
483 	   input_buffer_length - sizeof(libusb_request),
484 	   USBD_TRANSFER_DIRECTION_OUT,
485 	   &ret, request->timeout);
486 		break;
487 
488 	case LIBUSB_IOCTL_RESET_ENDPOINT:
489 
490 		status = reset_endpoint(dev, request->endpoint.endpoint,
491 			request->timeout);
492 		break;
493 
494 	case LIBUSB_IOCTL_ABORT_ENDPOINT:
495 
496 		status = abort_endpoint(dev, request->endpoint.endpoint,
497 			request->timeout);
498 		break;
499 
500 	case LIBUSB_IOCTL_RESET_DEVICE:
501 
502 		status = reset_device(dev, request->timeout);
503 		break;
504 
505 	case LIBUSB_IOCTL_RESET_DEVICE_EX:
506 
507 		status = reset_device_ex(dev, request->timeout, request->reset_ex.reset_type);
508 		break;
509 
510 	case LIBUSB_IOCTL_SET_DEBUG_LEVEL:
511 		usb_log_set_level(request->debug.level);
512 		break;
513 
514 	case LIBUSB_IOCTL_GET_VERSION:
515 
516 		if (!request || output_buffer_length < sizeof(libusb_request))
517 		{
518 			USBERR0("get_version: invalid output buffer\n");
519 			status = STATUS_INVALID_PARAMETER;
520 			break;
521 		}
522 
523 		request->version.major = VERSION_MAJOR;
524 		request->version.minor = VERSION_MINOR;
525 		request->version.micro = VERSION_MICRO;
526 		request->version.nano  = VERSION_NANO;
527 		request->version.mod_value = 1;
528 
529 		ret = sizeof(libusb_request);
530 		break;
531 
532 	case LIBUSB_IOCTL_CLAIM_INTERFACE:
533 		status = claim_interface(dev, stack_location->FileObject,
534 			request->intf.interface_number);
535 		break;
536 
537 	case LIBUSB_IOCTL_RELEASE_INTERFACE:
538 		status = release_interface(dev, stack_location->FileObject,
539 			request->intf.interface_number);
540 		break;
541 
542 	case LIBUSB_IOCTL_GET_DEVICE_PROPERTY:
543 		if (!request || output_buffer_length < sizeof(libusb_request))
544 		{
545 			USBERR0("get_device_property: invalid output buffer\n");
546 			status = STATUS_INVALID_PARAMETER;
547 			break;
548 		}
549 		status = reg_get_device_property(
550 			dev->physical_device_object,
551 			request->device_property.property,
552 			output_buffer,
553 			output_buffer_length, &ret);
554 		break;
555 
556 	case LIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY:
557 		if (!input_buffer || (input_buffer_length < sizeof(libusb_request)))
558 		{
559 			USBERR0("get_custom_reg_property: invalid buffer\n");
560 			status = STATUS_INVALID_PARAMETER;
561 			break;
562 		}
563 		status=reg_get_custom_property(
564 			dev->physical_device_object,
565 			input_buffer,
566 			output_buffer_length,
567 			request->device_registry_key.name_offset,
568 			&ret);
569 		break;
570 
571 	case LIBUSB_IOCTL_GET_OBJECT_NAME:
572 		if (!request || output_buffer_length < 2)
573 		{
574 			USBERR0("get_object_name: invalid output buffer\n");
575 			status = STATUS_INVALID_PARAMETER;
576 			break;
577 		}
578 		switch (request->objname.objname_index)
579 		{
580 		case 0:
581 			ret = (int)strlen(dev->objname_plugplay_registry_key)+1;
582 			ret = ret > (int)output_buffer_length ? (int)output_buffer_length : ret;
583 			RtlCopyMemory(output_buffer, dev->objname_plugplay_registry_key,(SIZE_T) (ret-1));
584 			output_buffer[ret-1]='\0';
585 			break;
586 		default:
587 			status = STATUS_INVALID_PARAMETER;
588 		}
589 		break;
590 
591 	case LIBUSB_IOCTL_QUERY_DEVICE_INFORMATION:	// METHOD_BUFFERED (QUERY_DEVICE_INFORMATION)
592 		status = STATUS_NOT_IMPLEMENTED;
593 		break;
594 
595 	case LIBUSB_IOCTL_SET_PIPE_POLICY:			// METHOD_BUFFERED (SET_PIPE_POLICY)
596 		if (!request || !input_buffer || (input_buffer_length <= sizeof(libusb_request)))
597 		{
598 			USBERR0("set_pipe_policy: invalid output buffer\n");
599 			status = STATUS_BUFFER_TOO_SMALL;
600 			break;
601 		}
602 		input_buffer+=sizeof(libusb_request);
603 		input_buffer_length-=sizeof(libusb_request);
604 		if (request->pipe_policy.policy_type==PIPE_TRANSFER_TIMEOUT)
605 		{
606 			if (input_buffer_length < sizeof(ULONG))
607 			{
608 				USBERR0("set_pipe_policy:pipe_transfer_timeout: invalid input buffer\n");
609 				status = STATUS_BUFFER_TOO_SMALL;
610 				break;
611 			}
612 			if (request->pipe_policy.pipe_id & USB_ENDPOINT_ADDRESS_MASK)
613 			{
614 				status = STATUS_NOT_IMPLEMENTED;
615 				break;
616 			}
617 
618 			if (request->pipe_policy.pipe_id & USB_ENDPOINT_DIR_MASK)
619 				dev->control_read_timeout=*((PULONG)input_buffer);
620 			else
621 				dev->control_write_timeout=*((PULONG)input_buffer);
622 
623 			status = STATUS_SUCCESS;
624 			break;
625 		}
626 
627 		break;
628 
629 	case LIBUSB_IOCTL_GET_PIPE_POLICY:			// METHOD_BUFFERED (GET_PIPE_POLICY)
630 		if (!request || input_buffer_length < sizeof(libusb_request) || !output_buffer || (output_buffer_length < 1))
631 		{
632 			USBERR0("get_pipe_policy: invalid output buffer\n");
633 			status = STATUS_BUFFER_TOO_SMALL;
634 			break;
635 		}
636 		if (request->pipe_policy.policy_type==PIPE_TRANSFER_TIMEOUT)
637 		{
638 			if (output_buffer_length < sizeof(ULONG))
639 			{
640 				USBERR0("get_pipe_policy:pipe_transfer_timeout: invalid output buffer\n");
641 				status = STATUS_BUFFER_TOO_SMALL;
642 				break;
643 			}
644 			if (request->pipe_policy.pipe_id & USB_ENDPOINT_ADDRESS_MASK)
645 			{
646 				status = STATUS_NOT_IMPLEMENTED;
647 				break;
648 			}
649 			if (request->pipe_policy.pipe_id & USB_ENDPOINT_DIR_MASK)
650 				*((PULONG)output_buffer) = dev->control_read_timeout;
651 			else
652 				*((PULONG)output_buffer) = dev->control_write_timeout;
653 
654 			status = STATUS_SUCCESS;
655 			break;
656 		}
657 		break;
658 
659 	case LIBUSB_IOCTL_SET_POWER_POLICY:			// METHOD_BUFFERED (SET_POWER_POLICY)
660 		status = STATUS_NOT_IMPLEMENTED;
661 		break;
662 
663 	case LIBUSB_IOCTL_GET_POWER_POLICY:			// METHOD_BUFFERED (GET_POWER_POLICY)
664 		status = STATUS_NOT_IMPLEMENTED;
665 		break;
666 
667 	case LIBUSB_IOCTL_CONTROL_WRITE:			// METHOD_IN_DIRECT (CONTROL_WRITE)
668 		// check if the request and buffer is valid
669 		if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
670 		{
671 			USBERR("%s: invalid transfer request\n", dispCtlCode);
672 			status = STATUS_INVALID_PARAMETER;
673 			goto IOCTL_Done;
674 		}
675 
676 		status = control_transfer(
677 			dev,
678 			irp,
679 			transfer_buffer_mdl,
680 			transfer_buffer_length,
681 			USBD_TRANSFER_DIRECTION_OUT,
682 			&ret,
683 			dev->control_write_timeout,
684 			request->control.RequestType,
685 			request->control.Request,
686 			request->control.Value,
687 			request->control.Index,
688 			request->control.Length);
689 
690 		break;
691 
692 	case LIBUSB_IOCTL_CONTROL_READ:				// METHOD_OUT_DIRECT (CONTROL_READ)
693 		// check if the request and buffer is valid
694 		if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
695 		{
696 			USBERR("%s: invalid transfer request\n", dispCtlCode);
697 			status = STATUS_INVALID_PARAMETER;
698 			goto IOCTL_Done;
699 		}
700 
701 		status = control_transfer(
702 			dev,
703 			irp,
704 			transfer_buffer_mdl,
705 			transfer_buffer_length,
706 			USBD_TRANSFER_DIRECTION_IN,
707 			&ret,
708 			dev->control_read_timeout,
709 			request->control.RequestType,
710 			request->control.Request,
711 			request->control.Value,
712 			request->control.Index,
713 			request->control.Length);
714 
715 		break;
716 
717 	case LIBUSB_IOCTL_FLUSH_PIPE:				// METHOD_BUFFERED (FLUSH_PIPE)
718 
719 		status = STATUS_SUCCESS;
720 		break;
721 
722 
723 	case LIBUSBK_IOCTL_CLAIM_INTERFACE:			// METHOD_BUFFERED (CLAIM_INTERFACE)
724 		if (!request || output_buffer_length < sizeof(libusb_request))
725 		{
726 			USBERR0("claim_interfaceK: invalid output buffer\n");
727 			status = STATUS_BUFFER_TOO_SMALL;
728 			break;
729 		}
730 
731 		status = claim_interface_ex(dev, stack_location->FileObject, &request->intf);
732 		if (NT_SUCCESS(status))
733 		{
734 			ret = sizeof(libusb_request);
735 		}
736 		break;
737 
738 	case LIBUSBK_IOCTL_RELEASE_INTERFACE:		// METHOD_BUFFERED (RELEASE_INTERFACE)
739 
740 		if (!request || output_buffer_length < sizeof(libusb_request))
741 		{
742 			USBERR0("release_interfaceK: invalid output buffer\n");
743 			status = STATUS_BUFFER_TOO_SMALL;
744 			break;
745 		}
746 
747 		status = release_interface_ex(dev, stack_location->FileObject, &request->intf);
748 		if (NT_SUCCESS(status))
749 		{
750 			ret = sizeof(libusb_request);
751 		}
752 		break;
753 
754 	case LIBUSBK_IOCTL_SET_INTERFACE:			// METHOD_BUFFERED (SET_INTERFACE)
755 
756 		if (!request || output_buffer_length < sizeof(libusb_request))
757 		{
758 			USBERR0("set_interfaceK: invalid output buffer\n");
759 			status = STATUS_BUFFER_TOO_SMALL;
760 			break;
761 		}
762 
763 		status = set_interface_ex(dev, &request->intf, request->timeout);
764 		if (NT_SUCCESS(status))
765 		{
766 			ret = sizeof(libusb_request);
767 		}
768 		break;
769 
770 	case LIBUSBK_IOCTL_GET_INTERFACE:			// METHOD_BUFFERED (GET_INTERFACE)
771 
772 		if (!request || output_buffer_length < sizeof(libusb_request))
773 		{
774 			USBERR0("get_interfaceK: invalid output buffer\n");
775 			status = STATUS_BUFFER_TOO_SMALL;
776 			break;
777 		}
778 
779 		status = get_interface_ex(dev, &request->intf, request->timeout);
780 		if (NT_SUCCESS(status))
781 		{
782 			ret = sizeof(libusb_request);
783 		}
784 		break;
785 
786 	default:
787 		status = STATUS_INVALID_PARAMETER;
788 	}
789 
790 IOCTL_Done:
791 	status = complete_irp(irp, status, ret);
792 	remove_lock_release(dev);
793 
794 	return status;
795 }
796