fix order of OEMparameters to enable BIOS SOL on newer AMT generations
[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;
240 unsigned char *request;
241
242 for (i = 0; i < blen; i++) {
243 if (buf[i] == 0x0a)
244 buf[i] = 0x0d;
245 }
246
247 request = malloc(len);
248 if (!request) {
249 return -1;
250 }
251
252 memset(request, 0, len);
253 request[0] = SOL_DATA_TO_HOST;
254 request[8] = blen & 0xff;
255 request[9] = blen >> 8;
256 memcpy(request + 10, buf, blen);
257 rc = redir_write(r, request, len);
258 free(request);
259 return rc;
260 }
261
262 int 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
302 int 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
405 again:
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
411 err:
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