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