1/*
2 *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 *  @APPLE_LICENSE_HEADER_START@
5 *
6 *  This file contains Original Code and/or Modifications of Original Code
7 *  as defined in and that are subject to the Apple Public Source License
8 *  Version 2.0 (the 'License'). You may not use this file except in
9 *  compliance with the License. Please obtain a copy of the License at
10 *  http://www.opensource.apple.com/apsl/ and read it before using this
11 *  file.
12 *
13 *  The Original Code and all software distributed under the License are
14 *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 *  Please see the License for the specific language governing rights and
19 *  limitations under the License.
20 *
21 *  @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 *  prothandler.c
26 *  SmartCardServices
27 */
28
29/*
30 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
31 *
32 * Copyright (C) 1999
33 *  David Corcoran <corcoran@linuxnet.com>
34 * Copyright (C) 2004
35 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
36 *
37 * $Id: prothandler.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
38 */
39
40/**
41 * @file
42 * @brief This handles protocol defaults, PTS, etc.
43 */
44
45#include "config.h"
46#include <string.h>
47
48#include "wintypes.h"
49#include "pcsclite.h"
50#include "ifdhandler.h"
51#include "debuglog.h"
52#include "readerfactory.h"
53#include "prothandler.h"
54#include "atrhandler.h"
55#include "ifdwrapper.h"
56#include "eventhandler.h"
57
58/*
59 * Function: PHGetDefaultProtocol Purpose : To get the default protocol
60 * used immediately after reset. This protocol is returned from the
61 * function.
62 */
63
64UCHAR PHGetDefaultProtocol(const unsigned char *pucAtr, DWORD dwLength)
65{
66	SMARTCARD_EXTENSION sSmartCard;
67
68	/*
69	 * Zero out everything
70	 */
71	memset(&sSmartCard, 0x00, sizeof(SMARTCARD_EXTENSION));
72
73	if (ATRDecodeAtr(&sSmartCard, pucAtr, dwLength))
74		return sSmartCard.CardCapabilities.CurrentProtocol;
75	else
76		return 0x00;
77}
78
79/*
80 * Function: PHGetAvailableProtocols Purpose : To get the protocols
81 * supported by the card. These protocols are returned from the function
82 * as bit masks.
83 */
84
85UCHAR PHGetAvailableProtocols(const unsigned char *pucAtr, DWORD dwLength)
86{
87	SMARTCARD_EXTENSION sSmartCard;
88
89	/*
90	 * Zero out everything
91	 */
92	memset(&sSmartCard, 0x00, sizeof(SMARTCARD_EXTENSION));
93
94	if (ATRDecodeAtr(&sSmartCard, pucAtr, dwLength))
95		return sSmartCard.CardCapabilities.AvailableProtocols;
96	else
97		return 0x00;
98}
99
100/*
101 * Function: PHSetProtocol Purpose : To determine which protocol to use.
102 * SCardConnect has a DWORD dwPreferredProtocols that is a bitmask of what
103 * protocols to use.  Basically, if T=N where N is not zero will be used
104 * first if it is available in ucAvailable.  Otherwise it will always
105 * default to T=0.
106 *
107 * IFDSetPTS() is _always_ called so that the driver can initialise its data
108 */
109
110DWORD PHSetProtocol(struct ReaderContext * rContext,
111	DWORD dwPreferred, UCHAR ucAvailable, UCHAR ucDefault)
112{
113	DWORD protocol;
114	LONG rv;
115	UCHAR ucChosen;
116
117	/* App has specified no protocol */
118	if (dwPreferred == 0)
119		return SET_PROTOCOL_WRONG_ARGUMENT;
120
121	/* requested protocol is not available */
122	if (! (dwPreferred & ucAvailable))
123	{
124		/* Note:
125		 * dwPreferred must be either SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
126		 * if dwPreferred == SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 the test
127		 * (SCARD_PROTOCOL_T0 == dwPreferred) will not work as expected
128		 * and the debug message will not be correct.
129		 *
130		 * This case may only occur if
131		 * dwPreferred == SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1
132		 * and ucAvailable == 0 since we have (dwPreferred & ucAvailable) == 0
133		 * and the case ucAvailable == 0 should never occur (the card is at
134		 * least T=0 or T=1)
135		 */
136		Log2(PCSC_LOG_ERROR, "Protocol T=%d requested but unsupported by the card",
137			(SCARD_PROTOCOL_T0 == dwPreferred) ? 0 : 1);
138		return SET_PROTOCOL_WRONG_ARGUMENT;
139	}
140
141	/* set default value */
142	protocol = ucDefault;
143
144	/* keep only the available protocols */
145	dwPreferred &= ucAvailable;
146
147	/* we try to use T=1 first */
148	if (dwPreferred & SCARD_PROTOCOL_T1)
149		ucChosen = SCARD_PROTOCOL_T1;
150	else
151		if (dwPreferred & SCARD_PROTOCOL_T0)
152			ucChosen = SCARD_PROTOCOL_T0;
153		else
154			/* App wants unsupported protocol */
155			return SET_PROTOCOL_WRONG_ARGUMENT;
156
157	Log2(PCSC_LOG_INFO, "Attempting PTS to T=%d",
158		(SCARD_PROTOCOL_T0 == ucChosen ? 0 : 1));
159	rv = IFDSetPTS(rContext, ucChosen, 0x00, 0x00, 0x00, 0x00);
160
161	if (IFD_SUCCESS == rv)
162		protocol = ucChosen;
163	else
164		if (IFD_NOT_SUPPORTED == rv)
165			Log2(PCSC_LOG_INFO, "PTS not supported by driver, using T=%d",
166				(SCARD_PROTOCOL_T0 == protocol) ? 0 : 1);
167		else
168			if (IFD_PROTOCOL_NOT_SUPPORTED == rv)
169				Log2(PCSC_LOG_INFO, "PTS protocol not supported, using T=%d",
170					(SCARD_PROTOCOL_T0 == protocol) ? 0 : 1);
171			else
172			{
173				Log3(PCSC_LOG_INFO, "PTS failed (%d), using T=%d", rv,
174					(SCARD_PROTOCOL_T0 == protocol) ? 0 : 1);
175
176				/* ISO 7816-3:1997 ch. 7.2 PPS protocol page 14
177				 * - If the PPS exchange is unsuccessful, then the interface device
178				 *   shall either reset or reject the card.
179				 */
180				return SET_PROTOCOL_PPS_FAILED;
181			}
182
183	return protocol;
184}
185
186