revert enter expansion and simply replace 0x0a with 0x0d
[amt] / redir.c
CommitLineData
402f63cd
MG
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
31static 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
45static 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
61static 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
92static 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
104static 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
115const 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
126const 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
137int 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
156int 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
167int 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
179int 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
201int 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
224int 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
235int redir_sol_send(struct redir *r, unsigned char *buf, int blen)
236{
237 int len = 10+blen;
238 int rc;
0ddcc0c9 239 int i;
bdb412f7
MG
240 unsigned char *request;
241
242 for (i = 0; i < blen; i++) {
243 if (buf[i] == 0x0a)
0ddcc0c9 244 buf[i] = 0x0d;
bdb412f7
MG
245 }
246
247 request = malloc(len);
0ddcc0c9
MG
248 if (!request) {
249 return -1;
250 }
402f63cd
MG
251
252 memset(request, 0, len);
253 request[0] = SOL_DATA_TO_HOST;
0ddcc0c9
MG
254 request[8] = blen & 0xff;
255 request[9] = blen >> 8;
256 memcpy(request + 10, buf, blen);
402f63cd
MG
257 rc = redir_write(r, request, len);
258 free(request);
259 return rc;
260}
261
262int redir_sol_recv(struct redir *r)
263{
264 unsigned char msg[64];
265 int count, len, bshift;
266
267 len = r->buf[8] + (r->buf[9] << 8);
268 count = r->blen - 10;
269 if (count > len)
270 count = len;
271 bshift = count + 10;
272 if (r->cb_recv)
273 r->cb_recv(r->cb_data, r->buf + 10, count);
274 len -= count;
275
276 while (len) {
277 if (r->trace)
278 fprintf(stderr, "in+: need %d more data bytes\n", len);
279 count = sizeof(msg);
280 if (count > len)
281 count = len;
282 count = read(r->sock, msg, count);
283 switch (count) {
284 case -1:
285 snprintf(r->err, sizeof(r->err), "read(socket): %s", strerror(errno));
286 return -1;
287 case 0:
288 snprintf(r->err, sizeof(r->err), "EOF from socket");
289 return -1;
290 default:
291 if (r->trace)
292 hexdump("in+", msg, count);
293 if (r->cb_recv)
294 r->cb_recv(r->cb_data, msg, count);
295 len -= count;
296 }
297 }
298
299 return bshift;
300}
301
302int redir_data(struct redir *r)
303{
304 int rc, bshift;
305
306 if (r->trace) {
307 fprintf(stderr, "in --\n");
308 if (r->blen)
309 fprintf(stderr, "in : already have %d\n", r->blen);
310 }
311 rc = read(r->sock, r->buf + r->blen, sizeof(r->buf) - r->blen);
312 switch (rc) {
313 case -1:
314 snprintf(r->err, sizeof(r->err), "read(socket): %s", strerror(errno));
315 goto err;
316 case 0:
317 snprintf(r->err, sizeof(r->err), "EOF from socket");
318 goto err;
319 default:
320 if (r->trace)
321 hexdump("in ", r->buf + r->blen, rc);
322 r->blen += rc;
323 }
324
325 for (;;) {
326 if (r->blen < 4)
327 goto again;
328 bshift = 0;
329
330 switch (r->buf[0]) {
331 case START_REDIRECTION_SESSION_REPLY:
332 bshift = START_REDIRECTION_SESSION_REPLY_LENGTH;
333 if (r->blen < bshift)
334 goto again;
335 if (r->buf[1] != STATUS_SUCCESS) {
336 snprintf(r->err, sizeof(r->err), "redirection session start failed");
337 goto err;
338 }
339 if (-1 == redir_auth(r))
340 goto err;
341 break;
342 case AUTHENTICATE_SESSION_REPLY:
343 bshift = r->blen; /* FIXME */
344 if (r->blen < bshift)
345 goto again;
346 if (r->buf[1] != STATUS_SUCCESS) {
347 snprintf(r->err, sizeof(r->err), "session authentication failed");
348 goto err;
349 }
350 if (-1 == redir_sol_start(r))
351 goto err;
352 break;
353 case START_SOL_REDIRECTION_REPLY:
354 bshift = r->blen; /* FIXME */
355 if (r->blen < bshift)
356 goto again;
357 if (r->buf[1] != STATUS_SUCCESS) {
358 snprintf(r->err, sizeof(r->err), "serial-over-lan redirection failed");
359 goto err;
360 }
361 redir_state(r, REDIR_RUN_SOL);
362 break;
363 case SOL_HEARTBEAT:
364 case SOL_KEEP_ALIVE_PING:
365 case IDER_HEARTBEAT:
366 case IDER_KEEP_ALIVE_PING:
367 bshift = HEARTBEAT_LENGTH;
368 if (r->blen < bshift)
369 goto again;
370 if (HEARTBEAT_LENGTH != redir_write(r, r->buf, HEARTBEAT_LENGTH))
371 goto err;
372 break;
373 case SOL_DATA_FROM_HOST:
374 if (r->blen < 10) /* header length */
375 goto again;
376 bshift = redir_sol_recv(r);
377 if (bshift < 0)
378 goto err;
379 break;
380 case END_SOL_REDIRECTION_REPLY:
381 bshift = r->blen; /* FIXME */
382 if (r->blen < bshift)
383 goto again;
384 redir_stop(r);
385 break;
386 default:
387 snprintf(r->err, sizeof(r->err), "%s: unknown r->buf 0x%02x",
388 __FUNCTION__, r->buf[0]);
389 goto err;
390 }
391
392 if (bshift == r->blen) {
393 r->blen = 0;
394 break;
395 }
396
397 /* have more data, shift by bshift */
398 if (r->trace)
399 fprintf(stderr, "in : shift by %d\n", bshift);
400 memmove(r->buf, r->buf + bshift, r->blen - bshift);
401 r->blen -= bshift;
402 }
403 return 0;
404
405again:
406 /* need more data, jump back into poll/select loop */
407 if (r->trace)
408 fprintf(stderr, "in : need more data\n");
409 return 0;
410
411err:
412 if (r->trace)
413 fprintf(stderr, "in : ERROR (%s)\n", r->err);
414 redir_state(r, REDIR_ERROR);
415 close(r->sock);
416 return -1;
417}
Impressum, Datenschutz