2 * Intel AMT tcp redirection protocol helper functions.
4 * Copyright (C) 2007 Gerd Hoffmann <kraxel@redhat.com
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.
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.
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.
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",
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",
59 /* ------------------------------------------------------------------ */
61 static void hexdump(const char *prefix
, const unsigned char *data
, size_t size
)
66 for (i
= 0; i
< size
; i
++) {
68 fprintf(stderr
,"%s%s%04x:",
72 memset(ascii
,0,sizeof(ascii
));
76 fprintf(stderr
," %02x",data
[i
]);
77 ascii
[i
%16] = isprint(data
[i
]) ? data
[i
] : '.';
79 fprintf(stderr
," %s\n",ascii
);
88 fprintf(stderr
," %s\n",ascii
);
92 static ssize_t
redir_write(struct redir
*r
, const char *buf
, size_t count
)
97 hexdump("out", buf
, count
);
98 rc
= write(r
->sock
, buf
, count
);
100 snprintf(r
->err
, sizeof(r
->err
), "write(socket): %s", strerror(errno
));
104 static void redir_state(struct redir
*r
, enum redir_state
new)
106 enum redir_state old
= r
->state
;
110 r
->cb_state(r
->cb_data
, old
, new);
113 /* ------------------------------------------------------------------ */
115 const char *redir_state_name(enum redir_state state
)
117 const char *name
= NULL
;
119 if (state
< sizeof(state_name
)/sizeof(state_name
[0]))
120 name
= state_name
[state
];
126 const char *redir_state_desc(enum redir_state state
)
128 const char *desc
= NULL
;
130 if (state
< sizeof(state_desc
)/sizeof(state_desc
[0]))
131 desc
= state_desc
[state
];
137 int redir_connect(struct redir
*r
)
139 static unsigned char *defport
= "16994";
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
);
150 redir_state(r
, REDIR_ERROR
);
156 int redir_start(struct redir
*r
)
158 unsigned char request
[START_REDIRECTION_SESSION_LENGTH
] = {
159 START_REDIRECTION_SESSION
, 0, 0, 0, 0, 0, 0, 0
162 memcpy(request
+4, r
->type
, 4);
163 redir_state(r
, REDIR_INIT
);
164 return redir_write(r
, request
, sizeof(request
));
167 int redir_stop(struct redir
*r
)
169 unsigned char request
[END_REDIRECTION_SESSION_LENGTH
] = {
170 END_REDIRECTION_SESSION
, 0, 0, 0
173 redir_state(r
, REDIR_CLOSED
);
174 redir_write(r
, request
, sizeof(request
));
179 int redir_auth(struct redir
*r
)
181 int ulen
= strlen(r
->user
);
182 int plen
= strlen(r
->pass
);
183 int len
= 11+ulen
+plen
;
185 unsigned char *request
= malloc(len
);
187 memset(request
, 0, len
);
188 request
[0] = AUTHENTICATE_SESSION
;
190 request
[5] = ulen
+plen
+2;
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
);
201 int redir_sol_start(struct redir
*r
)
203 unsigned char request
[START_SOL_REDIRECTION_LENGTH
] = {
204 START_SOL_REDIRECTION
, 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,
220 redir_state(r
, REDIR_INIT_SOL
);
221 return redir_write(r
, request
, sizeof(request
));
224 int redir_sol_stop(struct redir
*r
)
226 unsigned char request
[END_SOL_REDIRECTION_LENGTH
] = {
227 END_SOL_REDIRECTION
, 0, 0, 0,
231 redir_state(r
, REDIR_CLOSING
);
232 return redir_write(r
, request
, sizeof(request
));
235 int redir_sol_send(struct redir
*r
, unsigned char *buf
, int blen
)
239 unsigned char *request
= malloc(len
);
241 memset(request
, 0, len
);
242 request
[0] = SOL_DATA_TO_HOST
;
243 request
[8] = blen
& 0xff;
244 request
[9] = blen
>> 8;
245 memcpy(request
+ 10, buf
, blen
);
246 rc
= redir_write(r
, request
, len
);
251 int redir_sol_recv(struct redir
*r
)
253 unsigned char msg
[64];
254 int count
, len
, bshift
;
256 len
= r
->buf
[8] + (r
->buf
[9] << 8);
257 count
= r
->blen
- 10;
262 r
->cb_recv(r
->cb_data
, r
->buf
+ 10, count
);
267 fprintf(stderr
, "in+: need %d more data bytes\n", len
);
271 count
= read(r
->sock
, msg
, count
);
274 snprintf(r
->err
, sizeof(r
->err
), "read(socket): %s", strerror(errno
));
277 snprintf(r
->err
, sizeof(r
->err
), "EOF from socket");
281 hexdump("in+", msg
, count
);
283 r
->cb_recv(r
->cb_data
, msg
, count
);
291 int redir_data(struct redir
*r
)
296 fprintf(stderr
, "in --\n");
298 fprintf(stderr
, "in : already have %d\n", r
->blen
);
300 rc
= read(r
->sock
, r
->buf
+ r
->blen
, sizeof(r
->buf
) - r
->blen
);
303 snprintf(r
->err
, sizeof(r
->err
), "read(socket): %s", strerror(errno
));
306 snprintf(r
->err
, sizeof(r
->err
), "EOF from socket");
310 hexdump("in ", r
->buf
+ r
->blen
, rc
);
320 case START_REDIRECTION_SESSION_REPLY
:
321 bshift
= START_REDIRECTION_SESSION_REPLY_LENGTH
;
322 if (r
->blen
< bshift
)
324 if (r
->buf
[1] != STATUS_SUCCESS
) {
325 snprintf(r
->err
, sizeof(r
->err
), "redirection session start failed");
328 if (-1 == redir_auth(r
))
331 case AUTHENTICATE_SESSION_REPLY
:
332 bshift
= r
->blen
; /* FIXME */
333 if (r
->blen
< bshift
)
335 if (r
->buf
[1] != STATUS_SUCCESS
) {
336 snprintf(r
->err
, sizeof(r
->err
), "session authentication failed");
339 if (-1 == redir_sol_start(r
))
342 case START_SOL_REDIRECTION_REPLY
:
343 bshift
= r
->blen
; /* FIXME */
344 if (r
->blen
< bshift
)
346 if (r
->buf
[1] != STATUS_SUCCESS
) {
347 snprintf(r
->err
, sizeof(r
->err
), "serial-over-lan redirection failed");
350 redir_state(r
, REDIR_RUN_SOL
);
353 case SOL_KEEP_ALIVE_PING
:
355 case IDER_KEEP_ALIVE_PING
:
356 bshift
= HEARTBEAT_LENGTH
;
357 if (r
->blen
< bshift
)
359 if (HEARTBEAT_LENGTH
!= redir_write(r
, r
->buf
, HEARTBEAT_LENGTH
))
362 case SOL_DATA_FROM_HOST
:
363 if (r
->blen
< 10) /* header length */
365 bshift
= redir_sol_recv(r
);
369 case END_SOL_REDIRECTION_REPLY
:
370 bshift
= r
->blen
; /* FIXME */
371 if (r
->blen
< bshift
)
376 snprintf(r
->err
, sizeof(r
->err
), "%s: unknown r->buf 0x%02x",
377 __FUNCTION__
, r
->buf
[0]);
381 if (bshift
== r
->blen
) {
386 /* have more data, shift by bshift */
388 fprintf(stderr
, "in : shift by %d\n", bshift
);
389 memmove(r
->buf
, r
->buf
+ bshift
, r
->blen
- bshift
);
395 /* need more data, jump back into poll/select loop */
397 fprintf(stderr
, "in : need more data\n");
402 fprintf(stderr
, "in : ERROR (%s)\n", r
->err
);
403 redir_state(r
, REDIR_ERROR
);