rename status-code.h
[gnuk/gnuk.git] / src / usb-msc.c
1 /*
2  * usb-msc.c -- USB Mass Storage Class protocol handling
3  *
4  * Copyright (C) 2011, 2012, 2013, 2015
5  *               Free Software Initiative of Japan
6  * Author: NIIBE Yutaka <gniibe@fsij.org>
7  *
8  * This file is a part of Gnuk, a GnuPG USB Token implementation.
9  *
10  * Gnuk is free software: you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include <stdint.h>
26 #include <string.h>
27 #include <chopstx.h>
28
29 #include "config.h"
30 #include "gnuk.h"
31 #include "usb_lld.h"
32 #include "usb-msc.h"
33
34 extern uint8_t __process5_stack_base__[], __process5_stack_size__[];
35 #define STACK_ADDR_MSC ((uint32_t)__process5_stack_base__)
36 #define STACK_SIZE_MSC ((uint32_t)__process5_stack_size__)
37 #define PRIO_MSC 3
38
39 static chopstx_mutex_t a_pinpad_mutex;
40 static chopstx_cond_t a_pinpad_cond;
41
42 static chopstx_mutex_t a_msc_mutex;
43 static chopstx_cond_t a_msc_cond;
44
45 #define RDY_OK    0
46 #define RDY_RESET 1
47 static uint8_t msg;
48
49 chopstx_mutex_t *pinpad_mutex = &a_pinpad_mutex;
50 chopstx_cond_t *pinpad_cond = &a_pinpad_cond;
51
52 static chopstx_mutex_t *msc_mutex = &a_msc_mutex;
53 static chopstx_cond_t *msc_cond = &a_msc_cond;
54
55
56 struct usb_endp_in {
57   const uint8_t *txbuf;      /* Pointer to the transmission buffer. */
58   size_t txsize;             /* Transmit transfer size remained. */
59   size_t txcnt;              /* Transmitted bytes so far. */
60 };
61
62 struct usb_endp_out {
63   uint8_t *rxbuf;               /* Pointer to the receive buffer. */
64   size_t rxsize;                /* Requested receive transfer size. */
65   size_t rxcnt;                 /* Received bytes so far.  */
66 };
67
68 static struct usb_endp_in ep6_in;
69 static struct usb_endp_out ep6_out;
70
71 #define ENDP_MAX_SIZE 64
72
73 static uint8_t msc_state;
74
75
76 static void usb_start_transmit (const uint8_t *p, size_t n)
77 {
78   size_t pkt_len = n > ENDP_MAX_SIZE ? ENDP_MAX_SIZE : n;
79
80   ep6_in.txbuf = p;
81   ep6_in.txsize = n;
82   ep6_in.txcnt = 0;
83
84   usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, pkt_len);
85 }
86
87 /* "Data Transmitted" callback */
88 void
89 EP6_IN_Callback (uint16_t len)
90 {
91   size_t n = len;
92
93   chopstx_mutex_lock (msc_mutex);
94
95   ep6_in.txbuf += n;
96   ep6_in.txcnt += n;
97   ep6_in.txsize -= n;
98
99   if (ep6_in.txsize > 0)        /* More data to be sent */
100     {
101       if (ep6_in.txsize > ENDP_MAX_SIZE)
102         n = ENDP_MAX_SIZE;
103       else
104         n = ep6_in.txsize;
105       usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, n);
106     }
107   else
108     /* Transmit has been completed, notify the waiting thread */
109     switch (msc_state)
110       {
111       case MSC_SENDING_CSW:
112       case MSC_DATA_IN:
113         msg = RDY_OK;
114         chopstx_cond_signal (msc_cond);
115         break;
116       default:
117         break;
118       }
119
120   chopstx_mutex_unlock (msc_mutex);
121 }
122
123
124 static void usb_start_receive (uint8_t *p, size_t n)
125 {
126   ep6_out.rxbuf = p;
127   ep6_out.rxsize = n;
128   ep6_out.rxcnt = 0;
129   usb_lld_rx_enable (ENDP6);
130 }
131
132 /* "Data Received" call back */
133 void
134 EP6_OUT_Callback (uint16_t len)
135 {
136   size_t n = len;
137   int err = 0;
138
139   chopstx_mutex_lock (msc_mutex);
140
141   if (n > ep6_out.rxsize)
142     {                           /* buffer overflow */
143       err = 1;
144       n = ep6_out.rxsize;
145     }
146
147   usb_lld_rxcpy (ep6_out.rxbuf, ENDP6, 0, n);
148   ep6_out.rxbuf += n;
149   ep6_out.rxcnt += n;
150   ep6_out.rxsize -= n;
151
152   if (n == ENDP_MAX_SIZE && ep6_out.rxsize != 0)
153     /* More data to be received */
154     usb_lld_rx_enable (ENDP6);
155   else
156     /* Receiving has been completed, notify the waiting thread */
157     switch (msc_state)
158       {
159       case MSC_IDLE:
160       case MSC_DATA_OUT:
161         msg = err ? RDY_RESET : RDY_OK;
162         chopstx_cond_signal (msc_cond);
163         break;
164       default:
165         break;
166       }
167
168   chopstx_mutex_unlock (msc_mutex);
169 }
170
171 static const uint8_t scsi_inquiry_data_00[] = { 0, 0, 0, 0, 0 };
172 static const uint8_t scsi_inquiry_data_83[] = { 0, 0x83, 0, 0 };
173
174
175 static const uint8_t scsi_inquiry_data[] = {
176   0x00,                         /* Direct Access Device.      */
177   0x80,                         /* RMB = 1: Removable Medium. */
178   0x00,                         /* Version: not claim conformance.  */
179   0x02,                         /* Response format: SPC-3.    */
180   36 - 4,                       /* Additional Length.         */
181   0x00,
182   0x00,
183   0x00,
184                                 /* Vendor Identification */
185   'F', 'S', 'I', 'J', ' ', ' ', ' ', ' ',
186                                 /* Product Identification */
187   'V', 'i', 'r', 't', 'u', 'a', 'l', ' ',
188   'D', 'i', 's', 'k', ' ', ' ', ' ', ' ',
189                                 /* Product Revision Level */
190   '1', '.', '0', ' '
191 };
192
193 static uint8_t scsi_sense_data_desc[] = {
194   0x72,                   /* Response Code: descriptor, current */
195   0x02,                   /* Sense Key */
196   0x3a,                   /* ASC (additional sense code) */
197   0x00,                   /* ASCQ (additional sense code qualifier) */
198   0x00, 0x00, 0x00,
199   0x00,                   /* Additional Sense Length */
200 };
201
202 static uint8_t scsi_sense_data_fixed[] = {
203   0x70,                   /* Response Code: fixed, current */
204   0x00,
205   0x02,                   /* Sense Key */
206   0x00, 0x00, 0x00, 0x00,
207   0x0a,                   /* Additional Sense Length */
208   0x00, 0x00, 0x00, 0x00,
209   0x3a,                   /* ASC (additional sense code) */
210   0x00,                   /* ASCQ (additional sense code qualifier) */
211   0x00,
212   0x00, 0x00, 0x00,
213 };
214
215 static void set_scsi_sense_data(uint8_t sense_key, uint8_t asc)
216 {
217   scsi_sense_data_desc[1] = scsi_sense_data_fixed[2] = sense_key;
218   scsi_sense_data_desc[2] = scsi_sense_data_fixed[12] = asc;
219 }
220
221
222 static uint8_t buf[512];
223
224 static uint8_t contingent_allegiance;
225 static uint8_t keep_contingent_allegiance;
226
227 uint8_t media_available;
228
229 void
230 msc_media_insert_change (int available)
231 {
232   contingent_allegiance = 1;
233   media_available = available;
234   if (available)
235     {
236       set_scsi_sense_data (0x06, 0x28); /* UNIT_ATTENTION */
237       keep_contingent_allegiance = 0;
238     }
239   else
240     {
241       set_scsi_sense_data (0x02, 0x3a); /* NOT_READY */
242       keep_contingent_allegiance = 1;
243     }
244 }
245
246
247 static uint8_t scsi_read_format_capacities (uint32_t *nblocks,
248                                             uint32_t *secsize)
249 {
250   *nblocks = 68;
251   *secsize = 512;
252   if (media_available)
253     return 2; /* Formatted Media.*/
254   else
255     return 3; /* No Media.*/
256 }
257
258 static struct CBW CBW;
259
260 static struct CSW CSW;
261
262
263 /* called with holding the lock.  */
264 static int msc_recv_data (void)
265 {
266   msc_state = MSC_DATA_OUT;
267   usb_start_receive (buf, 512);
268   chopstx_cond_wait (msc_cond, msc_mutex);
269   return 0;
270 }
271
272 /* called with holding the lock.  */
273 static void msc_send_data (const uint8_t *p, size_t n)
274 {
275   msc_state = MSC_DATA_IN;
276   usb_start_transmit (p, n);
277   chopstx_cond_wait (msc_cond, msc_mutex);
278   CSW.dCSWDataResidue -= (uint32_t)n;
279 }
280
281 /* called with holding the lock.  */
282 static void msc_send_result (const uint8_t *p, size_t n)
283 {
284   if (p != NULL)
285     {
286       if (n > CBW.dCBWDataTransferLength)
287         n = CBW.dCBWDataTransferLength;
288
289       CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
290       msc_send_data (p, n);
291       CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
292     }
293
294   CSW.dCSWSignature = MSC_CSW_SIGNATURE;
295
296   msc_state = MSC_SENDING_CSW;
297   usb_start_transmit ((uint8_t *)&CSW, sizeof CSW);
298   chopstx_cond_wait (msc_cond, msc_mutex);
299 }
300
301
302 void
303 msc_handle_command (void)
304 {
305   size_t n;
306   uint32_t nblocks, secsize;
307   uint32_t lba;
308   int r;
309
310   chopstx_mutex_lock (msc_mutex);
311   msc_state = MSC_IDLE;
312   usb_start_receive ((uint8_t *)&CBW, sizeof CBW);
313   chopstx_cond_wait (msc_cond, msc_mutex);
314
315   if (msg != RDY_OK)
316     {
317       /* Error occured, ignore the request and go into error state */
318       msc_state = MSC_ERROR;
319       usb_lld_stall_rx (ENDP6);
320       goto done;
321     }
322
323   n = ep6_out.rxcnt;
324
325   if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
326     {
327       msc_state = MSC_ERROR;
328       usb_lld_stall_rx (ENDP6);
329       goto done;
330     }
331
332   CSW.dCSWTag = CBW.dCBWTag;
333   switch (CBW.CBWCB[0]) {
334   case SCSI_REPORT_LUN:
335     buf[0]  = buf[1] = buf[2] = buf[3] = 0;
336     buf[4]  = buf[5] = buf[6] = buf[7] = 0;
337     msc_send_result (buf, 8);
338     goto done;
339   case SCSI_REQUEST_SENSE:
340     if (CBW.CBWCB[1] & 0x01) /* DESC */
341       msc_send_result ((uint8_t *)&scsi_sense_data_desc,
342                        sizeof scsi_sense_data_desc);
343     else
344       msc_send_result ((uint8_t *)&scsi_sense_data_fixed,
345                        sizeof scsi_sense_data_fixed);
346     /* After the error is reported, clear it, if it's .  */
347     if (!keep_contingent_allegiance)
348       {
349         contingent_allegiance = 0;
350         set_scsi_sense_data (0x00, 0x00);
351       }
352     goto done;
353   case SCSI_INQUIRY:
354     if (CBW.CBWCB[1] & 0x01)
355       /* EVPD */
356       {
357         if (CBW.CBWCB[2] == 0x83)
358           /* Handle the case Page Code 0x83 */
359           msc_send_result ((uint8_t *)&scsi_inquiry_data_83,
360                            sizeof scsi_inquiry_data_83);
361         else
362           /* Otherwise, assume page 00 */
363           msc_send_result ((uint8_t *)&scsi_inquiry_data_00,
364                            sizeof scsi_inquiry_data_00);
365       }
366     else
367       msc_send_result ((uint8_t *)&scsi_inquiry_data,
368                        sizeof scsi_inquiry_data);
369     goto done;
370   case SCSI_READ_FORMAT_CAPACITIES:
371     buf[8]  = scsi_read_format_capacities (&nblocks, &secsize);
372     buf[0]  = buf[1] = buf[2] = 0;
373     buf[3]  = 8;
374     buf[4]  = (uint8_t)(nblocks >> 24);
375     buf[5]  = (uint8_t)(nblocks >> 16);
376     buf[6]  = (uint8_t)(nblocks >> 8);
377     buf[7]  = (uint8_t)(nblocks >> 0);
378     buf[9]  = (uint8_t)(secsize >> 16);
379     buf[10] = (uint8_t)(secsize >> 8);
380     buf[11] = (uint8_t)(secsize >> 0);
381     msc_send_result (buf, 12);
382     goto done;
383   case SCSI_START_STOP_UNIT:
384     if (CBW.CBWCB[4] == 0x00 /* stop */
385         || CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
386       {
387         msc_scsi_stop (CBW.CBWCB[4]);
388         set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */
389         contingent_allegiance = 1;
390         keep_contingent_allegiance = 1;
391       }
392     /* CBW.CBWCB[4] == 0x01 *//* start */
393     goto success;
394   case SCSI_TEST_UNIT_READY:
395     if (contingent_allegiance)
396       {
397         CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
398         CSW.dCSWDataResidue = 0;
399         msc_send_result (NULL, 0);
400         goto done;
401       }
402     /* fall through */
403   success:
404   case SCSI_SYNCHRONIZE_CACHE:
405   case SCSI_VERIFY10:
406   case SCSI_ALLOW_MEDIUM_REMOVAL:
407     CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
408     CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
409     msc_send_result (NULL, 0);
410     goto done;
411   case SCSI_MODE_SENSE6:
412     buf[0] = 0x03;
413     buf[1] = buf[2] = buf[3] = 0;
414     msc_send_result (buf, 4);
415     goto done;
416   case SCSI_READ_CAPACITY10:
417     scsi_read_format_capacities (&nblocks, &secsize);
418     buf[0]  = (uint8_t)((nblocks - 1) >> 24);
419     buf[1]  = (uint8_t)((nblocks - 1) >> 16);
420     buf[2]  = (uint8_t)((nblocks - 1) >> 8);
421     buf[3]  = (uint8_t)((nblocks - 1) >> 0);
422     buf[4]  = (uint8_t)(secsize >> 24);
423     buf[5]  = (uint8_t)(secsize >> 16);
424     buf[6] = (uint8_t)(secsize >> 8);
425     buf[7] = (uint8_t)(secsize >> 0);
426     msc_send_result (buf, 8);
427     goto done;
428   case SCSI_READ10:
429   case SCSI_WRITE10:
430     break;
431   default:
432     if (CBW.dCBWDataTransferLength == 0)
433       {
434         CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
435         CSW.dCSWDataResidue = 0;
436         msc_send_result (NULL, 0);
437         goto done;
438       }
439     else
440       {
441         msc_state = MSC_ERROR;
442         usb_lld_stall_tx (ENDP6);
443         usb_lld_stall_rx (ENDP6);
444         goto done;
445       }
446   }
447
448   lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16)
449       | (CBW.CBWCB[4] <<  8) | CBW.CBWCB[5];
450
451   /* Transfer direction.*/
452   if (CBW.bmCBWFlags & 0x80)
453     {
454       /* IN, Device to Host.*/
455       msc_state = MSC_DATA_IN;
456       if (CBW.CBWCB[0] == SCSI_READ10)
457         {
458           const uint8_t *p;
459
460           CSW.dCSWDataResidue = 0;
461           while (1)
462             {
463               if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0)
464                 {
465                   CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
466                   break;
467                 }
468
469               if ((r = msc_scsi_read (lba, &p)) == 0)
470                 {
471                   msc_send_data (p, 512);
472                   if (++CBW.CBWCB[5] == 0)
473                     if (++CBW.CBWCB[4] == 0)
474                       if (++CBW.CBWCB[3] == 0)
475                         ++CBW.CBWCB[2];
476                   if (CBW.CBWCB[8]-- == 0)
477                     CBW.CBWCB[7]--;
478                   CSW.dCSWDataResidue += 512;
479                   lba++;
480                 }
481               else
482                 {
483                   CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
484                   contingent_allegiance = 1;
485                   if (r == SCSI_ERROR_NOT_READY)
486                     set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
487                   else
488                     set_scsi_sense_data (r, 0x00);
489                   break;
490                 }
491             }
492
493           msc_send_result (NULL, 0);
494         }
495     }
496   else
497     {
498       /* OUT, Host to Device.*/
499       if (CBW.CBWCB[0] == SCSI_WRITE10)
500         {
501           CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
502
503           while (1)
504             {
505               if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0)
506                 {
507                   CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
508                   break;
509                 }
510
511               msc_recv_data ();
512               if (msg != RDY_OK)
513                 /* ignore erroneous packet, ang go next.  */
514                 continue;
515
516               if ((r = msc_scsi_write (lba, buf, 512)) == 0)
517                 {
518                   if (++CBW.CBWCB[5] == 0)
519                     if (++CBW.CBWCB[4] == 0)
520                       if (++CBW.CBWCB[3] == 0)
521                         ++CBW.CBWCB[2];
522                   if (CBW.CBWCB[8]-- == 0)
523                     CBW.CBWCB[7]--;
524                   CSW.dCSWDataResidue -= 512;
525                   lba++;
526                 }
527               else
528                 {
529                   CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
530                   contingent_allegiance = 1;
531                   if (r == SCSI_ERROR_NOT_READY)
532                     set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
533                   else
534                     set_scsi_sense_data (r, 0x00);
535                   break;
536                 }
537             }
538
539           msc_send_result (NULL, 0);
540         }
541     }
542
543  done:
544   chopstx_mutex_unlock (msc_mutex);
545 }
546
547
548 static void *
549 msc_main (void *arg)
550 {
551   (void)arg;
552
553   chopstx_mutex_init (msc_mutex);
554   chopstx_cond_init (msc_cond);
555
556   chopstx_mutex_init (pinpad_mutex);
557   chopstx_cond_init (pinpad_cond);
558
559   /* Initially, it starts with no media */
560   msc_media_insert_change (0);
561   while (1)
562     msc_handle_command ();
563
564   return NULL;
565 }
566
567
568 void
569 msc_init (void)
570 {
571   chopstx_create (PRIO_MSC, STACK_ADDR_MSC, STACK_SIZE_MSC, msc_main, NULL);
572 }