CCID Low Level Demo: Add missing request length check.
[pub/lufa.git] / LUFA / Drivers / USB / Class / Device / CCIDClassDevice.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2021.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2021 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 Copyright 2021 Filipe Rodrigues (filipepazrodrigues [at] gmail [dot] com)
12
13 Permission to use, copy, modify, distribute, and sell this
14 software and its documentation for any purpose is hereby granted
15 without fee, provided that the above copyright notice appear in
16 all copies and that both that the copyright notice and this
17 permission notice and warranty disclaimer appear in supporting
18 documentation, and that the name of the author not be used in
19 advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
21
22 The author disclaims all warranties with regard to this
23 software, including all implied warranties of merchantability
24 and fitness. In no event shall the author be liable for any
25 special, indirect or consequential damages or any damages
26 whatsoever resulting from loss of use, data or profits, whether
27 in an action of contract, negligence or other tortious action,
28 arising out of or in connection with the use or performance of
29 this software.
30 */
31
32 #define __INCLUDE_FROM_USB_DRIVER
33 #include "../../Core/USBMode.h"
34
35 #if defined(USB_CAN_BE_DEVICE)
36
37 #define __INCLUDE_FROM_CCID_DRIVER
38 #define __INCLUDE_FROM_CCID_DEVICE_C
39 #include "CCIDClassDevice.h"
40
41
42 bool CCID_CheckStatusNoError(uint8_t Status)
43 {
44 return (Status & 0xC0) == 0x0;
45 }
46
47 void CCID_Device_ProcessControlRequest(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
48 {
49 if (!(Endpoint_IsSETUPReceived()))
50 return;
51
52 if (USB_ControlRequest.wIndex != CCIDInterfaceInfo->Config.InterfaceNumber)
53 return;
54
55 switch (USB_ControlRequest.bRequest)
56 {
57 case CCID_ABORT:
58 {
59 // Initiates the abort process.
60 // The host should send 2 messages in the following order:
61 // - CCID_ABORT control request
62 // - CCID_PC_t_PCo_RDR_Abort command
63 //
64 // If the device is still processing a message, it should fail it until receiving a CCIRPC_to_RDR_Abort
65 // command.
66 //
67 // When the device receives the CCIRPC_to_RDR_Abort message, it replies with RDR_to_PC_SlotStatus
68 // and the abort process ends.
69
70 // The wValue field contains the slot number (bSlot) in the low byte and the sequence number (bSeq) in
71 // the high byte
72 uint8_t Slot = USB_ControlRequest.wValue & 0xFF;
73 uint8_t Seq = USB_ControlRequest.wValue >> 8;
74
75 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE) && Slot == 0)
76 {
77 Endpoint_ClearSETUP();
78
79 CCIDInterfaceInfo->State.Aborted = true;
80 CCIDInterfaceInfo->State.AbortedSeq = Seq;
81
82 Endpoint_ClearOUT();
83 }
84
85 break;
86 }
87
88 case CCID_GET_CLOCK_FREQUENCIES:
89 {
90 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
91 {
92
93 Endpoint_ClearSETUP();
94 Endpoint_Write_8(0); // Not supported
95 Endpoint_ClearOUT();
96 }
97 break;
98 }
99
100 case CCID_GET_DATA_RATES:
101 {
102 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
103 {
104
105 Endpoint_ClearSETUP();
106 Endpoint_Write_8(0); // Not supported
107 Endpoint_ClearOUT();
108 }
109 break;
110 }
111 }
112 }
113
114 bool CCID_Device_ConfigureEndpoints(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
115 {
116 CCIDInterfaceInfo->Config.DataINEndpoint.Type = EP_TYPE_BULK;
117 CCIDInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK;
118
119 if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo->Config.DataINEndpoint, 1)))
120 return false;
121
122 if (!(Endpoint_ConfigureEndpointTable(&CCIDInterfaceInfo->Config.DataOUTEndpoint, 1)))
123 return false;
124
125 return true;
126 }
127
128 void CCID_Device_USBTask(USB_ClassInfo_CCID_Device_t* const CCIDInterfaceInfo)
129 {
130 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataOUTEndpoint.Address);
131
132 uint8_t RequestBuffer[0x40 - sizeof(USB_CCID_BulkMessage_Header_t)];
133 uint8_t ResponseBuffer[0x40];
134
135 CCIDInterfaceInfo->State.Aborted = false;
136 CCIDInterfaceInfo->State.AbortedSeq = -1;
137
138 if (Endpoint_IsOUTReceived())
139 {
140 USB_CCID_BulkMessage_Header_t CCIDHeader;
141 CCIDHeader.MessageType = Endpoint_Read_8();
142 CCIDHeader.Length = Endpoint_Read_32_LE();
143 CCIDHeader.Slot = Endpoint_Read_8();
144 CCIDHeader.Seq = Endpoint_Read_8();
145
146 uint8_t Status;
147 uint8_t Error = CCID_ERROR_NO_ERROR;
148
149 switch (CCIDHeader.MessageType)
150 {
151 case CCID_PC_to_RDR_IccPowerOn:
152 {
153 uint8_t AtrLength;
154 USB_CCID_RDR_to_PC_DataBlock_t* ResponseATR = (USB_CCID_RDR_to_PC_DataBlock_t*)&ResponseBuffer;
155
156 ResponseATR->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock;
157 ResponseATR->CCIDHeader.Slot = CCIDHeader.Slot;
158 ResponseATR->CCIDHeader.Seq = CCIDHeader.Seq;
159 ResponseATR->ChainParam = 0;
160
161 Status = CALLBACK_CCID_IccPowerOn(CCIDInterfaceInfo, ResponseATR->CCIDHeader.Slot, (uint8_t*)ResponseATR->Data, &AtrLength, &Error);
162
163 if (CCID_CheckStatusNoError(Status) && !CCIDInterfaceInfo->State.Aborted)
164 {
165 ResponseATR->CCIDHeader.Length = AtrLength;
166 }
167 else if (CCIDInterfaceInfo->State.Aborted)
168 {
169 Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE;
170 Error = CCID_ERROR_CMD_ABORTED;
171 AtrLength = 0;
172 }
173 else
174 {
175 AtrLength = 0;
176 }
177
178 ResponseATR->Status = Status;
179 ResponseATR->Error = Error;
180
181 Endpoint_ClearOUT();
182
183 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
184 Endpoint_Write_Stream_LE(ResponseATR, sizeof(USB_CCID_RDR_to_PC_DataBlock_t) + AtrLength, NULL);
185 Endpoint_ClearIN();
186 break;
187 }
188
189 case CCID_PC_to_RDR_IccPowerOff:
190 {
191 USB_CCID_RDR_to_PC_SlotStatus_t* ResponsePowerOff = (USB_CCID_RDR_to_PC_SlotStatus_t*)&ResponseBuffer;
192 ResponsePowerOff->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
193 ResponsePowerOff->CCIDHeader.Length = 0;
194 ResponsePowerOff->CCIDHeader.Slot = CCIDHeader.Slot;
195 ResponsePowerOff->CCIDHeader.Seq = CCIDHeader.Seq;
196
197 ResponsePowerOff->ClockStatus = 0;
198
199 Status = CALLBACK_CCID_IccPowerOff(CCIDInterfaceInfo, CCIDHeader.Slot, &Error);
200
201 ResponsePowerOff->Status = Status;
202 ResponsePowerOff->Error = Error;
203
204 Endpoint_ClearOUT();
205
206 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
207 Endpoint_Write_Stream_LE(ResponsePowerOff, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
208 Endpoint_ClearIN();
209 break;
210 }
211
212 case CCID_PC_to_RDR_GetSlotStatus:
213 {
214 USB_CCID_RDR_to_PC_SlotStatus_t* ResponseSlotStatus = (USB_CCID_RDR_to_PC_SlotStatus_t*)&ResponseBuffer;
215 ResponseSlotStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
216 ResponseSlotStatus->CCIDHeader.Length = 0;
217 ResponseSlotStatus->CCIDHeader.Slot = CCIDHeader.Slot;
218 ResponseSlotStatus->CCIDHeader.Seq = CCIDHeader.Seq;
219
220 ResponseSlotStatus->ClockStatus = 0;
221
222 Status = CALLBACK_CCID_GetSlotStatus(CCIDInterfaceInfo, CCIDHeader.Slot, &Error);
223
224 ResponseSlotStatus->Status = Status;
225 ResponseSlotStatus->Error = Error;
226
227 Endpoint_ClearOUT();
228
229 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
230 Endpoint_Write_Stream_LE(ResponseSlotStatus, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
231 Endpoint_ClearIN();
232 break;
233 }
234
235 case CCID_PC_to_RDR_SetParameters:
236 {
237 uint8_t ProtocolNum = Endpoint_Read_8();
238 uint8_t RFU = Endpoint_Read_16_LE();
239
240 (void)RFU;
241
242 USB_CCID_RDR_to_PC_Parameters_t* ResponseParametersStatus = (USB_CCID_RDR_to_PC_Parameters_t*)&ResponseBuffer;
243 ResponseParametersStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_Parameters;
244 ResponseParametersStatus->CCIDHeader.Length = 0;
245 ResponseParametersStatus->CCIDHeader.Slot = CCIDHeader.Slot;
246 ResponseParametersStatus->CCIDHeader.Seq = CCIDHeader.Seq;
247
248 if (ProtocolNum == CCID_PROTOCOLNUM_T0)
249 {
250 if (CCIDHeader.Length * sizeof(uint8_t) == sizeof(USB_CCID_ProtocolData_T0_t))
251 {
252 Endpoint_Read_Stream_LE(RequestBuffer, CCIDHeader.Length * sizeof(uint8_t), NULL);
253 Status = CALLBACK_CCID_SetParameters_T0(CCIDInterfaceInfo, CCIDHeader.Slot, &Error, (USB_CCID_ProtocolData_T0_t*) RequestBuffer);
254 if (CCID_CheckStatusNoError(Status))
255 {
256 ResponseParametersStatus->CCIDHeader.Length = CCIDHeader.Length;
257 Status = CALLBACK_CCID_GetParameters_T0(CCIDInterfaceInfo, CCIDHeader.Slot, &Error, &ResponseParametersStatus->ProtocolNum, (USB_CCID_ProtocolData_T0_t*) &ResponseParametersStatus->ProtocolData);
258 }
259 }
260 else
261 {
262 // Unexpected length
263 Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE;
264 }
265 }
266 else
267 {
268 ResponseParametersStatus->ProtocolNum = CCID_PROTOCOLNUM_T0;
269
270 // For now, we don't support T=1 protocol
271 Error = CCID_ERROR_PARAMETERS_PROTOCOL_NOT_SUPPORTED;
272 Status = CCID_COMMANDSTATUS_ERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
273 }
274
275 ResponseParametersStatus->Status = Status;
276 ResponseParametersStatus->Error = Error;
277
278 Endpoint_ClearOUT();
279
280 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
281 Endpoint_Write_Stream_LE(ResponseParametersStatus, sizeof(USB_CCID_BulkMessage_Header_t) + 3 + ResponseParametersStatus->CCIDHeader.Length , NULL);
282 Endpoint_ClearIN();
283 break;
284 }
285
286 case CCID_PC_to_RDR_GetParameters:
287 {
288 USB_CCID_RDR_to_PC_Parameters_t* ResponseParametersStatus = (USB_CCID_RDR_to_PC_Parameters_t*)&ResponseBuffer;
289 ResponseParametersStatus->CCIDHeader.MessageType = CCID_RDR_to_PC_Parameters;
290 ResponseParametersStatus->CCIDHeader.Length = sizeof(USB_CCID_ProtocolData_T0_t);
291 ResponseParametersStatus->CCIDHeader.Slot = CCIDHeader.Slot;
292 ResponseParametersStatus->CCIDHeader.Seq = CCIDHeader.Seq;
293
294 Status = CALLBACK_CCID_GetParameters_T0(CCIDInterfaceInfo, CCIDHeader.Slot, &Error, &ResponseParametersStatus->ProtocolNum, (USB_CCID_ProtocolData_T0_t*) &ResponseParametersStatus->ProtocolData);
295
296 ResponseParametersStatus->Status = Status;
297 ResponseParametersStatus->Error = Error;
298
299 Endpoint_ClearOUT();
300
301 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
302 Endpoint_Write_Stream_LE(ResponseParametersStatus, sizeof(USB_CCID_BulkMessage_Header_t) + 3 + ResponseParametersStatus->CCIDHeader.Length , NULL);
303 Endpoint_ClearIN();
304 break;
305 }
306
307 case CCID_PC_to_RDR_XfrBlock:
308 {
309 uint8_t Bwi = Endpoint_Read_8();
310 uint16_t LevelParameter = Endpoint_Read_16_LE();
311 uint8_t ReceivedBuffer[0x4];
312
313 (void)Bwi;
314 (void)LevelParameter;
315
316 Endpoint_Read_Stream_LE(ReceivedBuffer, sizeof(ReceivedBuffer), NULL);
317
318 uint8_t ResponseDataLength = 0;
319
320 USB_CCID_RDR_to_PC_DataBlock_t* ResponseBlock = (USB_CCID_RDR_to_PC_DataBlock_t*)&ResponseBuffer;
321 ResponseBlock->CCIDHeader.MessageType = CCID_RDR_to_PC_DataBlock;
322 ResponseBlock->CCIDHeader.Slot = CCIDHeader.Slot;
323 ResponseBlock->CCIDHeader.Seq = CCIDHeader.Seq;
324
325 ResponseBlock->ChainParam = 0;
326
327 Status = CALLBACK_CCID_XfrBlock(CCIDInterfaceInfo, CCIDHeader.Slot, RequestBuffer, CCIDHeader.Length, (uint8_t*) &ResponseBlock->Data, &ResponseDataLength, &Error);
328
329 if (CCID_CheckStatusNoError(Status) && !CCIDInterfaceInfo->State.Aborted)
330 {
331 ResponseBlock->CCIDHeader.Length = ResponseDataLength;
332 }
333 else if (CCIDInterfaceInfo->State.Aborted)
334 {
335 Status = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_PRESENTANDACTIVE;
336 Error = CCID_ERROR_CMD_ABORTED;
337 ResponseDataLength = 0;
338 }
339 else
340 {
341 ResponseDataLength = 0;
342 }
343
344 ResponseBlock->Status = Status;
345 ResponseBlock->Error = Error;
346
347 Endpoint_ClearOUT();
348
349 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
350 Endpoint_Write_Stream_LE(ResponseBlock, sizeof(USB_CCID_RDR_to_PC_DataBlock_t) + ResponseDataLength, NULL);
351 Endpoint_ClearIN();
352 break;
353 }
354
355 case CCID_PC_to_RDR_Abort:
356 {
357 USB_CCID_RDR_to_PC_SlotStatus_t* ResponseAbort = (USB_CCID_RDR_to_PC_SlotStatus_t*)&ResponseBuffer;
358 ResponseAbort->CCIDHeader.MessageType = CCID_RDR_to_PC_SlotStatus;
359 ResponseAbort->CCIDHeader.Length = 0;
360 ResponseAbort->CCIDHeader.Slot = CCIDHeader.Slot;
361 ResponseAbort->CCIDHeader.Seq = CCIDHeader.Seq;
362
363 ResponseAbort->ClockStatus = 0;
364
365 Status = CALLBACK_CCID_Abort(CCIDInterfaceInfo, CCIDHeader.Slot, CCIDHeader.Seq, &Error);
366
367 ResponseAbort->Status = Status;
368 ResponseAbort->Error = Error;
369
370 Endpoint_ClearOUT();
371
372 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
373 Endpoint_Write_Stream_LE(ResponseAbort, sizeof(USB_CCID_RDR_to_PC_SlotStatus_t), NULL);
374 Endpoint_ClearIN();
375 break;
376 }
377
378 default:
379 {
380 memset(ResponseBuffer, 0x00, sizeof(ResponseBuffer));
381
382 Endpoint_SelectEndpoint(CCIDInterfaceInfo->Config.DataINEndpoint.Address);
383 Endpoint_Write_Stream_LE(ResponseBuffer, sizeof(ResponseBuffer), NULL);
384 Endpoint_ClearIN();
385 break;
386 }
387 }
388 }
389 }
390
391 #endif