translate 0x0a to 0x0d 0x0a in SOL
[amt] / redir.c
1 /*
2 * Intel AMT tcp redirection protocol helper functions.
3 *
4 * Copyright (C) 2007 Gerd Hoffmann <kraxel@redhat.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27
28 #include "tcp.h"
29 #include "redir.h"
30
31 static const char *state_name[] = {
32 [ REDIR_NONE ] = "NONE",
33 [ REDIR_CONNECT ] = "CONNECT",
34 [ REDIR_INIT ] = "INIT",
35 [ REDIR_AUTH ] = "AUTH",
36 [ REDIR_INIT_SOL ] = "INIT_SOL",
37 [ REDIR_RUN_SOL ] = "RUN_SOL",
38 [ REDIR_INIT_IDER ] = "INIT_IDER",
39 [ REDIR_RUN_IDER ] = "RUN_IDER",
40 [ REDIR_CLOSING ] = "CLOSING",
41 [ REDIR_CLOSED ] = "CLOSED",
42 [ REDIR_ERROR ] = "ERROR",
43 };
44
45 static const char *state_desc[] = {
46 [ REDIR_NONE ] = "disconnected",
47 [ REDIR_CONNECT ] = "connection to host",
48 [ REDIR_INIT ] = "redirection initialization",
49 [ REDIR_AUTH ] = "session authentication",
50 [ REDIR_INIT_SOL ] = "serial-over-lan initialization",
51 [ REDIR_RUN_SOL ] = "serial-over-lan active",
52 [ REDIR_INIT_IDER ] = "IDE redirect initialization",
53 [ REDIR_RUN_IDER ] = "IDE redirect active",
54 [ REDIR_CLOSING ] = "redirection shutdown",
55 [ REDIR_CLOSED ] = "connection closed",
56 [ REDIR_ERROR ] = "failure",
57 };
58
59 /* ------------------------------------------------------------------ */
60
61 static void hexdump(const char *prefix, const unsigned char *data, size_t size)
62 {
63 char ascii[17];
64 int i;
65
66 for (i = 0; i < size; i++) {
67 if (0 == (i%16)) {
68 fprintf(stderr,"%s%s%04x:",
69 prefix ? prefix : "",
70 prefix ? ": " : "",
71 i);
72 memset(ascii,0,sizeof(ascii));
73 }
74 if (0 == (i%4))
75 fprintf(stderr," ");
76 fprintf(stderr," %02x",data[i]);
77 ascii[i%16] = isprint(data[i]) ? data[i] : '.';
78 if (15 == (i%16))
79 fprintf(stderr," %s\n",ascii);
80 }
81 if (0 != (i%16)) {
82 while (0 != (i%16)) {
83 if (0 == (i%4))
84 fprintf(stderr," ");
85 fprintf(stderr," ");
86 i++;
87 };
88 fprintf(stderr," %s\n",ascii);
89 }
90 }
91
92 static ssize_t redir_write(struct redir *r, const char *buf, size_t count)
93 {
94 int rc;
95
96 if (r->trace)
97 hexdump("out", buf, count);
98 rc = write(r->sock, buf, count);
99 if (-1 == rc)
100 snprintf(r->err, sizeof(r->err), "write(socket): %s", strerror(errno));
101 return rc;
102 }
103
104 static void redir_state(struct redir *r, enum redir_state new)
105 {
106 enum redir_state old = r->state;
107
108 r->state = new;
109 if (r->cb_state)
110 r->cb_state(r->cb_data, old, new);
111 }
112
113 /* ------------------------------------------------------------------ */
114
115 const char *redir_state_name(enum redir_state state)
116 {
117 const char *name = NULL;
118
119 if (state < sizeof(state_name)/sizeof(state_name[0]))
120 name = state_name[state];
121 if (NULL == name)
122 name = "unknown";
123 return name;
124 }
125
126 const char *redir_state_desc(enum redir_state state)
127 {
128 const char *desc = NULL;
129
130 if (state < sizeof(state_desc)/sizeof(state_desc[0]))
131 desc = state_desc[state];
132 if (NULL == desc)
133 desc = "unknown";
134 return desc;
135 }
136
137 int redir_connect(struct redir *r)
138 {
139 static unsigned char *defport = "16994";
140 struct addrinfo ai;
141
142 memset(&ai, 0, sizeof(ai));
143 ai.ai_socktype = SOCK_STREAM;
144 ai.ai_family = PF_UNSPEC;
145 tcp_verbose = r->verbose;
146 redir_state(r, REDIR_CONNECT);
147 r->sock = tcp_connect(&ai, NULL, NULL, r->host,
148 strlen(r->port) ? r->port : defport);
149 if (-1 == r->sock) {
150 redir_state(r, REDIR_ERROR);
151 return -1;
152 }
153 return 0;
154 }
155
156 int redir_start(struct redir *r)
157 {
158 unsigned char request[START_REDIRECTION_SESSION_LENGTH] = {
159 START_REDIRECTION_SESSION, 0, 0, 0, 0, 0, 0, 0
160 };
161
162 memcpy(request+4, r->type, 4);
163 redir_state(r, REDIR_INIT);
164 return redir_write(r, request, sizeof(request));
165 }
166
167 int redir_stop(struct redir *r)
168 {
169 unsigned char request[END_REDIRECTION_SESSION_LENGTH] = {
170 END_REDIRECTION_SESSION, 0, 0, 0
171 };
172
173 redir_state(r, REDIR_CLOSED);
174 redir_write(r, request, sizeof(request));
175 close(r->sock);
176 return 0;
177 }
178
179 int redir_auth(struct redir *r)
180 {
181 int ulen = strlen(r->user);
182 int plen = strlen(r->pass);
183 int len = 11+ulen+plen;
184 int rc;
185 unsigned char *request = malloc(len);
186
187 memset(request, 0, len);
188 request[0] = AUTHENTICATE_SESSION;
189 request[4] = 0x01;
190 request[5] = ulen+plen+2;
191 request[9] = ulen;
192 memcpy(request + 10, r->user, ulen);
193 request[10 + ulen] = plen;
194 memcpy(request + 11 + ulen, r->pass, plen);
195 redir_state(r, REDIR_AUTH);
196 rc = redir_write(r, request, len);
197 free(request);
198 return rc;
199 }
200
201 int redir_sol_start(struct redir *r)
202 {
203 unsigned char request[START_SOL_REDIRECTION_LENGTH] = {
204 START_SOL_REDIRECTION, 0, 0, 0,
205 0, 0, 0, 0,
206 MAX_TRANSMIT_BUFFER & 0xff,
207 MAX_TRANSMIT_BUFFER >> 8,
208 TRANSMIT_BUFFER_TIMEOUT & 0xff,
209 TRANSMIT_BUFFER_TIMEOUT >> 8,
210 TRANSMIT_OVERFLOW_TIMEOUT & 0xff, TRANSMIT_OVERFLOW_TIMEOUT >> 8,
211 HOST_SESSION_RX_TIMEOUT & 0xff,
212 HOST_SESSION_RX_TIMEOUT >> 8,
213 HOST_FIFO_RX_FLUSH_TIMEOUT & 0xff,
214 HOST_FIFO_RX_FLUSH_TIMEOUT >> 8,
215 HEARTBEAT_INTERVAL & 0xff,
216 HEARTBEAT_INTERVAL >> 8,
217 0, 0, 0, 0
218 };
219
220 redir_state(r, REDIR_INIT_SOL);
221 return redir_write(r, request, sizeof(request));
222 }
223
224 int redir_sol_stop(struct redir *r)
225 {
226 unsigned char request[END_SOL_REDIRECTION_LENGTH] = {
227 END_SOL_REDIRECTION, 0, 0, 0,
228 0, 0, 0, 0,
229 };
230
231 redir_state(r, REDIR_CLOSING);
232 return redir_write(r, request, sizeof(request));
233 }
234
235 int redir_sol_send(struct redir *r, unsigned char *buf, int blen)
236 {
237 int len = 10+blen;
238 int rc;
239 int i,j;
240 unsigned char *request;
241
242 for (i = 0; i < blen; i++) {
243 if (buf[i] == 0x0a)
244 len++;
245 }
246
247 request = malloc(len);
248
249 memset(request, 0, len);
250 request[0] = SOL_DATA_TO_HOST;
251 request[8] = (len-10) & 0xff;
252 request[9] = (len-10) >> 8;
253 for (i=0, j=0; i < blen; i++,j++) {
254 if (buf[i] == 0x0a) {
255 request[j + 10] = 0x0d;
256 j++;
257 }
258 request[j + 10] = buf[i];
259 }
260 rc = redir_write(r, request, len);
261 free(request);
262 return rc;
263 }
264
265 int redir_sol_recv(struct redir *r)
266 {
267 unsigned char msg[64];
268 int count, len, bshift;
269
270 len = r->buf[8] + (r->buf[9] << 8);
271 count = r->blen - 10;
272 if (count > len)
273 count = len;
274 bshift = count + 10;
275 if (r->cb_recv)
276 r->cb_recv(r->cb_data, r->buf + 10, count);
277 len -= count;
278
279 while (len) {
280 if (r->trace)
281 fprintf(stderr, "in+: need %d more data bytes\n", len);
282 count = sizeof(msg);
283 if (count > len)
284 count = len;
285 count = read(r->sock, msg, count);
286 switch (count) {
287 case -1:
288 snprintf(r->err, sizeof(r->err), "read(socket): %s", strerror(errno));
289 return -1;
290 case 0:
291 snprintf(r->err, sizeof(r->err), "EOF from socket");
292 return -1;
293 default:
294 if (r->trace)
295 hexdump("in+", msg, count);
296 if (r->cb_recv)
297 r->cb_recv(r->cb_data, msg, count);
298 len -= count;
299 }
300 }
301
302 return bshift;
303 }
304
305 int redir_data(struct redir *r)
306 {
307 int rc, bshift;
308
309 if (r->trace) {
310 fprintf(stderr, "in --\n");
311 if (r->blen)
312 fprintf(stderr, "in : already have %d\n", r->blen);
313 }
314 rc = read(r->sock, r->buf + r->blen, sizeof(r->buf) - r->blen);
315 switch (rc) {
316 case -1:
317 snprintf(r->err, sizeof(r->err), "read(socket): %s", strerror(errno));
318 goto err;
319 case 0:
320 snprintf(r->err, sizeof(r->err), "EOF from socket");
321 goto err;
322 default:
323 if (r->trace)
324 hexdump("in ", r->buf + r->blen, rc);
325 r->blen += rc;
326 }
327
328 for (;;) {
329 if (r->blen < 4)
330 goto again;
331 bshift = 0;
332
333 switch (r->buf[0]) {
334 case START_REDIRECTION_SESSION_REPLY:
335 bshift = START_REDIRECTION_SESSION_REPLY_LENGTH;
336 if (r->blen < bshift)
337 goto again;
338 if (r->buf[1] != STATUS_SUCCESS) {
339 snprintf(r->err, sizeof(r->err), "redirection session start failed");
340 goto err;
341 }
342 if (-1 == redir_auth(r))
343 goto err;
344 break;
345 case AUTHENTICATE_SESSION_REPLY:
346 bshift = r->blen; /* FIXME */
347 if (r->blen < bshift)
348 goto again;
349 if (r->buf[1] != STATUS_SUCCESS) {
350 snprintf(r->err, sizeof(r->err), "session authentication failed");
351 goto err;
352 }
353 if (-1 == redir_sol_start(r))
354 goto err;
355 break;
356 case START_SOL_REDIRECTION_REPLY:
357 bshift = r->blen; /* FIXME */
358 if (r->blen < bshift)
359 goto again;
360 if (r->buf[1] != STATUS_SUCCESS) {
361 snprintf(r->err, sizeof(r->err), "serial-over-lan redirection failed");
362 goto err;
363 }
364 redir_state(r, REDIR_RUN_SOL);
365 break;
366 case SOL_HEARTBEAT:
367 case SOL_KEEP_ALIVE_PING:
368 case IDER_HEARTBEAT:
369 case IDER_KEEP_ALIVE_PING:
370 bshift = HEARTBEAT_LENGTH;
371 if (r->blen < bshift)
372 goto again;
373 if (HEARTBEAT_LENGTH != redir_write(r, r->buf, HEARTBEAT_LENGTH))
374 goto err;
375 break;
376 case SOL_DATA_FROM_HOST:
377 if (r->blen < 10) /* header length */
378 goto again;
379 bshift = redir_sol_recv(r);
380 if (bshift < 0)
381 goto err;
382 break;
383 case END_SOL_REDIRECTION_REPLY:
384 bshift = r->blen; /* FIXME */
385 if (r->blen < bshift)
386 goto again;
387 redir_stop(r);
388 break;
389 default:
390 snprintf(r->err, sizeof(r->err), "%s: unknown r->buf 0x%02x",
391 __FUNCTION__, r->buf[0]);
392 goto err;
393 }
394
395 if (bshift == r->blen) {
396 r->blen = 0;
397 break;
398 }
399
400 /* have more data, shift by bshift */
401 if (r->trace)
402 fprintf(stderr, "in : shift by %d\n", bshift);
403 memmove(r->buf, r->buf + bshift, r->blen - bshift);
404 r->blen -= bshift;
405 }
406 return 0;
407
408 again:
409 /* need more data, jump back into poll/select loop */
410 if (r->trace)
411 fprintf(stderr, "in : need more data\n");
412 return 0;
413
414 err:
415 if (r->trace)
416 fprintf(stderr, "in : ERROR (%s)\n", r->err);
417 redir_state(r, REDIR_ERROR);
418 close(r->sock);
419 return -1;
420 }
Impressum, Datenschutz