1 /* Hey EMACS -*- linux-c -*- */
2 /* $Id: packets.c 1404 2005-07-20 20:39:39Z roms $ */
3 
4 /*  libticalcs - Ti Calculator library, a part of the TiLP project
5  *  Copyright (C) 1999-2005  Romain Liévin
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software Foundation,
19  *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /*
23 	This unit manages raw packets from/to D-USB (DirectLink).
24 */
25 
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "ticalcs.h"
30 #include "internal.h"
31 #include "dusb_rpkt.h"
32 #include "dusb_vpkt.h"
33 #include "logging.h"
34 #include "error.h"
35 
36 typedef struct
37 {
38 	uint8_t     id;
39 	uint8_t     data_hdr;
40 	uint8_t     data;
41 	const char* name;
42 } DUSBRawPacketInfo;
43 
44 static const DUSBRawPacketInfo dusbrawpackets[] =
45 {
46 	{ DUSB_RPKT_BUF_SIZE_REQ, 0, 4, "Buffer Size Request" },
47 	{ DUSB_RPKT_BUF_SIZE_ALLOC, 0, 4, "Buffer Size Allocation" },
48 	{ DUSB_RPKT_VIRT_DATA, 1, 6, "Virtual Packet Data with Continuation" },
49 	{ DUSB_RPKT_VIRT_DATA_LAST, 1, 6, "Virtual Packet Data Final" },
50 	{ DUSB_RPKT_VIRT_DATA_ACK, 0, 2, "Virtual Packet Data Acknowledgement" }
51 };
52 
dusb_rpkt_type2name(uint8_t id)53 TIEXPORT3 const char* TICALL dusb_rpkt_type2name(uint8_t id)
54 {
55 	unsigned int i;
56 
57 	for (i = 0; i < sizeof(dusbrawpackets) / sizeof(dusbrawpackets[0]); i++)
58 	{
59 		if (id == dusbrawpackets[i].id)
60 		{
61 			return dusbrawpackets[i].name;
62 		}
63 	}
64 
65 	return "";
66 }
67 
dusb_send(CalcHandle * handle,DUSBRawPacket * pkt)68 TIEXPORT3 int TICALL dusb_send(CalcHandle* handle, DUSBRawPacket* pkt)
69 {
70 	uint8_t buf[sizeof(pkt->data) + 5];
71 	uint32_t size;
72 	int ret;
73 
74 	VALIDATE_HANDLE(handle);
75 	VALIDATE_NONNULL(pkt);
76 
77 	memset(buf, 0, sizeof(buf));
78 	size = pkt->size;
79 
80 	if (size > sizeof(pkt->data))
81 	{
82 		size = sizeof(pkt->data);
83 	}
84 
85 	buf[0] = MSB(MSW(size));
86 	buf[1] = LSB(MSW(size));
87 	buf[2] = MSB(LSW(size));
88 	buf[3] = LSB(LSW(size));
89 	buf[4] = pkt->type;
90 	memcpy(buf + 5, pkt->data, size);
91 
92 	//printf("dusb_send: pkt->size=%d\n", pkt->size);
93 	ticables_progress_reset(handle->cable);
94 	ret = ticables_cable_send(handle->cable, buf, size + 5);
95 	if (!ret)
96 	{
97 		if (size >= 128)
98 		{
99 			ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
100 		}
101 
102 		if (handle->updat->cancel)
103 		{
104 			ret = ERR_ABORT;
105 		}
106 	}
107 
108 	return ret;
109 }
110 
dusb_recv(CalcHandle * handle,DUSBRawPacket * pkt)111 TIEXPORT3 int TICALL dusb_recv(CalcHandle* handle, DUSBRawPacket* pkt)
112 {
113 	uint8_t buf[5];
114 	int ret;
115 
116 	VALIDATE_HANDLE(handle);
117 	VALIDATE_NONNULL(pkt);
118 
119 	// Any packet has always an header of 5 bytes (size & type)
120 	ticables_progress_reset(handle->cable);
121 	ret = ticables_cable_recv(handle->cable, buf, 5);
122 	while (!ret)
123 	{
124 
125 		pkt->size = buf[3] | (((uint32_t)buf[2]) << 8) | (((uint32_t)buf[1]) << 16) | (((uint32_t)buf[0]) << 24);
126 		pkt->type = buf[4];
127 
128 		if (   (handle->model == CALC_TI84P_USB || handle->model == CALC_TI84PC_USB || handle->model == CALC_TI82A_USB || handle->model == CALC_TI84PT_USB)
129 		    && pkt->size > 250)
130 		{
131 			ticalcs_warning("Raw packet is unexpectedly large: %u bytes", pkt->size);
132 		}
133 		else if (   (handle->model == CALC_TI83PCE_USB || handle->model == CALC_TI84PCE_USB)
134 		         && pkt->size > 1018)
135 		{
136 			ticalcs_warning("Raw packet is unexpectedly large: %u bytes", pkt->size);
137 		}
138 		else if (handle->model == CALC_TI89T_USB)
139 		{
140 			// Fall through.
141 		}
142 		// else do nothing for now.
143 
144 		if (pkt->size > sizeof(pkt->data))
145 		{
146 			ticalcs_critical("Raw packet is too large: %u bytes", pkt->size);
147 			ret = ERR_INVALID_PACKET;
148 			break;
149 		}
150 
151 		//printf("dusb_send: pkt->size=%d\n", pkt->size);
152 		// Next, follows data
153 		ret = ticables_cable_recv(handle->cable, pkt->data, pkt->size);
154 		if (!ret)
155 		{
156 			if (pkt->size >= 128)
157 			{
158 				ticables_progress_get(handle->cable, NULL, NULL, &handle->updat->rate);
159 			}
160 
161 			if (handle->updat->cancel)
162 			{
163 				ret = ERR_ABORT;
164 			}
165 		}
166 		break;
167 	}
168 
169 	return ret;
170 }
171 
ep_way(uint8_t ep)172 static const char* ep_way(uint8_t ep)
173 {
174 	if (ep == 0x01)
175 	{
176 		return "TI>PC";
177 	}
178 	else if (ep == 0x02)
179 	{
180 		return "PC>TI";
181 	}
182 	else
183 	{
184 		return "XX>XX";
185 	}
186 }
187 
dusb_dissect(CalcModel model,FILE * f,const uint8_t * data,uint32_t len,uint8_t ep,uint8_t * first)188 TIEXPORT3 int TICALL dusb_dissect(CalcModel model, FILE * f, const uint8_t * data, uint32_t len, uint8_t ep, uint8_t * first)
189 {
190 	int ret = 0;
191 	uint32_t raw_size;
192 	uint8_t raw_type;
193 
194 	VALIDATE_NONNULL(f);
195 	VALIDATE_NONNULL(data);
196 	VALIDATE_NONNULL(first);
197 
198 	if (len < 5 || len > sizeof(((DUSBRawPacket *)0)->data))
199 	{
200 		ticalcs_critical("Length %lu (%lX) is too small or too large for a valid DUSB raw packet", (unsigned long)len, (unsigned long)len);
201 		return ERR_INVALID_PACKET;
202 	}
203 
204 	raw_size = (((uint32_t)(data[0])) << 24) | (((uint32_t)(data[1])) << 16) | (((uint32_t)(data[2])) << 8) | ((uint32_t)(data[3]));
205 	raw_type = data[4];
206 
207 	fprintf(f, "%08lX (%02X)\t\t\t\t\t\t\t| %s: %s\n", (unsigned long)raw_size, (unsigned int)raw_type, ep_way(ep), dusb_rpkt_type2name(raw_type));
208 
209 	if (raw_size > sizeof(((DUSBRawPacket *)0)->data) - 5)
210 	{
211 		ticalcs_critical("Raw size %lu (%lX) is too large for a valid DUSB raw packet", (unsigned long)raw_size, (unsigned long)raw_size);
212 		return ERR_INVALID_PACKET;
213 	}
214 
215 	if (raw_type < 1 || raw_type > 5)
216 	{
217 		ticalcs_critical("Raw type unknown in DUSB raw packet");
218 		return ERR_INVALID_PACKET;
219 	}
220 
221 	if (len < 5U + dusbrawpackets[raw_type - 1].data)
222 	{
223 		ticalcs_critical("Length %ld is too small for a valid data part in DUSB raw packet of type %u", (unsigned long)len, raw_type);
224 		return ERR_INVALID_PACKET;
225 	}
226 
227 	switch (raw_type)
228 	{
229 		case DUSB_RPKT_BUF_SIZE_REQ:
230 		case DUSB_RPKT_BUF_SIZE_ALLOC:
231 		{
232 			uint32_t tmp = (((uint32_t)(data[5])) << 24) | (((uint32_t)(data[6])) << 16) | (((uint32_t)(data[7])) << 8) | ((uint32_t)(data[8]));
233 			fprintf(f, "\t[%08lX]\n", (unsigned long)tmp);
234 			if (len != 5U + 4)
235 			{
236 				fputs("(unexpected size for a packet of that type)\n", f);
237 			}
238 		}
239 		break;
240 
241 		case DUSB_RPKT_VIRT_DATA:
242 		case DUSB_RPKT_VIRT_DATA_LAST:
243 		{
244 			if (*first)
245 			{
246 				uint32_t vtl_size = (((uint32_t)(data[5])) << 24) | (((uint32_t)(data[6])) << 16) | (((uint32_t)(data[7])) << 8) | ((uint32_t)(data[8]));
247 				uint16_t vtl_type = (((uint16_t)(data[9])) << 8) | ((uint16_t)(data[10]));
248 				fprintf(f, "\t%08lX {%04X}\t\t\t\t\t\t| CMD: %s\n", (unsigned long)vtl_size, vtl_type, dusb_vpkt_type2name(vtl_type));
249 
250 				if (vtl_size != raw_size - 6)
251 				{
252 					fputs("(unexpected size for a packet of that type)\n", f);
253 				}
254 
255 				if (!vtl_size)
256 				{
257 					fputs("(no data to dissect)\n", f);
258 				}
259 				else
260 				{
261 					uint32_t i;
262 					data += 11;
263 					len -= 11;
264 					if (len < vtl_size)
265 					{
266 						fputs("(packet truncated: insufficient given length)\n", f);
267 					}
268 					else if (len > vtl_size)
269 					{
270 						fputs("(given length larger than length in packet)\n", f);
271 					}
272 					fprintf(f, "\t\t");
273 					for (i = 0; i < len;)
274 					{
275 						fprintf(f, "%02X ", *data++);
276 						if (!(++i & 15))
277 						{
278 							fprintf(f, "\n\t\t");
279 						}
280 					}
281 					data -= vtl_size;
282 					fputc('\n', f);
283 					ret = dusb_dissect_cmd_data(model, f, data, len, vtl_size, vtl_type);
284 					if (ret)
285 					{
286 						fputs("(inner data dissection had a problem with the packet)\n", f);
287 					}
288 				}
289 			}
290 			else
291 			{
292 				uint32_t i;
293 				fprintf(f, "\t%02X %02X %02X ", data[5], data[6], data[7]);
294 				data += 8;
295 				len -= 8;
296 				if (len < raw_size - 3)
297 				{
298 					fputs("(packet truncated: insufficient given length)\n", f);
299 					raw_size = len;
300 				}
301 				else if (len > raw_size - 3)
302 				{
303 					fputs("(given length larger than length in packet)\n", f);
304 				}
305 				for (i = 0; i < len;)
306 				{
307 					fprintf(f, "%02X ", *data++);
308 					if (!(++i & 15))
309 					{
310 						fprintf(f, "\n\t\t");
311 					}
312 				}
313 				fputc('\n', f);
314 			}
315 			*first = (raw_type == DUSB_RPKT_VIRT_DATA) ? 0 : 1;
316 		}
317 		break;
318 
319 
320 		case DUSB_RPKT_VIRT_DATA_ACK:
321 		{
322 			uint16_t tmp = (((uint16_t)(data[5])) << 8) | ((uint16_t)(data[6]));
323 			fprintf(f, "\t[%04X]\n", tmp);
324 			if (len != 5 + 2)
325 			{
326 				fputs("(unexpected size for a packet of that type)\n", f);
327 			}
328 		}
329 		break;
330 	}
331 
332 	return ret;
333 }
334