Version 1.1.9
[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 const uint32_t __stackaddr_msc = (uint32_t)&__process5_stack_base__;
36 const size_t __stacksize_msc = (size_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 (void)
90 {
91   size_t n;
92
93   chopstx_mutex_lock (msc_mutex);
94
95   n = (size_t)usb_lld_tx_data_len (ENDP6);
96   ep6_in.txbuf += n;
97   ep6_in.txcnt += n;
98   ep6_in.txsize -= n;
99
100   if (ep6_in.txsize > 0)        /* More data to be sent */
101     {
102       if (ep6_in.txsize > ENDP_MAX_SIZE)
103         n = ENDP_MAX_SIZE;
104       else
105         n = ep6_in.txsize;
106       usb_lld_write (ENDP6, (uint8_t *)ep6_in.txbuf, n);
107     }
108   else
109     /* Transmit has been completed, notify the waiting thread */
110     switch (msc_state)
111       {
112       case MSC_SENDING_CSW:
113       case MSC_DATA_IN:
114         msg = RDY_OK;
115         chopstx_cond_signal (msc_cond);
116         break;
117       default:
118         break;
119       }
120
121   chopstx_mutex_unlock (msc_mutex);
122 }
123
124
125 static void usb_start_receive (uint8_t *p, size_t n)
126 {
127   ep6_out.rxbuf = p;
128   ep6_out.rxsize = n;
129   ep6_out.rxcnt = 0;
130   usb_lld_rx_enable (ENDP6);
131 }
132
133 /* "Data Received" call back */
134 void
135 EP6_OUT_Callback (void)
136 {
137   size_t n;
138   int err = 0;
139
140   chopstx_mutex_lock (msc_mutex);
141
142   n =  (size_t)usb_lld_rx_data_len (ENDP6);
143   if (n > ep6_out.rxsize)
144     {                           /* buffer overflow */
145       err = 1;
146       n = ep6_out.rxsize;
147     }
148
149   usb_lld_rxcpy (ep6_out.rxbuf, ENDP6, 0, n);
150   ep6_out.rxbuf += n;
151   ep6_out.rxcnt += n;
152   ep6_out.rxsize -= n;
153
154   if (n == ENDP_MAX_SIZE && ep6_out.rxsize != 0)
155     /* More data to be received */
156     usb_lld_rx_enable (ENDP6);
157   else
158     /* Receiving has been completed, notify the waiting thread */
159     switch (msc_state)
160       {
161       case MSC_IDLE:
162       case MSC_DATA_OUT:
163         msg = err ? RDY_RESET : RDY_OK;
164         chopstx_cond_signal (msc_cond);
165         break;
166       default:
167         break;
168       }
169
170   chopstx_mutex_unlock (msc_mutex);
171 }
172
173 static const uint8_t scsi_inquiry_data_00[] = { 0, 0, 0, 0, 0 };
174 static const uint8_t scsi_inquiry_data_83[] = { 0, 0x83, 0, 0 };
175
176
177 static const uint8_t scsi_inquiry_data[] = {
178   0x00,                         /* Direct Access Device.      */
179   0x80,                         /* RMB = 1: Removable Medium. */
180   0x00,                         /* Version: not claim conformance.  */
181   0x02,                         /* Response format: SPC-3.    */
182   36 - 4,                       /* Additional Length.         */
183   0x00,
184   0x00,
185   0x00,
186                                 /* Vendor Identification */
187   'F', 'S', 'I', 'J', ' ', ' ', ' ', ' ',
188                                 /* Product Identification */
189   'V', 'i', 'r', 't', 'u', 'a', 'l', ' ',
190   'D', 'i', 's', 'k', ' ', ' ', ' ', ' ',
191                                 /* Product Revision Level */
192   '1', '.', '0', ' '
193 };
194
195 static uint8_t scsi_sense_data_desc[] = {
196   0x72,                   /* Response Code: descriptor, current */
197   0x02,                   /* Sense Key */
198   0x3a,                   /* ASC (additional sense code) */
199   0x00,                   /* ASCQ (additional sense code qualifier) */
200   0x00, 0x00, 0x00,
201   0x00,                   /* Additional Sense Length */
202 };
203
204 static uint8_t scsi_sense_data_fixed[] = {
205   0x70,                   /* Response Code: fixed, current */
206   0x00,
207   0x02,                   /* Sense Key */
208   0x00, 0x00, 0x00, 0x00,
209   0x0a,                   /* Additional Sense Length */
210   0x00, 0x00, 0x00, 0x00,
211   0x3a,                   /* ASC (additional sense code) */
212   0x00,                   /* ASCQ (additional sense code qualifier) */
213   0x00,
214   0x00, 0x00, 0x00,
215 };
216
217 static void set_scsi_sense_data(uint8_t sense_key, uint8_t asc)
218 {
219   scsi_sense_data_desc[1] = scsi_sense_data_fixed[2] = sense_key;
220   scsi_sense_data_desc[2] = scsi_sense_data_fixed[12] = asc;
221 }
222
223
224 static uint8_t buf[512];
225
226 static uint8_t contingent_allegiance;
227 static uint8_t keep_contingent_allegiance;
228
229 uint8_t media_available;
230
231 void
232 msc_media_insert_change (int available)
233 {
234   contingent_allegiance = 1;
235   media_available = available;
236   if (available)
237     {
238       set_scsi_sense_data (0x06, 0x28); /* UNIT_ATTENTION */
239       keep_contingent_allegiance = 0;
240     }
241   else
242     {
243       set_scsi_sense_data (0x02, 0x3a); /* NOT_READY */
244       keep_contingent_allegiance = 1;
245     }
246 }
247
248
249 static uint8_t scsi_read_format_capacities (uint32_t *nblocks,
250                                             uint32_t *secsize)
251 {
252   *nblocks = 68;
253   *secsize = 512;
254   if (media_available)
255     return 2; /* Formatted Media.*/
256   else
257     return 3; /* No Media.*/
258 }
259
260 static struct CBW CBW;
261
262 static struct CSW CSW;
263
264
265 /* called with holding the lock.  */
266 static int msc_recv_data (void)
267 {
268   msc_state = MSC_DATA_OUT;
269   usb_start_receive (buf, 512);
270   chopstx_cond_wait (msc_cond, msc_mutex);
271   return 0;
272 }
273
274 /* called with holding the lock.  */
275 static void msc_send_data (const uint8_t *p, size_t n)
276 {
277   msc_state = MSC_DATA_IN;
278   usb_start_transmit (p, n);
279   chopstx_cond_wait (msc_cond, msc_mutex);
280   CSW.dCSWDataResidue -= (uint32_t)n;
281 }
282
283 /* called with holding the lock.  */
284 static void msc_send_result (const uint8_t *p, size_t n)
285 {
286   if (p != NULL)
287     {
288       if (n > CBW.dCBWDataTransferLength)
289         n = CBW.dCBWDataTransferLength;
290
291       CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
292       msc_send_data (p, n);
293       CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
294     }
295
296   CSW.dCSWSignature = MSC_CSW_SIGNATURE;
297
298   msc_state = MSC_SENDING_CSW;
299   usb_start_transmit ((uint8_t *)&CSW, sizeof CSW);
300   chopstx_cond_wait (msc_cond, msc_mutex);
301 }
302
303
304 void
305 msc_handle_command (void)
306 {
307   size_t n;
308   uint32_t nblocks, secsize;
309   uint32_t lba;
310   int r;
311
312   chopstx_mutex_lock (msc_mutex);
313   msc_state = MSC_IDLE;
314   usb_start_receive ((uint8_t *)&CBW, sizeof CBW);
315   chopstx_cond_wait (msc_cond, msc_mutex);
316
317   if (msg != RDY_OK)
318     {
319       /* Error occured, ignore the request and go into error state */
320       msc_state = MSC_ERROR;
321       usb_lld_stall_rx (ENDP6);
322       goto done;
323     }
324
325   n = ep6_out.rxcnt;
326
327   if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE))
328     {
329       msc_state = MSC_ERROR;
330       usb_lld_stall_rx (ENDP6);
331       goto done;
332     }
333
334   CSW.dCSWTag = CBW.dCBWTag;
335   switch (CBW.CBWCB[0]) {
336   case SCSI_REPORT_LUN:
337     buf[0]  = buf[1] = buf[2] = buf[3] = 0;
338     buf[4]  = buf[5] = buf[6] = buf[7] = 0;
339     msc_send_result (buf, 8);
340     goto done;
341   case SCSI_REQUEST_SENSE:
342     if (CBW.CBWCB[1] & 0x01) /* DESC */
343       msc_send_result ((uint8_t *)&scsi_sense_data_desc,
344                        sizeof scsi_sense_data_desc);
345     else
346       msc_send_result ((uint8_t *)&scsi_sense_data_fixed,
347                        sizeof scsi_sense_data_fixed);
348     /* After the error is reported, clear it, if it's .  */
349     if (!keep_contingent_allegiance)
350       {
351         contingent_allegiance = 0;
352         set_scsi_sense_data (0x00, 0x00);
353       }
354     goto done;
355   case SCSI_INQUIRY:
356     if (CBW.CBWCB[1] & 0x01)
357       /* EVPD */
358       {
359         if (CBW.CBWCB[2] == 0x83)
360           /* Handle the case Page Code 0x83 */
361           msc_send_result ((uint8_t *)&scsi_inquiry_data_83,
362                            sizeof scsi_inquiry_data_83);
363         else
364           /* Otherwise, assume page 00 */
365           msc_send_result ((uint8_t *)&scsi_inquiry_data_00,
366                            sizeof scsi_inquiry_data_00);
367       }
368     else
369       msc_send_result ((uint8_t *)&scsi_inquiry_data,
370                        sizeof scsi_inquiry_data);
371     goto done;
372   case SCSI_READ_FORMAT_CAPACITIES:
373     buf[8]  = scsi_read_format_capacities (&nblocks, &secsize);
374     buf[0]  = buf[1] = buf[2] = 0;
375     buf[3]  = 8;
376     buf[4]  = (uint8_t)(nblocks >> 24);
377     buf[5]  = (uint8_t)(nblocks >> 16);
378     buf[6]  = (uint8_t)(nblocks >> 8);
379     buf[7]  = (uint8_t)(nblocks >> 0);
380     buf[9]  = (uint8_t)(secsize >> 16);
381     buf[10] = (uint8_t)(secsize >> 8);
382     buf[11] = (uint8_t)(secsize >> 0);
383     msc_send_result (buf, 12);
384     goto done;
385   case SCSI_START_STOP_UNIT:
386     if (CBW.CBWCB[4] == 0x00 /* stop */
387         || CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
388       {
389         msc_scsi_stop (CBW.CBWCB[4]);
390         set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */
391         contingent_allegiance = 1;
392         keep_contingent_allegiance = 1;
393       }
394     /* CBW.CBWCB[4] == 0x01 *//* start */
395     goto success;
396   case SCSI_TEST_UNIT_READY:
397     if (contingent_allegiance)
398       {
399         CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
400         CSW.dCSWDataResidue = 0;
401         msc_send_result (NULL, 0);
402         goto done;
403       }
404     /* fall through */
405   success:
406   case SCSI_SYNCHRONIZE_CACHE:
407   case SCSI_VERIFY10:
408   case SCSI_ALLOW_MEDIUM_REMOVAL:
409     CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
410     CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
411     msc_send_result (NULL, 0);
412     goto done;
413   case SCSI_MODE_SENSE6:
414     buf[0] = 0x03;
415     buf[1] = buf[2] = buf[3] = 0;
416     msc_send_result (buf, 4);
417     goto done;
418   case SCSI_READ_CAPACITY10:
419     scsi_read_format_capacities (&nblocks, &secsize);
420     buf[0]  = (uint8_t)((nblocks - 1) >> 24);
421     buf[1]  = (uint8_t)((nblocks - 1) >> 16);
422     buf[2]  = (uint8_t)((nblocks - 1) >> 8);
423     buf[3]  = (uint8_t)((nblocks - 1) >> 0);
424     buf[4]  = (uint8_t)(secsize >> 24);
425     buf[5]  = (uint8_t)(secsize >> 16);
426     buf[6] = (uint8_t)(secsize >> 8);
427     buf[7] = (uint8_t)(secsize >> 0);
428     msc_send_result (buf, 8);
429     goto done;
430   case SCSI_READ10:
431   case SCSI_WRITE10:
432     break;
433   default:
434     if (CBW.dCBWDataTransferLength == 0)
435       {
436         CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
437         CSW.dCSWDataResidue = 0;
438         msc_send_result (NULL, 0);
439         goto done;
440       }
441     else
442       {
443         msc_state = MSC_ERROR;
444         usb_lld_stall_tx (ENDP6);
445         usb_lld_stall_rx (ENDP6);
446         goto done;
447       }
448   }
449
450   lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16)
451       | (CBW.CBWCB[4] <<  8) | CBW.CBWCB[5];
452
453   /* Transfer direction.*/
454   if (CBW.bmCBWFlags & 0x80)
455     {
456       /* IN, Device to Host.*/
457       msc_state = MSC_DATA_IN;
458       if (CBW.CBWCB[0] == SCSI_READ10)
459         {
460           const uint8_t *p;
461
462           CSW.dCSWDataResidue = 0;
463           while (1)
464             {
465               if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0)
466                 {
467                   CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
468                   break;
469                 }
470
471               if ((r = msc_scsi_read (lba, &p)) == 0)
472                 {
473                   msc_send_data (p, 512);
474                   if (++CBW.CBWCB[5] == 0)
475                     if (++CBW.CBWCB[4] == 0)
476                       if (++CBW.CBWCB[3] == 0)
477                         ++CBW.CBWCB[2];
478                   if (CBW.CBWCB[8]-- == 0)
479                     CBW.CBWCB[7]--;
480                   CSW.dCSWDataResidue += 512;
481                   lba++;
482                 }
483               else
484                 {
485                   CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
486                   contingent_allegiance = 1;
487                   if (r == SCSI_ERROR_NOT_READY)
488                     set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
489                   else
490                     set_scsi_sense_data (r, 0x00);
491                   break;
492                 }
493             }
494
495           msc_send_result (NULL, 0);
496         }
497     }
498   else
499     {
500       /* OUT, Host to Device.*/
501       if (CBW.CBWCB[0] == SCSI_WRITE10)
502         {
503           CSW.dCSWDataResidue = CBW.dCBWDataTransferLength;
504
505           while (1)
506             {
507               if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0)
508                 {
509                   CSW.bCSWStatus = MSC_CSW_STATUS_PASSED;
510                   break;
511                 }
512
513               msc_recv_data ();
514               if (msg != RDY_OK)
515                 /* ignore erroneous packet, ang go next.  */
516                 continue;
517
518               if ((r = msc_scsi_write (lba, buf, 512)) == 0)
519                 {
520                   if (++CBW.CBWCB[5] == 0)
521                     if (++CBW.CBWCB[4] == 0)
522                       if (++CBW.CBWCB[3] == 0)
523                         ++CBW.CBWCB[2];
524                   if (CBW.CBWCB[8]-- == 0)
525                     CBW.CBWCB[7]--;
526                   CSW.dCSWDataResidue -= 512;
527                   lba++;
528                 }
529               else
530                 {
531                   CSW.bCSWStatus = MSC_CSW_STATUS_FAILED;
532                   contingent_allegiance = 1;
533                   if (r == SCSI_ERROR_NOT_READY)
534                     set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a);
535                   else
536                     set_scsi_sense_data (r, 0x00);
537                   break;
538                 }
539             }
540
541           msc_send_result (NULL, 0);
542         }
543     }
544
545  done:
546   chopstx_mutex_unlock (msc_mutex);
547 }
548
549
550 static void *
551 msc_main (void *arg)
552 {
553   (void)arg;
554
555   chopstx_mutex_init (msc_mutex);
556   chopstx_cond_init (msc_cond);
557
558   chopstx_mutex_init (pinpad_mutex);
559   chopstx_cond_init (pinpad_cond);
560
561   /* Initially, it starts with no media */
562   msc_media_insert_change (0);
563   while (1)
564     msc_handle_command ();
565
566   return NULL;
567 }
568
569
570 void
571 msc_init (void)
572 {
573   chopstx_create (PRIO_MSC, __stackaddr_msc, __stacksize_msc, msc_main, NULL);
574 }