Project

General

Profile

Download (4.06 KB) Statistics
| Branch: | Tag: | Revision:
1
/* simtrace - main program for the host PC
2
 *
3
 * (C) 2010 by Harald Welte <hwelte@hmw-consulting.de>
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License version 2 
7
 *  as published by the Free Software Foundation
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program; if not, write to the Free Software
16
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 */
18

    
19
#include <errno.h>
20
#include <unistd.h>
21
#include <stdio.h>
22
#include <string.h>
23
#include <stdlib.h>
24
#include <stdint.h>
25
#include <time.h>
26
#include <assert.h>
27
#include <sys/time.h>
28
#include <sys/types.h>
29

    
30
#include "apdu_split.h"
31

    
32
enum iso7816_apdu_state {
33
	APDU_S_CLA,
34
	APDU_S_INS,
35
	APDU_S_P1,
36
	APDU_S_P2,
37
	APDU_S_P3,
38
	APDU_S_DATA,
39
	APDU_S_DATA_SINGLE,
40
	APDU_S_SW1,
41
	APDU_S_SW2,
42
};
43

    
44
const char *state_names[] = {
45
	[APDU_S_CLA]	= "CLA",
46
	[APDU_S_INS]	= "INS",
47
	[APDU_S_P1]	= "P1",
48
	[APDU_S_P2]	= "P2",
49
	[APDU_S_P3]	= "P3",
50
	[APDU_S_DATA]	= "DATA",
51
	[APDU_S_SW1]	= "SW1",
52
	[APDU_S_SW2]	= "SW2",
53
};
54

    
55
struct apdu_split {
56
	apdu_cb_t *apdu_out_cb;
57
	void *user_data;
58

    
59
	enum iso7816_apdu_state state;
60
	uint8_t apdu_ins;
61
	unsigned int apdu_len;
62
	unsigned int apdu_data_remaining;
63
	uint8_t apdu_buf[(2<<16)];
64
};
65

    
66
/* wrapper function to catch apdu_buf overflows */
67
static void apdu_buf_append(struct apdu_split *as, uint8_t ch)
68
{
69
	assert(as->apdu_len < sizeof(as->apdu_buf));
70
	as->apdu_buf[as->apdu_len++] = ch;
71
}
72

    
73
static void set_state(struct apdu_split *as, enum iso7816_apdu_state new_state)
74
{
75
	switch (new_state) {
76
	case APDU_S_CLA:
77
		as->apdu_len = 0;
78
		memset(as->apdu_buf, 0, sizeof(as->apdu_buf));
79
		break;
80
	}
81

    
82
	if (as->state == new_state)
83
		return;
84

    
85
	//printf("APDU split state %s -> %s\n", state_names[as->state], state_names[new_state]);
86

    
87
	as->state = new_state;
88
}
89

    
90
static void apdu_split_inbyte(struct apdu_split *as, uint8_t ch)
91
{
92
	switch (as->state) {
93
	case APDU_S_INS:
94
		as->apdu_ins = ch;
95
	case APDU_S_CLA:
96
	case APDU_S_P1:
97
	case APDU_S_P2:
98
		apdu_buf_append(as, ch);
99
		set_state(as, as->state+1);
100
		break;
101
	case APDU_S_P3:
102
		apdu_buf_append(as, ch);
103
		as->apdu_data_remaining = (ch == 0 ? 256 : ch);
104
		set_state(as, APDU_S_SW1);
105
		break;
106
	case APDU_S_DATA:
107
		apdu_buf_append(as, ch);
108
		as->apdu_data_remaining--;
109
		if (as->apdu_data_remaining == 0)
110
			set_state(as, APDU_S_SW1);
111
		break;
112
	case APDU_S_DATA_SINGLE:
113
		apdu_buf_append(as, ch);
114
		as->apdu_data_remaining--;
115
		set_state(as, APDU_S_SW1);
116
		break;
117
	case APDU_S_SW1:
118
		/* check for NULL / waiting time extension */
119
		if (ch == 0x60) {
120
			//printf("NULL");
121
		} else
122
		/* check for 'all remaining' type ACK */
123
		if (ch == as->apdu_ins || ch == as->apdu_ins + 1 ||
124
		    ch == ~(as->apdu_ins+1))  {
125
			//printf("ACK");
126
			set_state(as, APDU_S_DATA);
127
		} else
128
		/* check for 'only next byte' type ACK */
129
		if (ch == ~(as->apdu_ins)) {
130
			set_state(as, APDU_S_DATA_SINGLE);
131
		} else {
132
			/* must be SW1 */
133
			apdu_buf_append(as, ch);
134
			set_state(as, APDU_S_SW2);
135
		}
136
		break;
137
	case APDU_S_SW2:
138
		apdu_buf_append(as, ch);
139
		//printf("APDU: %s\n", osmo_hexdump(as->apdu_buf, as->apdu_len));
140
		as->apdu_out_cb(as->apdu_buf, as->apdu_len, as->user_data);
141
		set_state(as, APDU_S_CLA);
142
		break;
143
	}
144
		
145
}
146

    
147
/* public API */
148

    
149
struct apdu_split *apdu_split_init(apdu_cb_t *apdu_out_cb, void *user_data)
150
{
151
	struct apdu_split *as;
152

    
153
	as = malloc(sizeof(*as));
154
	if (!as)
155
		return NULL;
156

    
157
	memset(as, 0, sizeof(*as));
158
	as->apdu_out_cb = apdu_out_cb;
159
	as->user_data = user_data;
160

    
161
	return as;
162
}
163

    
164
int apdu_split_reset(struct apdu_split *as)
165
{
166
	set_state(as, APDU_S_CLA);
167
}
168

    
169
void apdu_split_boundary(struct apdu_split *as)
170
{
171
	printf("BOUNDARY\n");
172
	as->apdu_out_cb(as->apdu_buf, as->apdu_len, as->user_data);
173
	set_state(as, APDU_S_CLA);
174
}
175

    
176
void apdu_split_in(struct apdu_split *as, uint8_t *buf, int len)
177
{
178
	while (len--)
179
		apdu_split_inbyte(as, *buf++);
180
}
(2-2/7)
Add picture from clipboard (Maximum size: 48.8 MB)