1 /*
2 * ipmi_sol.c
3 *
4 * IPMI Serial-over-LAN Client Code
5 *
6 * Author: Cyclades Australia Pty. Ltd.
7 * Darius Davis <darius.davis@cyclades.com>
8 *
9 * Copyright 2005 Cyclades Australia Pty. Ltd.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 *
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * You should have received a copy of the GNU Lesser General Public
29 * License along with this program; if not, write to the Free
30 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32
33 /*
34 * TODO:
35 * - We only support UDP port 623 for now. Add support for other ports.
36 *
37 * CAVEATS:
38 * - Multiple connections at once: should work, but UNTESTED.
39 */
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <sys/stat.h>
44 #include <sys/poll.h>
45 #include <sys/time.h>
46 #include <fcntl.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <netdb.h>
52
53 #include <OpenIPMI/ipmi_conn.h>
54 #include <OpenIPMI/ipmi_msgbits.h>
55 #include <OpenIPMI/ipmi_err.h>
56 #include <OpenIPMI/ipmi_lan.h>
57 #include <OpenIPMI/internal/ipmi_malloc.h>
58 #include <OpenIPMI/ipmi_auth.h>
59 #include <OpenIPMI/internal/locked_list.h>
60 #include <OpenIPMI/internal/ipmi_int.h>
61 #include <OpenIPMI/ipmi_sol.h>
62
63 /* FIXME - after processing waiting packets, a transmitter prod may be
64 necessary in some cases. Figure out where. */
65
66
67 /*
68 * Locking notes:
69 *
70 * You may claim the queue_lock or the oob_lock if you already hold
71 * packet_lock. The reverse is not allowed. You may not claim the
72 * oob_lock and the queue lock at the same time.
73 *
74 * You may not hold the conn_lock with any other lock; use the
75 * refcounts instead.
76 *
77 * The packet_lock is the "general" lock for the connection; it
78 * protects the non-atomic data updates that would affect the
79 * operation of the connection.
80 *
81 * No locks may be held in user callbacks. All the do_xxx_callbacks()
82 * functions must be called with the packet lock held. They will
83 * release the packet lock and reclaim it. These functions are
84 * responsible for serializing
85 */
86
87 /*
88 * Bit masks for status conditions sent BMC -> console, see Table 15-2
89 * [1], page 208, 3rd column.
90 */
91 #define IPMI_SOL_STATUS_NACK_PACKET 0x40
92 #define IPMI_SOL_STATUS_CHARACTER_TRANSFER_UNAVAIL 0x20
93 #define IPMI_SOL_STATUS_DEACTIVATED 0x10
94 #define IPMI_SOL_STATUS_BMC_TX_OVERRUN 0x08
95 #define IPMI_SOL_STATUS_BREAK_DETECTED 0x04
96
97
98 /*
99 * Bit masks for operations sent console -> BMC, see Table 15-2 [1],
100 * page 208, 4th column.
101 */
102 #define IPMI_SOL_OPERATION_NACK_PACKET 0x40
103 #define IPMI_SOL_OPERATION_RING_REQUEST 0x20
104 #define IPMI_SOL_OPERATION_GENERATE_BREAK 0x10
105 #define IPMI_SOL_OPERATION_CTS_PAUSE 0x08
106 #define IPMI_SOL_OPERATION_DROP_DCD_DSR 0x04
107 #define IPMI_SOL_OPERATION_FLUSH_CONSOLE_TO_BMC 0x02
108 #define IPMI_SOL_OPERATION_FLUSH_BMC_TO_CONSOLE 0x01
109
110
111 #define IPMI_SOL_AUX_USE_ENCRYPTION 0x80
112 #define IPMI_SOL_AUX_USE_AUTHENTICATION 0x40
113 #define IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_SHIFT 2
114 #define IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_MASK 0x03
115 #define IPMI_SOL_AUX_DEASSERT_HANDSHAKE 0x02
116
117
118 #define IPMI_SOL_MAX_DATA_SIZE 103
119
120 #if 0
121 #define IPMI_SOL_DEBUG_TRANSMIT
122 #define IPMI_SOL_VERBOSE
123 #define IPMI_SOL_DEBUG_RECEIVE
124 #endif
125
126
127 typedef struct ipmi_sol_transmitter_context_s ipmi_sol_transmitter_context_t;
128
129
130 /**
131 * Stores a list of generic callback functions. Values are to be typecast as
132 * they are extracted.
133 */
134 typedef struct callback_list_s callback_list_t;
135 struct callback_list_s {
136 void *cb;
137 void *cb_data;
138 int error;
139 callback_list_t *next;
140 };
141
142 /**
143 * Stores a write-request from the client software, along with its transmit
144 * complete callback and in-band operation mask (currently used only for serial
145 * breaks).
146 */
147 typedef struct ipmi_sol_outgoing_queue_item_s ipmi_sol_outgoing_queue_item_t;
148 struct ipmi_sol_outgoing_queue_item_s {
149 /* The bytes to transmit. This will be NULL if the queue item
150 represents a BREAK. */
151 char *data;
152
153 /* The number of bytes in this packet. Will be zero if the queue
154 item represents a BREAK. */
155 unsigned char data_len;
156
157 /* The in-band (sequential) operation. Should only contain
158 IPMI_SOL_GENERATE_BREAK for now. */
159 unsigned char ib_op;
160
161 /* The callback to call when the data (or BREAK) have been ACKed
162 or sent. */
163 ipmi_sol_transmit_complete_cb transmit_complete_callback;
164 void *cb_data;
165
166 ipmi_sol_outgoing_queue_item_t *next;
167 };
168
169
170
171 /**
172 * Outgoing write-requests are queued for transmission as the SoL channel
173 * is available. This structure stores the queue.
174 */
175 typedef struct ipmi_sol_outgoing_queue_s {
176 ipmi_sol_outgoing_queue_item_t *head;
177 ipmi_sol_outgoing_queue_item_t *tail;
178 } ipmi_sol_outgoing_queue_t;
179
180
181 /**
182 * Offsets of fields within the SoL packet
183 */
184 #define PACKET_SEQNR 0
185 #define PACKET_ACK_NACK_SEQNR 1
186 #define PACKET_ACCEPTED_CHARACTER_COUNT 2
187 #define PACKET_OP 3
188 #define PACKET_STATUS 3
189 #define PACKET_DATA 4
190
191 typedef struct ipmi_sol_outgoing_packet_record_s {
192 /* OS handler for freeing the timer. */
193 os_handler_t *os_hnd;
194
195 /* The connection that owns this packet. */
196 ipmi_sol_conn_t *conn;
197
198 /* The outgoing SoL payload data. Min 4 bytes long. */
199 unsigned char *packet;
200
201 /* The length of the outgoing SoL payload data. */
202 int packet_size;
203
204 /* The timer to manage retransmits. Needs a lock for concurrency
205 handling. */
206 int deleted;
207 int timer_running;
208 ipmi_lock_t *timer_lock;
209 os_hnd_timer_id_t *ack_timer;
210
211 /* Nonzero iff we're expecting an ACK for this packet. */
212 int expecting_ACK;
213
214 /* Countdown of number of transmission attempts left before we
215 declare the packet "lost". */
216 int transmit_attempts_remaining;
217
218 /* callbacks for operations in this packet. */
219 callback_list_t *op_callback_list;
220 } ipmi_sol_outgoing_packet_record_t;
221
222
223 /* Used to keep a list of incoming packets to process. */
224 typedef struct sol_in_packet_info_s
225 {
226 unsigned int data_len;
227
228 struct sol_in_packet_info_s *next;
229
230 /* Data is tacked on to the end of this. */
231 } sol_in_packet_info_t;
232
233 /* Used to keep a list of pending state transitions. */
234 typedef struct sol_state_cb_info_s
235 {
236 ipmi_sol_state state;
237 int error;
238
239 struct sol_state_cb_info_s *next;
240 } sol_state_cb_info_t;
241
242 struct ipmi_sol_transmitter_context_s {
243 /* A queue of un-acked transmit requests. */
244 ipmi_sol_outgoing_queue_t outgoing_queue;
245
246 /* A reference back to the SoL connection to which this
247 transmitter belongs. */
248 ipmi_sol_conn_t *sol_conn;
249
250 /* The latest entire packet transmitted is stored here. */
251 ipmi_sol_outgoing_packet_record_t *transmitted_packet;
252
253 /* A buffer into which the data is coalesced for transmission. */
254 unsigned char *scratch_area;
255
256 /* The size of the scratch_area buffer. */
257 int scratch_area_size;
258
259 /* Keep track of the sequence number that we've most recently sent. */
260 int latest_outgoing_seqnr;
261
262 /* Next outgoing packet will ACK/NACK this packet. */
263 int packet_to_acknowledge;
264
265 /* We accepted this many chars from the above packet. */
266 int accepted_character_count;
267
268 /* Nack returns pending that we need release_nack calls for. */
269 int nack_count;
270
271 /* Are we currently in a receive callback? */
272 int in_recv_cb;
273
274 /* We have already acked this many chars from the request at the
275 head of the tx queue. */
276 int bytes_acked_at_head;
277
278 /* Lock for the op callback list and the op data. */
279 ipmi_lock_t *oob_op_lock;
280
281 /* a combination of IPMI_SOL_OPERATION_RING_REQUEST,
282 IPMI_SOL_OPERATION_CTS_PAUSE,
283 IPMI_SOL_OPERATION_DROP_DCD_DSR */
284 unsigned char oob_persistent_op;
285
286 /* a combination of IPMI_SOL_OPERATION_FLUSH_CONSOLE_TO_BMC,
287 IPMI_SOL_OPERATION_FLUSH_BMC_TO_CONSOLE */
288 unsigned char oob_transient_op;
289
290 /* callbacks for operations currently in oob_persistent_op and
291 oob_transient_op but not yet transmitted */
292 callback_list_t *op_callback_list;
293
294 /* Locking for queue operations and packet operations */
295 ipmi_lock_t *queue_lock, *packet_lock;
296 };
297
298 struct ipmi_sol_conn_s {
299 /* The IPMI connection for commands. */
300 ipmi_con_t *ipmi;
301
302 /* The IPMI connection for SOL data. */
303 ipmi_con_t *ipmid;
304
305 /* Used to know how many users are using this right now. */
306 unsigned int refcount;
307
308 /* The system interface address is cached here for sending RMCP+
309 commands. */
310 ipmi_system_interface_addr_t addr;
311
312 /* The RMCP+ destination address is cached here for sending SoL
313 packets. */
314 ipmi_rmcpp_addr_t sol_payload_addr;
315
316 unsigned char initial_bit_rate;
317 unsigned char privilege_level;
318
319 /* Nonzero allows ipmi_sol_open to alter the nonvolatile
320 configuration to force SoL to come up if at all possible. Only
321 for debugging, please! */
322 int force_connection_configure;
323
324 /* Connects more quickly, but will give a lot less diagnostic info
325 if it fails. */
326 int try_fast_connect;
327
328 /* The current state of the SoL connection. Note that state
329 changes are protected by the packet lock. */
330 ipmi_sol_state state;
331
332 /* Max payload size outbound from here->BMC */
333 unsigned int max_outbound_payload_size;
334
335 /* Max payload size inbound from BMC->here */
336 unsigned int max_inbound_payload_size;
337
338 unsigned int payload_port_number;
339
340 /* We choose a payload instance number when activating the SoL payload */
341 unsigned int payload_instance;
342
343 /* This is the transmitter for this connection */
344 ipmi_sol_transmitter_context_t transmitter;
345
346 /* The last sequence number we received from the BMC. */
347 unsigned char prev_received_seqnr;
348
349 /* The number of characters we ACKed in the last packet received
350 from the BMC. */
351 unsigned char prev_character_count;
352
353 /* Configuration data used at Payload Activation */
354 unsigned char auxiliary_payload_data;
355 int ACK_timeout_usec;
356 int ACK_retries;
357
358 /* A list of callbacks that are called when data received from the BMC. */
359 locked_list_t *data_received_callback_list;
360
361 /* A list of callbacks that are called when a break is reported by
362 the BMC. */
363 locked_list_t *break_detected_callback_list;
364
365 /* A list of callbacks that are called when a transmit overrun is
366 reported by the BMC. */
367 locked_list_t *bmc_transmit_overrun_callback_list;
368
369 /* A list of callbacks that are called when the SoL connection
370 changes state. */
371 locked_list_t *connection_state_callback_list;
372
373 /* We single-thread the processing of packets for a connection.
374 New packets get queued to be process later if processing is
375 already going on. The following handle this. */
376 unsigned int processing_packet;
377 sol_in_packet_info_t *waiting_packets;
378 callback_list_t *waiting_callbacks;
379 sol_state_cb_info_t *waiting_states;
380
381 /* Used to make a linked-list of these */
382 ipmi_sol_conn_t *next;
383 };
384
385
386 static int transmitter_startup(ipmi_sol_transmitter_context_t *transmitter);
387 static void transmitter_shutdown(ipmi_sol_transmitter_context_t *transmitter,
388 int error);
389 static void transmitter_prod_nolock
390 (ipmi_sol_transmitter_context_t *transmitter);
391 static void process_packet(ipmi_sol_conn_t *conn,
392 unsigned char *packet,
393 unsigned int data_len);
394
395 static void
dump_hex(unsigned char * data,int len)396 dump_hex(unsigned char *data, int len)
397 {
398 int i;
399 for (i=0; i<len; i++) {
400 if ((i != 0) && ((i % 16) == 0)) {
401 ipmi_log(IPMI_LOG_DEBUG_CONT, "\n ");
402 }
403 ipmi_log(IPMI_LOG_DEBUG_CONT, " %2.2x", data[i]);
404 }
405 }
406
407
408 /****************************************************************************
409 * SoL Connection List
410 *
411 * Used to match up an incoming packet with the SoL connection that should
412 * be interested in that packet.
413 */
414
415 /* FIXME - a list is ineffecient for large numbers of connections. It
416 probably doesn't matter for now, but a hash table might be a good
417 idea in the future. */
418
419 static ipmi_sol_conn_t *conn_list = NULL;
420 static ipmi_lock_t *conn_lock = NULL;
421
422 /**
423 * Adds the given (ipmi, sol) pairing to the list of connections we're
424 * managing.
425 */
426 static int
add_connection(ipmi_sol_conn_t * nconn)427 add_connection(ipmi_sol_conn_t *nconn)
428 {
429 ipmi_sol_conn_t *conn;
430
431 ipmi_lock(conn_lock);
432
433 /* Make sure the connection doesn't already exist */
434 conn = conn_list;
435 while (conn) {
436 if (conn->ipmi == nconn->ipmi) {
437 ipmi_unlock(conn_lock);
438 return EAGAIN;
439 }
440 conn = conn->next;
441 }
442
443 nconn->next = conn_list;
444 conn_list = nconn;
445 ipmi_unlock(conn_lock);
446 return 0;
447 }
448
449
450 /**
451 * Removes the given connection from the list of connections we're managing.
452 */
delete_connection(ipmi_sol_conn_t * sol)453 static void delete_connection(ipmi_sol_conn_t *sol)
454 {
455 ipmi_sol_conn_t *curr;
456 ipmi_sol_conn_t *prev = NULL;
457
458 ipmi_lock(conn_lock);
459 curr = conn_list;
460 while (curr) {
461 if (curr == sol) {
462 /*
463 * Delete me!
464 */
465 if (!prev)
466 /* Deleting from head of list... */
467 conn_list = conn_list->next;
468 else
469 /* Deleting from within list */
470 prev->next = curr->next;
471 break;
472 }
473
474 prev = curr;
475 curr = curr->next;
476 }
477 ipmi_unlock(conn_lock);
478 }
479
480
481 /**
482 * Finds the sol connection for a given ipmi connection.
483 */
484 static ipmi_sol_conn_t *
find_sol_connection_for_ipmi(ipmi_con_t * ipmi)485 find_sol_connection_for_ipmi(ipmi_con_t *ipmi)
486 {
487 ipmi_sol_conn_t *conn;
488
489 ipmi_lock(conn_lock);
490 conn = conn_list;
491 while (conn) {
492 if (conn->ipmi == ipmi) {
493 conn->refcount++;
494 ipmi_unlock(conn_lock);
495 return conn;
496 }
497 conn = conn->next;
498 }
499 ipmi_unlock(conn_lock);
500
501 return NULL;
502 }
503
504 static ipmi_sol_conn_t *
find_sol_connection(ipmi_sol_conn_t * sol)505 find_sol_connection(ipmi_sol_conn_t *sol)
506 {
507 ipmi_sol_conn_t *conn;
508
509 ipmi_lock(conn_lock);
510 conn = conn_list;
511 while (conn) {
512 if (conn == sol) {
513 conn->refcount++;
514 ipmi_unlock(conn_lock);
515 return conn;
516 }
517 conn = conn->next;
518 }
519 ipmi_unlock(conn_lock);
520
521 return NULL;
522 }
523
524 static void ipmid_changed(ipmi_con_t *ipmid,
525 int err,
526 unsigned int port_num,
527 int any_port_up,
528 void *cb_data);
529
530 static void
sol_connection_closed(ipmi_con_t * ipmi,void * cb_data)531 sol_connection_closed(ipmi_con_t *ipmi, void *cb_data)
532 {
533 ipmi_sol_conn_t *conn = cb_data;
534
535 if (conn->transmitter.packet_lock)
536 ipmi_destroy_lock(conn->transmitter.packet_lock);
537 if (conn->transmitter.queue_lock)
538 ipmi_destroy_lock(conn->transmitter.queue_lock);
539 if (conn->transmitter.oob_op_lock)
540 ipmi_destroy_lock(conn->transmitter.oob_op_lock);
541 if (conn->data_received_callback_list)
542 locked_list_destroy(conn->data_received_callback_list);
543 if (conn->break_detected_callback_list)
544 locked_list_destroy(conn->break_detected_callback_list);
545 if (conn->bmc_transmit_overrun_callback_list)
546 locked_list_destroy(conn->bmc_transmit_overrun_callback_list);
547 if (conn->connection_state_callback_list)
548 locked_list_destroy(conn->connection_state_callback_list);
549 ipmi_mem_free(conn);
550 }
551
552 static void
sol_cleanup(ipmi_sol_conn_t * conn)553 sol_cleanup(ipmi_sol_conn_t *conn)
554 {
555 if (conn->ipmid)
556 conn->ipmid->remove_con_change_handler(conn->ipmid, ipmid_changed,
557 conn);
558
559 if (conn->state != ipmi_sol_state_closed)
560 ipmi_sol_force_close(conn);
561
562 delete_connection(conn);
563
564 while (conn->waiting_packets) {
565 sol_in_packet_info_t *to_free = conn->waiting_packets;
566
567 conn->waiting_packets = to_free->next;
568 ipmi_mem_free(to_free);
569 }
570
571 if (conn->ipmi->close_connection_done(conn->ipmid, sol_connection_closed,
572 conn))
573 sol_connection_closed(NULL, conn);
574 }
575
576 /**
577 * Tell the system that a user is done with the connection.
578 */
579 static void
sol_put_connection(ipmi_sol_conn_t * conn)580 sol_put_connection(ipmi_sol_conn_t *conn)
581 {
582 ipmi_lock(conn_lock);
583 conn->refcount--;
584 if (conn->refcount == 0) {
585 /* No more users, destroy the connection. */
586 ipmi_unlock(conn_lock);
587 sol_cleanup(conn);
588 } else
589 ipmi_unlock(conn_lock);
590 }
591
592
593 /***************************************************************************
594 ** Shorthand IPMI messaging; used to set up or close an ipmi_sol_conn_t.
595 ** This is NOT used for handling the SoL data... for that, see the payload
596 ** functions towards the end of this file.
597 **
598 ** Note that the packet lock will be held in the callback.
599 **/
600
601 typedef void (*sol_command_callback)(ipmi_sol_conn_t *conn, ipmi_msg_t *msg);
602
handle_response(ipmi_con_t * ipmi,ipmi_msgi_t * rspi)603 static int handle_response(ipmi_con_t *ipmi, ipmi_msgi_t *rspi)
604 {
605 ipmi_sol_conn_t *conn = find_sol_connection(rspi->data1);
606 sol_command_callback cb = rspi->data2;
607
608 if (! conn)
609 /* Connection went away while in progress... */
610 goto out;
611
612 if (cb) {
613 ipmi_lock(conn->transmitter.packet_lock);
614 cb(conn, &rspi->msg);
615 ipmi_unlock(conn->transmitter.packet_lock);
616 }
617
618 sol_put_connection(conn);
619 out:
620 ipmi_free_msg_item(rspi);
621 return IPMI_MSG_ITEM_USED;
622 }
623
624
625 static int
send_message(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_out,sol_command_callback cb)626 send_message(ipmi_sol_conn_t *conn,
627 ipmi_msg_t *msg_out,
628 sol_command_callback cb)
629 {
630 int rv = 0;
631 ipmi_msgi_t *rspi = ipmi_alloc_msg_item();
632
633 if (!rspi)
634 return ENOMEM;
635
636 rspi->data1 = conn;
637 rspi->data2 = cb;
638 rspi->data3 = NULL;
639 rspi->data4 = NULL;
640 rv = conn->ipmi->send_command(conn->ipmi,
641 (ipmi_addr_t *)&conn->addr,
642 sizeof(conn->addr),
643 msg_out,
644 handle_response,
645 rspi);
646
647 if (rv)
648 ipmi_free_msg_item(rspi);
649
650 return rv;
651 }
652
653 static int
send_close(ipmi_sol_conn_t * conn,sol_command_callback cb)654 send_close(ipmi_sol_conn_t *conn, sol_command_callback cb)
655 {
656 ipmi_msg_t msg_out;
657 unsigned char data[6];
658
659 /*
660 * Send a Deactivate Payload
661 */
662 msg_out.data_len = 6;
663 msg_out.data = data;
664
665 msg_out.data[0] = IPMI_RMCPP_PAYLOAD_TYPE_SOL & 0x3f; /* payload type */
666 msg_out.data[1] = conn->payload_instance; /* payload instance number */
667 msg_out.data[2] = 0x00; /* payload aux data */
668 msg_out.data[3] = 0x00;
669 msg_out.data[4] = 0x00;
670 msg_out.data[5] = 0x00;
671
672 msg_out.netfn = IPMI_APP_NETFN;
673 msg_out.cmd = IPMI_DEACTIVATE_PAYLOAD_CMD;
674
675 return send_message(conn, &msg_out, cb);
676 }
677
678
679 /****************************************************************************
680 ** Async callback handling - list management, registration, deregistration
681 **/
682
683 typedef struct do_data_received_callback_s
684 {
685 ipmi_sol_conn_t *conn;
686 const void *buf;
687 size_t count;
688 int nack;
689 } do_data_received_callback_t;
690
691 static int
do_data_received_callback(void * cb_data,void * item1,void * item2)692 do_data_received_callback(void *cb_data, void *item1, void *item2)
693 {
694 do_data_received_callback_t *info = cb_data;
695 ipmi_sol_data_received_cb cb = item1;
696
697 if (cb(info->conn, info->buf, info->count, item2))
698 info->nack++;
699 return LOCKED_LIST_ITER_CONTINUE;
700 }
701
702 static int
do_data_received_callbacks(ipmi_sol_conn_t * conn,const void * buf,size_t count)703 do_data_received_callbacks(ipmi_sol_conn_t *conn,
704 const void *buf,
705 size_t count)
706 {
707 do_data_received_callback_t info;
708
709 info.conn = conn;
710 info.buf = buf;
711 info.count = count;
712 info.nack = 0;
713 locked_list_iterate(conn->data_received_callback_list,
714 do_data_received_callback,
715 &info);
716
717 /* Only called from the packet handling routine, no need for any
718 special handling. for waiting */
719 return info.nack;
720 }
721
722 static int
do_break_detected_callback(void * cb_data,void * item1,void * item2)723 do_break_detected_callback(void *cb_data, void *item1, void *item2)
724 {
725 ipmi_sol_conn_t *conn = cb_data;
726 ipmi_sol_break_detected_cb cb = item1;
727
728 cb(conn, item2);
729 return LOCKED_LIST_ITER_CONTINUE;
730 }
731
732 static void
do_break_detected_callbacks(ipmi_sol_conn_t * conn)733 do_break_detected_callbacks(ipmi_sol_conn_t *conn)
734 {
735 locked_list_iterate(conn->break_detected_callback_list,
736 do_break_detected_callback,
737 conn);
738
739 /* Only called from the packet handling routine, no need for any
740 special handling. for waiting */
741 }
742
743 static int
do_transmit_overrun_callback(void * cb_data,void * item1,void * item2)744 do_transmit_overrun_callback(void *cb_data, void *item1, void *item2)
745 {
746 ipmi_sol_conn_t *conn = cb_data;
747 ipmi_sol_bmc_transmit_overrun_cb cb = item1;
748
749 cb(conn, item2);
750 return LOCKED_LIST_ITER_CONTINUE;
751 }
752
753 static void
do_transmit_overrun_callbacks(ipmi_sol_conn_t * conn)754 do_transmit_overrun_callbacks(ipmi_sol_conn_t *conn)
755 {
756 locked_list_iterate(conn->bmc_transmit_overrun_callback_list,
757 do_transmit_overrun_callback,
758 conn);
759
760 /* Only called from the packet handling routine, no need for any
761 special handling. for waiting */
762 }
763
764 typedef struct do_connection_state_callback_s
765 {
766 ipmi_sol_conn_t *conn;
767 ipmi_sol_state state;
768 int error;
769 } do_connection_state_callback_t;
770
771 static int
do_connection_state_callback(void * cb_data,void * item1,void * item2)772 do_connection_state_callback(void *cb_data, void *item1, void *item2)
773 {
774 do_connection_state_callback_t *info = cb_data;
775 ipmi_sol_connection_state_cb cb = item1;
776
777 cb(info->conn, info->state, info->error, item2);
778 return LOCKED_LIST_ITER_CONTINUE;
779 }
780
781 void
do_connection_state_callbacks(ipmi_sol_conn_t * conn,ipmi_sol_state new_state,int error)782 do_connection_state_callbacks(ipmi_sol_conn_t *conn,
783 ipmi_sol_state new_state,
784 int error)
785 {
786 do_connection_state_callback_t info;
787
788 info.conn = conn;
789 info.state = new_state;
790 info.error = error;
791 locked_list_iterate(conn->connection_state_callback_list,
792 do_connection_state_callback,
793 &info);
794 }
795
796 int
ipmi_sol_register_data_received_callback(ipmi_sol_conn_t * conn,ipmi_sol_data_received_cb cb,void * cb_data)797 ipmi_sol_register_data_received_callback(ipmi_sol_conn_t *conn,
798 ipmi_sol_data_received_cb cb,
799 void *cb_data)
800 {
801 if (locked_list_add(conn->data_received_callback_list, cb, cb_data))
802 return 0;
803 else
804 return ENOMEM;
805 }
806
807 int
ipmi_sol_deregister_data_received_callback(ipmi_sol_conn_t * conn,ipmi_sol_data_received_cb cb,void * cb_data)808 ipmi_sol_deregister_data_received_callback(ipmi_sol_conn_t *conn,
809 ipmi_sol_data_received_cb cb,
810 void *cb_data)
811 {
812 if (locked_list_remove(conn->data_received_callback_list, cb, cb_data))
813 return 0;
814 else
815 return EINVAL;
816 }
817
818
819 int
ipmi_sol_register_break_detected_callback(ipmi_sol_conn_t * conn,ipmi_sol_break_detected_cb cb,void * cb_data)820 ipmi_sol_register_break_detected_callback(ipmi_sol_conn_t *conn,
821 ipmi_sol_break_detected_cb cb,
822 void *cb_data)
823 {
824 if (locked_list_add(conn->break_detected_callback_list, cb, cb_data))
825 return 0;
826 else
827 return ENOMEM;
828 }
829
830 int
ipmi_sol_deregister_break_detected_callback(ipmi_sol_conn_t * conn,ipmi_sol_break_detected_cb cb,void * cb_data)831 ipmi_sol_deregister_break_detected_callback(ipmi_sol_conn_t *conn,
832 ipmi_sol_break_detected_cb cb,
833 void *cb_data)
834 {
835 if (locked_list_remove(conn->break_detected_callback_list, cb, cb_data))
836 return 0;
837 else
838 return EINVAL;
839 }
840
841
842 int
ipmi_sol_register_bmc_transmit_overrun_callback(ipmi_sol_conn_t * conn,ipmi_sol_bmc_transmit_overrun_cb cb,void * cb_data)843 ipmi_sol_register_bmc_transmit_overrun_callback(ipmi_sol_conn_t *conn,
844 ipmi_sol_bmc_transmit_overrun_cb cb,
845 void *cb_data)
846 {
847 if (locked_list_add(conn->bmc_transmit_overrun_callback_list, cb, cb_data))
848 return 0;
849 else
850 return ENOMEM;
851 }
852
853 int
ipmi_sol_deregister_bmc_transmit_overrun_callback(ipmi_sol_conn_t * conn,ipmi_sol_bmc_transmit_overrun_cb cb,void * cb_data)854 ipmi_sol_deregister_bmc_transmit_overrun_callback(ipmi_sol_conn_t *conn,
855 ipmi_sol_bmc_transmit_overrun_cb cb,
856 void *cb_data)
857 {
858 if (locked_list_remove(conn->bmc_transmit_overrun_callback_list, cb,
859 cb_data))
860 return 0;
861 else
862 return EINVAL;
863 }
864
865
866 int
ipmi_sol_register_connection_state_callback(ipmi_sol_conn_t * conn,ipmi_sol_connection_state_cb cb,void * cb_data)867 ipmi_sol_register_connection_state_callback(ipmi_sol_conn_t *conn,
868 ipmi_sol_connection_state_cb cb,
869 void *cb_data)
870 {
871 if (locked_list_add(conn->connection_state_callback_list, cb, cb_data))
872 return 0;
873 else
874 return ENOMEM;
875 }
876
877 int
ipmi_sol_deregister_connection_state_callback(ipmi_sol_conn_t * conn,ipmi_sol_connection_state_cb cb,void * cb_data)878 ipmi_sol_deregister_connection_state_callback(ipmi_sol_conn_t *conn,
879 ipmi_sol_connection_state_cb cb,
880 void *cb_data)
881 {
882 if (locked_list_remove(conn->connection_state_callback_list, cb, cb_data))
883 return 0;
884 else
885 return EINVAL;
886 }
887
888
889 void
ipmi_sol_set_ACK_timeout(ipmi_sol_conn_t * conn,int timeout_usec)890 ipmi_sol_set_ACK_timeout(ipmi_sol_conn_t *conn, int timeout_usec)
891 {
892 conn->ACK_timeout_usec = timeout_usec;
893 }
894
895 int
ipmi_sol_get_ACK_timeout(ipmi_sol_conn_t * conn)896 ipmi_sol_get_ACK_timeout(ipmi_sol_conn_t *conn)
897 {
898 return conn->ACK_timeout_usec;
899 }
900
901 void
ipmi_sol_set_ACK_retries(ipmi_sol_conn_t * conn,int retries)902 ipmi_sol_set_ACK_retries(ipmi_sol_conn_t *conn, int retries)
903 {
904 conn->ACK_retries = retries;
905 }
906
907 int
ipmi_sol_get_ACK_retries(ipmi_sol_conn_t * conn)908 ipmi_sol_get_ACK_retries(ipmi_sol_conn_t *conn)
909 {
910 return conn->ACK_retries;
911 }
912
913
914 /******************************************************************************
915 * SoL auxiliary payload data configuration
916 *
917 * These parameters will be set when the payload is activated:
918 * - authentication (enabled, disabled)
919 * - encryption (enabled, disabled)
920 * - shared serial alert behaviour (fail, defer, succeed)
921 * - Deassert DSR/DCD/CTS on connect (enabled, disabled)
922 */
923
924 int
ipmi_sol_set_use_authentication(ipmi_sol_conn_t * conn,int use_authentication)925 ipmi_sol_set_use_authentication(ipmi_sol_conn_t *conn,
926 int use_authentication)
927 {
928 if (!conn)
929 return EINVAL;
930
931 ipmi_lock(conn->transmitter.packet_lock);
932 if (conn->state != ipmi_sol_state_closed) {
933 ipmi_unlock(conn->transmitter.packet_lock);
934 return EINVAL;
935 }
936
937 if (use_authentication)
938 conn->auxiliary_payload_data |= IPMI_SOL_AUX_USE_AUTHENTICATION;
939 else
940 conn->auxiliary_payload_data &= ~IPMI_SOL_AUX_USE_AUTHENTICATION;
941 ipmi_unlock(conn->transmitter.packet_lock);
942
943 return 0;
944 }
945
946
947 int
ipmi_sol_get_use_authentication(ipmi_sol_conn_t * conn)948 ipmi_sol_get_use_authentication(ipmi_sol_conn_t *conn)
949 {
950 return ((conn->auxiliary_payload_data & IPMI_SOL_AUX_USE_AUTHENTICATION)
951 != 0);
952 }
953
954 int
ipmi_sol_set_use_encryption(ipmi_sol_conn_t * conn,int use_encryption)955 ipmi_sol_set_use_encryption(ipmi_sol_conn_t *conn, int use_encryption)
956 {
957 if (!conn)
958 return EINVAL;
959
960 ipmi_lock(conn->transmitter.packet_lock);
961 if (conn->state != ipmi_sol_state_closed) {
962 ipmi_unlock(conn->transmitter.packet_lock);
963 return EINVAL;
964 }
965
966 if (use_encryption)
967 conn->auxiliary_payload_data |= IPMI_SOL_AUX_USE_ENCRYPTION;
968 else
969 conn->auxiliary_payload_data &= ~IPMI_SOL_AUX_USE_ENCRYPTION;
970 ipmi_unlock(conn->transmitter.packet_lock);
971
972 return 0;
973 }
974
975 int
ipmi_sol_get_use_encryption(ipmi_sol_conn_t * conn)976 ipmi_sol_get_use_encryption(ipmi_sol_conn_t *conn)
977 {
978 return ((conn->auxiliary_payload_data & IPMI_SOL_AUX_USE_ENCRYPTION)
979 != 0);
980 }
981
982
983 int
ipmi_sol_set_shared_serial_alert_behavior(ipmi_sol_conn_t * conn,ipmi_sol_serial_alert_behavior behavior)984 ipmi_sol_set_shared_serial_alert_behavior(ipmi_sol_conn_t *conn,
985 ipmi_sol_serial_alert_behavior behavior)
986 {
987 if (!conn)
988 return EINVAL;
989
990 ipmi_lock(conn->transmitter.packet_lock);
991 if (conn->state != ipmi_sol_state_closed) {
992 ipmi_unlock(conn->transmitter.packet_lock);
993 return EINVAL;
994 }
995
996 conn->auxiliary_payload_data
997 &= ~(IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_MASK
998 << IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_SHIFT);
999 conn->auxiliary_payload_data
1000 |= behavior << IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_SHIFT;
1001 ipmi_unlock(conn->transmitter.packet_lock);
1002
1003 return 0;
1004 }
1005
1006
1007 ipmi_sol_serial_alert_behavior
ipmi_sol_get_shared_serial_alert_behavior(ipmi_sol_conn_t * conn)1008 ipmi_sol_get_shared_serial_alert_behavior(ipmi_sol_conn_t *conn)
1009 {
1010 return (ipmi_sol_serial_alert_behavior)
1011 ((conn->auxiliary_payload_data
1012 >> IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_SHIFT)
1013 & IPMI_SOL_AUX_SHARED_SERIAL_BEHAVIOR_MASK);
1014 }
1015
1016 int
ipmi_sol_set_deassert_CTS_DCD_DSR_on_connect(ipmi_sol_conn_t * conn,int deassert)1017 ipmi_sol_set_deassert_CTS_DCD_DSR_on_connect(ipmi_sol_conn_t *conn,
1018 int deassert)
1019 {
1020 if (!conn)
1021 return EINVAL;
1022
1023 ipmi_lock(conn->transmitter.packet_lock);
1024 if (conn->state != ipmi_sol_state_closed) {
1025 ipmi_unlock(conn->transmitter.packet_lock);
1026 return EINVAL;
1027 }
1028
1029 if (deassert)
1030 conn->auxiliary_payload_data |= IPMI_SOL_AUX_DEASSERT_HANDSHAKE;
1031 else
1032 conn->auxiliary_payload_data &= ~IPMI_SOL_AUX_DEASSERT_HANDSHAKE;
1033 ipmi_unlock(conn->transmitter.packet_lock);
1034
1035 return 0;
1036 }
1037
1038
1039 int
ipmi_sol_get_deassert_CTS_DCD_DSR_on_connect(ipmi_sol_conn_t * conn)1040 ipmi_sol_get_deassert_CTS_DCD_DSR_on_connect(ipmi_sol_conn_t *conn)
1041 {
1042 return ((conn->auxiliary_payload_data & IPMI_SOL_AUX_DEASSERT_HANDSHAKE)
1043 != 0);
1044 }
1045
1046
ipmi_sol_set_bit_rate(ipmi_sol_conn_t * conn,unsigned char rate)1047 int ipmi_sol_set_bit_rate(ipmi_sol_conn_t *conn, unsigned char rate)
1048 {
1049 if (!conn)
1050 return EINVAL;
1051
1052 ipmi_lock(conn->transmitter.packet_lock);
1053 if (conn->state != ipmi_sol_state_closed) {
1054 ipmi_unlock(conn->transmitter.packet_lock);
1055 return EINVAL;
1056 }
1057
1058 conn->initial_bit_rate = rate;
1059 ipmi_unlock(conn->transmitter.packet_lock);
1060
1061 return 0;
1062 }
1063
1064 unsigned char
ipmi_sol_get_bit_rate(ipmi_sol_conn_t * conn)1065 ipmi_sol_get_bit_rate(ipmi_sol_conn_t *conn)
1066 {
1067 return conn->initial_bit_rate;
1068 }
1069
1070
1071 static void
do_and_destroy_transmit_complete_callbacks(callback_list_t * list,ipmi_sol_conn_t * conn)1072 do_and_destroy_transmit_complete_callbacks(callback_list_t *list,
1073 ipmi_sol_conn_t *conn)
1074 {
1075 callback_list_t *temp;
1076
1077 while (NULL != list) {
1078 ((ipmi_sol_transmit_complete_cb)list->cb)(conn, list->error,
1079 list->cb_data);
1080 temp = list;
1081 list = list->next;
1082 ipmi_mem_free(temp);
1083 }
1084 }
1085
1086
1087 /*
1088 * Handle and packets that are waiting to be processed.
1089 */
1090 static void
process_waiting_packets(ipmi_sol_conn_t * conn)1091 process_waiting_packets(ipmi_sol_conn_t *conn)
1092 {
1093 while ((conn->waiting_packets) || conn->waiting_callbacks
1094 || (conn->waiting_states))
1095 {
1096 while (conn->waiting_callbacks) {
1097 callback_list_t *callbacks = conn->waiting_callbacks;
1098 conn->waiting_callbacks = NULL;
1099 ipmi_unlock(conn->transmitter.packet_lock);
1100 do_and_destroy_transmit_complete_callbacks(callbacks, conn);
1101 ipmi_lock(conn->transmitter.packet_lock);
1102 }
1103
1104 if (conn->waiting_states) {
1105 sol_state_cb_info_t *state = conn->waiting_states;
1106 conn->waiting_states = state->next;
1107 ipmi_unlock(conn->transmitter.packet_lock);
1108 do_connection_state_callbacks(conn, state->state, state->error);
1109 ipmi_mem_free(state);
1110 ipmi_lock(conn->transmitter.packet_lock);
1111 continue;
1112 }
1113
1114 if (conn->waiting_packets) {
1115 sol_in_packet_info_t *packet = conn->waiting_packets;
1116 unsigned char *pdata
1117 = ((unsigned char *) packet) + sizeof(*packet);
1118
1119 /* Connection may have closed during reporting information,
1120 make sure to check this. */
1121 if (conn->state == ipmi_sol_state_closed) {
1122 ipmi_log(IPMI_LOG_WARNING,
1123 "ipmi_sol.c(sol_handle_recv_async): "
1124 "Dropped incoming SoL packet: connection closed.");
1125 while (packet) {
1126 sol_in_packet_info_t *npacket = packet->next;
1127 ipmi_mem_free(packet);
1128 packet = npacket;
1129 }
1130 conn->waiting_packets = NULL;
1131 return;
1132 }
1133
1134 process_packet(conn, pdata, packet->data_len);
1135 ipmi_mem_free(packet);
1136 continue;
1137 }
1138 }
1139 }
1140
1141 /**
1142 * Changes the currently recorded "state" for the SoL connection.
1143 *
1144 * Does nothing if the currently recorded state is the same as the new state.
1145 *
1146 * @param [in] conn The SoL connection
1147 * @param [in] state The new connection state
1148 * @param [in] error The error value to pass to callbacks that are listening
1149 * for connection state changes.
1150 */
1151 static void
ipmi_sol_set_connection_state(ipmi_sol_conn_t * conn,ipmi_sol_state new_state,int error)1152 ipmi_sol_set_connection_state(ipmi_sol_conn_t *conn,
1153 ipmi_sol_state new_state,
1154 int error)
1155 {
1156 if (conn->state == new_state)
1157 return;
1158
1159 if (new_state == ipmi_sol_state_closed) {
1160 transmitter_shutdown(&conn->transmitter, error);
1161 } else if (((new_state == ipmi_sol_state_connected)
1162 || (new_state == ipmi_sol_state_connected_ctu))
1163 && (conn->state == ipmi_sol_state_connecting))
1164 {
1165 int rv = transmitter_startup(&conn->transmitter);
1166 if (rv) {
1167 new_state = ipmi_sol_state_closed;
1168 error = rv;
1169 }
1170 }
1171
1172 conn->state = new_state;
1173
1174 if (conn->processing_packet) {
1175 sol_state_cb_info_t *sp = ipmi_mem_alloc(sizeof(*sp));
1176 if (!sp) {
1177 /* Yikes, no memory to store this. Just log and give up. */
1178 ipmi_log(IPMI_LOG_SEVERE,
1179 "ipmi_sol.c(ipmi_sol_set_connection_state): "
1180 "Could not allocate memory to queue state change.");
1181
1182 }
1183 sp->state = new_state;
1184 sp->error = error;
1185 sp->next = NULL;
1186 if (conn->waiting_states) {
1187 sol_state_cb_info_t *end = conn->waiting_states;
1188 while (end->next)
1189 end = end->next;
1190 end->next = sp;
1191 } else {
1192 conn->waiting_states = sp;
1193 }
1194 return;
1195 }
1196
1197 conn->processing_packet = 1;
1198 ipmi_unlock(conn->transmitter.packet_lock);
1199 do_connection_state_callbacks(conn, new_state, error);
1200 ipmi_lock(conn->transmitter.packet_lock);
1201
1202 /* See if some other thread stuck some packets in for me to
1203 process. Do that now. */
1204 process_waiting_packets(conn);
1205
1206 conn->processing_packet = 0;
1207 }
1208
1209
1210 /*****************************************************************************
1211 ** IPMI SoL write operations
1212 **/
1213
1214 #ifdef IPMI_SOL_DEBUG_TRANSMIT
1215 /**
1216 * Dump the transmitter state.
1217 */
1218 static void
dump_transmitter_queue_state(ipmi_sol_transmitter_context_t * transmitter)1219 dump_transmitter_queue_state(ipmi_sol_transmitter_context_t *transmitter)
1220 {
1221 /* DEBUG: Just dump the queue! */
1222 ipmi_lock(transmitter->queue_lock);
1223 printf("Outgoing queue: 0x%p\n", &transmitter->outgoing_queue);
1224 if (!transmitter->outgoing_queue)
1225 return;
1226
1227 printf(" head: 0x%p\n"
1228 " tail: 0x%p\n", transmitter->outgoing_queue.head,
1229 transmitter->outgoing_queue.tail
1230 );
1231
1232 printf("vvvvv Outgoing queue:\n");
1233 if (transmitter->outgoing_queue.head) {
1234 ipmi_sol_outgoing_queue_item_t *i = transmitter->outgoing_queue.head;
1235 while (i) {
1236 printf("%p -> %d chars at %p -> [", i, i->data_len, i->data);
1237 fflush(stdout);
1238 int j;
1239 for (j = 0; j < i->data_len; ++j)
1240 printf("%c", i->data[j]);
1241 printf("]\n"); fflush(stdout);
1242 i = i->next;
1243 }
1244 }
1245 else
1246 printf("is empty.");
1247
1248 ipmi_unlock(transmitter->queue_lock);
1249
1250 printf("^^^^^ Outgoing queue\n\n"); fflush(stdout);
1251 }
1252 #endif
1253
1254 static ipmi_sol_outgoing_packet_record_t *
transmitter_gather(ipmi_sol_transmitter_context_t * transmitter,int control_only)1255 transmitter_gather(ipmi_sol_transmitter_context_t *transmitter,
1256 int control_only)
1257 {
1258 int data_len = 0;
1259 unsigned char *ptr = &transmitter->scratch_area[0];
1260 ipmi_sol_outgoing_packet_record_t *new_packet_record = NULL;
1261 ipmi_sol_outgoing_queue_item_t *qi = transmitter->outgoing_queue.head;
1262 unsigned char ib_op = 0;
1263 unsigned int already_acked = transmitter->bytes_acked_at_head;
1264
1265 if ((control_only || !qi)
1266 && !transmitter->packet_to_acknowledge
1267 && !transmitter->op_callback_list)
1268 /*
1269 * Absolutely nothing to transmit.
1270 */
1271 return NULL;
1272
1273 if (!control_only) {
1274 /*
1275 * Do the data gather into the transmitter scratch area
1276 */
1277 while (qi && (data_len < transmitter->scratch_area_size)) {
1278 /*
1279 * Is this queue item a break?
1280 */
1281 if (0 == qi->data_len) {
1282 /*
1283 * It's a break... can we add it to this packet?
1284 */
1285 if (0 == data_len)
1286 ib_op |= IPMI_SOL_OPERATION_GENERATE_BREAK;
1287 else
1288 /*
1289 * The data packet endeth here, if we want the break
1290 * to occur at the right time (and we do...).
1291 */
1292 break;
1293 } else {
1294 /*
1295 * Data in this qi: Figure out how many chars we are going to
1296 * copy. Skip any bytes that the BMC has already ACKed,
1297 * then limit our copy to fit within the buffer space.
1298 */
1299 int copychars = qi->data_len - already_acked;
1300 if (copychars > transmitter->scratch_area_size - data_len)
1301 copychars = transmitter->scratch_area_size - data_len;
1302
1303 memcpy(ptr, &qi->data[already_acked], copychars);
1304 ptr += copychars;
1305 data_len += copychars;
1306 already_acked = 0;
1307 }
1308 qi = qi->next;
1309 }
1310 }
1311
1312 /*
1313 * There's something there to send. Allocate the structure that
1314 * holds the packet info
1315 */
1316 new_packet_record = ipmi_mem_alloc(sizeof(*new_packet_record));
1317 if (!new_packet_record)
1318 return NULL;
1319 memset(new_packet_record, 0, sizeof(*new_packet_record));
1320
1321 new_packet_record->packet_size = 4 + data_len;
1322
1323 new_packet_record->packet = ipmi_mem_alloc(new_packet_record->packet_size);
1324 if (!new_packet_record->packet) {
1325 ipmi_mem_free(new_packet_record);
1326 return NULL;
1327 }
1328
1329 /*
1330 * Put the control and ack/nack information into the packet
1331 */
1332 new_packet_record->packet[PACKET_ACK_NACK_SEQNR]
1333 = transmitter->packet_to_acknowledge;
1334 if (! (transmitter->oob_transient_op & IPMI_SOL_OPERATION_NACK_PACKET))
1335 /* We have to ack the packet if we nack it, leave it around
1336 for the release if we are nack-ing. */
1337 transmitter->packet_to_acknowledge = 0;
1338
1339 new_packet_record->packet[PACKET_ACCEPTED_CHARACTER_COUNT]
1340 = transmitter->accepted_character_count;
1341 transmitter->accepted_character_count = 0;
1342
1343 ipmi_lock(transmitter->oob_op_lock);
1344 new_packet_record->packet[PACKET_OP]
1345 = (transmitter->oob_transient_op | transmitter->oob_persistent_op
1346 | ib_op);
1347
1348 /* Transmitted NACK has to be cleared by the user */
1349 transmitter->oob_transient_op &= IPMI_SOL_OPERATION_NACK_PACKET;
1350
1351 new_packet_record->op_callback_list = transmitter->op_callback_list;
1352 transmitter->op_callback_list = NULL;
1353 ipmi_unlock(transmitter->oob_op_lock);
1354
1355 /*
1356 * Note here that control_only implies data_len==0.
1357 */
1358 new_packet_record->expecting_ACK = (data_len > 0);
1359
1360 if (new_packet_record->expecting_ACK) {
1361 /* Data-bearing packet; will be ACKed (hopefully), needs a
1362 sequence number and a retransmit count */
1363 new_packet_record->packet[PACKET_SEQNR]
1364 = transmitter->latest_outgoing_seqnr++;
1365 if (transmitter->latest_outgoing_seqnr > 15)
1366 transmitter->latest_outgoing_seqnr = 1;
1367
1368 new_packet_record->transmit_attempts_remaining
1369 = transmitter->sol_conn->ACK_retries;
1370
1371 /* Give it the data */
1372 memcpy(&new_packet_record->packet[PACKET_DATA],
1373 transmitter->scratch_area,
1374 data_len);
1375 } else {
1376 /* Zero sequence number for control-only packet */
1377 new_packet_record->packet[PACKET_SEQNR] = 0;
1378 }
1379
1380 new_packet_record->os_hnd = transmitter->sol_conn->ipmi->os_hnd;
1381
1382 return new_packet_record;
1383 }
1384
1385
1386 static void
do_outstanding_op_callbacks(ipmi_sol_transmitter_context_t * transmitter,int error)1387 do_outstanding_op_callbacks(ipmi_sol_transmitter_context_t *transmitter,
1388 int error)
1389 {
1390 callback_list_t *callbacks;
1391 callback_list_t *end;
1392 ipmi_sol_conn_t *conn = transmitter->sol_conn;
1393
1394 callbacks = transmitter->transmitted_packet->op_callback_list;
1395 if (!callbacks)
1396 return;
1397 transmitter->transmitted_packet->op_callback_list = NULL;
1398
1399 end = callbacks;
1400 while (!end) {
1401 end->error = error;
1402 end = end->next;
1403 }
1404
1405 if (conn->processing_packet) {
1406 if (conn->waiting_callbacks) {
1407 end = conn->waiting_callbacks;
1408 while (end->next)
1409 end = end->next;
1410 end->next = callbacks;
1411 } else {
1412 conn->waiting_callbacks = callbacks;
1413 }
1414 return;
1415 }
1416
1417 conn->processing_packet = 1;
1418 ipmi_unlock(transmitter->packet_lock);
1419 do_and_destroy_transmit_complete_callbacks(callbacks,
1420 transmitter->sol_conn);
1421 ipmi_lock(transmitter->packet_lock);
1422
1423 /* See if some other thread stuck some packets in for me to
1424 process. Do that now. */
1425 process_waiting_packets(conn);
1426
1427 conn->processing_packet = 0;
1428 }
1429
1430
1431 /**
1432 * Get rid of any packet that we've recently transmitted and still
1433 * have in storage.
1434 *
1435 * MUST be called with the packet_lock held.
1436 *
1437 * @param [in] transmitter The SoL transmitter
1438 * @param [in] error The error code to return to any callbacks
1439 * waiting on this packet or its data.
1440 */
1441 static void
dispose_of_outstanding_packet(ipmi_sol_transmitter_context_t * transmitter,int error)1442 dispose_of_outstanding_packet(ipmi_sol_transmitter_context_t *transmitter,
1443 int error)
1444 {
1445 os_handler_t *os_hnd;
1446 int rv = 0;
1447 ipmi_sol_outgoing_packet_record_t *packet
1448 = transmitter->transmitted_packet;
1449
1450 if (!packet)
1451 return;
1452
1453 if (packet->ack_timer) {
1454 os_hnd = transmitter->sol_conn->ipmi->os_hnd;
1455
1456 ipmi_lock(packet->timer_lock);
1457 if (packet->timer_running)
1458 rv = os_hnd->stop_timer(os_hnd, packet->ack_timer);
1459 if (! rv) {
1460 ipmi_unlock(packet->timer_lock);
1461 ipmi_destroy_lock(packet->timer_lock);
1462 os_hnd->free_timer(os_hnd, packet->ack_timer);
1463 } else {
1464 /* Tell the timer handler to throw the packet away, since
1465 it's about to run. */
1466 packet->deleted = 1;
1467 ipmi_unlock(packet->timer_lock);
1468 packet = NULL;
1469 }
1470 }
1471
1472 do_outstanding_op_callbacks(transmitter, error);
1473
1474 if (packet) {
1475 if (packet->packet)
1476 ipmi_mem_free(packet->packet);
1477
1478 ipmi_mem_free(packet);
1479 }
1480 transmitter->transmitted_packet = NULL;
1481 }
1482
1483 /*
1484 * Must be called with the packet lock held.
1485 */
1486 static int
transmit_outstanding_packet(ipmi_sol_transmitter_context_t * transmitter)1487 transmit_outstanding_packet(ipmi_sol_transmitter_context_t *transmitter)
1488 {
1489 int rv;
1490 /*
1491 * Pack the packet into a pseudo-IPMI message.
1492 */
1493 ipmi_msg_t msg;
1494 ipmi_con_option_t options[3];
1495 int curr_opt = 0;
1496 ipmi_sol_conn_t *conn = transmitter->sol_conn;
1497
1498 options[curr_opt].option = IPMI_CON_MSG_OPTION_CONF;
1499 options[curr_opt].ival = ipmi_sol_get_use_encryption(conn);
1500 curr_opt++;
1501 options[curr_opt].option = IPMI_CON_MSG_OPTION_AUTH;
1502 options[curr_opt].ival = ipmi_sol_get_use_authentication(conn);
1503 curr_opt++;
1504 options[curr_opt].option = IPMI_CON_OPTION_LIST_END;
1505
1506 msg.netfn = 1;
1507 msg.cmd = 0;
1508 msg.data = (unsigned char *)transmitter->transmitted_packet->packet;
1509 msg.data_len = transmitter->transmitted_packet->packet_size;
1510
1511 #ifdef IPMI_SOL_DEBUG_TRANSMIT
1512 printf("Sending a packet! %d bytes: ",
1513 transmitter->transmitted_packet->packet_size);
1514 dump_hex(msg.data, msg.data_len);
1515 printf("That's it!\n");
1516 fflush(stdout);
1517 #endif
1518
1519 /*
1520 * And fire it off!
1521 */
1522 rv = conn->ipmid->send_command_option
1523 (conn->ipmi,
1524 (ipmi_addr_t *)&transmitter->sol_conn->sol_payload_addr,
1525 sizeof(transmitter->sol_conn->sol_payload_addr),
1526 &msg,
1527 options,
1528 NULL, NULL);
1529
1530 if (rv) {
1531 char buf[50];
1532 ipmi_log(IPMI_LOG_WARNING, "ipmi_sol.c(transmit_outstanding_packet): "
1533 "ipmi_send_command_addr: [%s]",
1534 ipmi_get_error_string(rv, buf, 50));
1535 dispose_of_outstanding_packet(transmitter, rv);
1536 }
1537 return rv;
1538 }
1539
1540
1541 /**
1542 * Handle expiration of the timer for a packet ACK.
1543 */
1544 static void sol_ACK_timer_expired(void *cb_data, os_hnd_timer_id_t *id);
1545
1546 static int
setup_ACK_timer(ipmi_sol_transmitter_context_t * transmitter)1547 setup_ACK_timer(ipmi_sol_transmitter_context_t *transmitter)
1548 {
1549 struct timeval timeout;
1550 os_handler_t *os_hnd;
1551 int rv;
1552 ipmi_sol_outgoing_packet_record_t *packet
1553 = transmitter->transmitted_packet;
1554
1555 os_hnd = transmitter->sol_conn->ipmi->os_hnd;
1556
1557 ipmi_lock(packet->timer_lock);
1558 if (packet->timer_running) {
1559 ipmi_unlock(packet->timer_lock);
1560 ipmi_log(IPMI_LOG_WARNING, "ipmi_sol.c(setup_ACK_timer): "
1561 "Timer start when timer was already running");
1562 return 0;
1563 }
1564 timeout.tv_sec = transmitter->sol_conn->ACK_timeout_usec / 1000000;
1565 timeout.tv_usec = transmitter->sol_conn->ACK_timeout_usec % 1000000;
1566
1567 rv = os_hnd->start_timer(os_hnd,
1568 packet->ack_timer,
1569 &timeout,
1570 sol_ACK_timer_expired,
1571 packet);
1572 if (!rv)
1573 packet->timer_running = 1;
1574 ipmi_unlock(packet->timer_lock);
1575 return rv;
1576 }
1577
1578 static void
sol_ACK_timer_expired(void * cb_data,os_hnd_timer_id_t * id)1579 sol_ACK_timer_expired(void *cb_data, os_hnd_timer_id_t *id)
1580 {
1581 ipmi_sol_transmitter_context_t *transmitter;
1582 ipmi_sol_conn_t *conn;
1583 ipmi_sol_outgoing_packet_record_t *packet = cb_data;
1584
1585 #ifdef SOL_DEBUG_TRANSMIT
1586 printf("sol_ACK_timer_expired!\n");
1587 #endif
1588
1589 ipmi_lock(packet->timer_lock);
1590 if (packet->deleted) {
1591 /* Packet was deleted while the timer was going off, just
1592 delete and return here. */
1593 ipmi_unlock(packet->timer_lock);
1594 if (packet->packet)
1595 ipmi_mem_free(packet->packet);
1596 ipmi_destroy_lock(packet->timer_lock);
1597 packet->os_hnd->free_timer(packet->os_hnd, packet->ack_timer);
1598 ipmi_mem_free(packet);
1599 return;
1600 }
1601 packet->timer_running = 0;
1602 ipmi_unlock(packet->timer_lock);
1603
1604 /* Get a refcount to the connection. */
1605 conn = find_sol_connection(packet->conn);
1606 if (!conn)
1607 return;
1608
1609 transmitter = &conn->transmitter;
1610
1611 ipmi_lock(transmitter->packet_lock);
1612
1613 if (transmitter->transmitted_packet != packet)
1614 /* OK, the packet was ACKed, it seems... */
1615 goto out_unlock;
1616
1617 packet->transmit_attempts_remaining--;
1618 if (packet->transmit_attempts_remaining == 0) {
1619 /*
1620 * Didn't get a response even after retries... connection is lost.
1621 */
1622 ipmi_sol_set_connection_state(transmitter->sol_conn,
1623 ipmi_sol_state_closed,
1624 IPMI_SOL_ERR_VAL(IPMI_SOL_DISCONNECTED));
1625 } else {
1626 int rv;
1627
1628 transmit_outstanding_packet(transmitter);
1629 rv = setup_ACK_timer(transmitter);
1630 if (rv) {
1631 char buf[50];
1632 ipmi_log(IPMI_LOG_WARNING, "ipmi_sol.c(sol_ACK_timer_expired): "
1633 "Unable to setup_ACK_timer: %s",
1634 ipmi_get_error_string(rv, buf, 50));
1635 dispose_of_outstanding_packet(transmitter, rv);
1636 /* FIXME: What is the right error value? */
1637 }
1638 }
1639 out_unlock:
1640 ipmi_unlock(transmitter->packet_lock);
1641 sol_put_connection(conn);
1642 }
1643
1644
1645 static void transmitter_handle_acknowledge(ipmi_sol_conn_t *conn,
1646 int error,
1647 int cknowledged_char_count);
1648
1649 /**
1650 * Causes the transmitter to examine its transmit queue and to prepare a packet
1651 * for transmission if needed.
1652 *
1653 * Anything that gives the transmitter something to transmit (data or control)
1654 * should call this.
1655 *
1656 * Must be called with the packet lock held.
1657 */
1658 static void
transmitter_prod_nolock(ipmi_sol_transmitter_context_t * transmitter)1659 transmitter_prod_nolock(ipmi_sol_transmitter_context_t *transmitter)
1660 {
1661 ipmi_sol_outgoing_packet_record_t *packet;
1662
1663 /*
1664 * TODO: If we are awaiting an ACK and we get a data packet from
1665 * the remote system that doesn't ACK our outstanding packet,
1666 * perhaps we should be able to send back an ACK (and control)
1667 * packet immediately??? If so, we should keep going here, and
1668 * later call transmitter_gather(transmitter, 1) to collect a
1669 * strictly control-only packet (no BREAKs, either!).
1670 */
1671 if (transmitter->transmitted_packet) {
1672 #ifdef IPMI_SOL_DEBUG_TRANSMIT
1673 ipmi_log(IPMI_LOG_INFO, "ipmi_sol.c(transmitter_prod_nolock): "
1674 "exiting early:"
1675 " already waiting for an ACK.");
1676 #endif
1677 return;
1678 }
1679
1680 #ifdef IPMI_SOL_DEBUG_TRANSMIT
1681 dump_transmitter_queue_state(transmitter);
1682 #endif
1683
1684 /* TODO: PREFERABLY this should happen next time we enter the event
1685 * loop, not right away! This will allow for control and character
1686 * accumulation in a reasonable way. Think Nagling (!TCP_NODELAY). */
1687
1688 if (! transmitter->transmitted_packet)
1689 transmitter->transmitted_packet = transmitter_gather(transmitter, 0);
1690 packet = transmitter->transmitted_packet;
1691
1692 if (packet) {
1693 int rv = 0;
1694
1695 if (packet->expecting_ACK) {
1696 os_handler_t *os_hnd = transmitter->sol_conn->ipmi->os_hnd;
1697
1698 packet->conn = transmitter->sol_conn;
1699 rv = ipmi_create_lock_os_hnd(os_hnd, &packet->timer_lock);
1700 if (rv)
1701 goto handle_err;
1702 rv = os_hnd->alloc_timer(os_hnd, &packet->ack_timer);
1703 if (rv) {
1704 ipmi_destroy_lock(packet->timer_lock);
1705 goto handle_err;
1706 }
1707 packet->timer_running = 0;
1708 }
1709
1710 if (!rv)
1711 rv = transmit_outstanding_packet(transmitter);
1712
1713 handle_err:
1714 if (rv) {
1715 dispose_of_outstanding_packet(transmitter, rv);
1716 return;
1717 }
1718
1719 if (transmitter->transmitted_packet->expecting_ACK) {
1720 rv = setup_ACK_timer(transmitter);
1721 if (rv) {
1722 char buf[50];
1723 ipmi_log(IPMI_LOG_WARNING,
1724 "ipmi_sol.c(transmitter_prod_nolock): "
1725 "Unable to setup_ACK_timer: %s",
1726 ipmi_get_error_string(rv, buf, 50));
1727 dispose_of_outstanding_packet(transmitter, rv);
1728 /* FIXME: What is the right error value? */
1729 }
1730 } else {
1731 /*
1732 * This packet won't get an acknowledgement! Dispose of
1733 * it NOW, and do its callbacks.
1734 */
1735 int errval = IPMI_SOL_ERR_VAL(IPMI_SOL_UNCONFIRMABLE_OPERATION);
1736 transmitter_handle_acknowledge(transmitter->sol_conn, errval, 0);
1737
1738 dispose_of_outstanding_packet(transmitter, errval);
1739 }
1740 }
1741 }
1742
1743 /**
1744 * Lock and call transmitter_prod_nolock()
1745 */
1746 static void
transmitter_prod(ipmi_sol_transmitter_context_t * transmitter)1747 transmitter_prod(ipmi_sol_transmitter_context_t *transmitter)
1748 {
1749 ipmi_lock(transmitter->packet_lock);
1750 transmitter_prod_nolock(transmitter);
1751 ipmi_unlock(transmitter->packet_lock);
1752 }
1753
1754 /**
1755 * Remove a packet from the head of the queue. This should be called
1756 * only after an ACK has been received or it has been determined that
1757 * the packet will never be ACKed.
1758 */
1759 static void
dequeue_head(ipmi_sol_transmitter_context_t * transmitter,int error)1760 dequeue_head(ipmi_sol_transmitter_context_t *transmitter, int error)
1761 {
1762 ipmi_sol_outgoing_queue_item_t *qitem;
1763
1764 transmitter->bytes_acked_at_head = 0;
1765 qitem = transmitter->outgoing_queue.head;
1766
1767 if (qitem) {
1768 if (qitem->transmit_complete_callback) {
1769 ipmi_unlock(transmitter->queue_lock);
1770 ipmi_unlock(transmitter->packet_lock);
1771 (qitem->transmit_complete_callback)(transmitter->sol_conn,
1772 error, qitem->cb_data);
1773 ipmi_lock(transmitter->packet_lock);
1774 ipmi_lock(transmitter->queue_lock);
1775 }
1776 if (qitem->data)
1777 ipmi_mem_free(qitem->data);
1778
1779 transmitter->outgoing_queue.head = qitem->next;
1780 ipmi_mem_free(qitem);
1781
1782 /* Deleting the last packet in the list? */
1783 if (NULL == transmitter->outgoing_queue.head)
1784 transmitter->outgoing_queue.tail = NULL;
1785 }
1786 }
1787
1788
1789 /**
1790 * Remove all outgoing packets queued on the given transmitter.
1791 *
1792 * @param [in] transmitter The transmitter to be flushed.
1793 */
1794 static void
transmitter_flush_outbound(ipmi_sol_transmitter_context_t * transmitter,int error)1795 transmitter_flush_outbound(ipmi_sol_transmitter_context_t *transmitter,
1796 int error)
1797 {
1798 dispose_of_outstanding_packet(transmitter, error);
1799
1800 ipmi_lock(transmitter->queue_lock);
1801 while (transmitter->outgoing_queue.head)
1802 dequeue_head(transmitter, error);
1803 ipmi_unlock(transmitter->queue_lock);
1804 }
1805
1806
1807 /**
1808 * Handle the acknowledgement of the given number of characters.
1809 * Note that acknowledged_character_count might be zero, if and only
1810 * if we have just sent out a packet with a BREAK and no data (in which
1811 * case, incidentally, "error" will be IPMI_SOL_UNCONFIRMABLE_OPERATION), and
1812 * we must dequeue the break only.
1813 */
1814 static void
transmitter_handle_acknowledge(ipmi_sol_conn_t * conn,int error,int acknowledged_char_count)1815 transmitter_handle_acknowledge(ipmi_sol_conn_t *conn,
1816 int error,
1817 int acknowledged_char_count)
1818 {
1819 ipmi_sol_outgoing_queue_item_t *qitem;
1820
1821 /*
1822 * Handle the in-band data by iterating through packets, and:
1823 * 1) Counting off how many bytes of this packet have been ACKed,
1824 * 2) When a packet is done, calling the IB callbacks, then disposing
1825 * of it.
1826 */
1827 #ifdef IPMI_SOL_DEBUG_RECEIVE
1828 ipmi_log(IPMI_LOG_INFO, "Received ACK for %d chars",
1829 acknowledged_char_count);
1830 #endif
1831
1832 do {
1833 int avail_this_pkt;
1834 int this_ack;
1835
1836 qitem = conn->transmitter.outgoing_queue.head;
1837 if (!qitem) {
1838 if (acknowledged_char_count) {
1839 /*
1840 * The BMC has acknowledged more than we've sent!
1841 */
1842 ipmi_log(IPMI_LOG_WARNING,
1843 "ipmi_sol.c(transmitter_handle_acknowledge): "
1844 "The BMC has acknowledged more data than we sent."
1845 " Ignoring excess ACK.");
1846 }
1847 return;
1848 }
1849
1850 /*
1851 * This will also work for BREAKs, stored as a zero-length transmit
1852 * request. They will be dequeued if they are at the start of the
1853 * queue for this ACK. They will also be dequeued if they are mid-
1854 * queue for this ACK, but that SHOULD never occur. They will
1855 * NOT be dequeued if they are directly after the last completely
1856 * ACKed request. This also means that should two BREAKs be queued
1857 * consecutively, only the first one will be dequeued if
1858 * acknowledged_char_count is zero.
1859 */
1860
1861 avail_this_pkt = (qitem->data_len
1862 - conn->transmitter.bytes_acked_at_head);
1863 if (avail_this_pkt < acknowledged_char_count)
1864 this_ack = avail_this_pkt;
1865 else
1866 this_ack = acknowledged_char_count;
1867
1868 conn->transmitter.bytes_acked_at_head += this_ack;
1869 if (conn->transmitter.bytes_acked_at_head == qitem->data_len) {
1870 /*
1871 * This packet is DONE.
1872 */
1873 ipmi_lock(conn->transmitter.queue_lock);
1874 dequeue_head(&conn->transmitter, error);
1875 ipmi_unlock(conn->transmitter.queue_lock);
1876 }
1877
1878 acknowledged_char_count -= this_ack;
1879 } while (acknowledged_char_count > 0);
1880
1881 /*
1882 * Thus endeth the ACKing game.
1883 */
1884 }
1885
1886
1887 /**
1888 * Creates a new transmitter tail packet and adds it to the transmit queue.
1889 *
1890 * If count > 0, the given data bytes are added to the queue. If count == 0,
1891 * this means a serial "break" to the transmitter.
1892 */
1893 static int
add_to_transmit_queue(ipmi_sol_transmitter_context_t * tx,const void * buf,int count,unsigned char ib_op,ipmi_sol_transmit_complete_cb cb,void * cb_data)1894 add_to_transmit_queue(ipmi_sol_transmitter_context_t *tx,
1895 const void *buf,
1896 int count,
1897 unsigned char ib_op,
1898 ipmi_sol_transmit_complete_cb cb,
1899 void *cb_data)
1900 {
1901 ipmi_sol_outgoing_queue_item_t *new_tail;
1902
1903 #ifdef IPMI_SOL_DEBUG_TRANSMIT
1904 dump_transmitter_queue_state(tx);
1905 #endif
1906
1907 new_tail = ipmi_mem_alloc(sizeof(*new_tail));
1908 if (!new_tail)
1909 return ENOMEM;
1910
1911 if (count) {
1912 new_tail->data = ipmi_mem_alloc(count);
1913 if (!new_tail->data) {
1914 ipmi_mem_free(new_tail);
1915 return ENOMEM;
1916 }
1917
1918 memcpy(new_tail->data, buf, count);
1919 } else
1920 new_tail->data = NULL;
1921
1922 new_tail->data_len = count;
1923 new_tail->ib_op = ib_op;
1924 new_tail->transmit_complete_callback = cb;
1925 new_tail->cb_data = cb_data;
1926 new_tail->next = NULL;
1927
1928 ipmi_lock(tx->queue_lock);
1929
1930 if (tx->outgoing_queue.tail)
1931 tx->outgoing_queue.tail->next = new_tail;
1932
1933 tx->outgoing_queue.tail = new_tail;
1934
1935 /* Adding to a previously empty list? */
1936 if (!tx->outgoing_queue.head)
1937 tx->outgoing_queue.head = new_tail;
1938
1939 ipmi_unlock(tx->queue_lock);
1940
1941 transmitter_prod_nolock(tx);
1942
1943 return 0;
1944 }
1945
1946 /*
1947 * Must be called with oob_op_lock held.
1948 */
1949 static int
add_op_control_callback(ipmi_sol_transmitter_context_t * tx,ipmi_sol_transmit_complete_cb cb,void * cb_data)1950 add_op_control_callback(ipmi_sol_transmitter_context_t *tx,
1951 ipmi_sol_transmit_complete_cb cb,
1952 void *cb_data)
1953 {
1954 callback_list_t *new_entry;
1955 callback_list_t *iter = tx->op_callback_list;
1956
1957 new_entry = ipmi_mem_alloc(sizeof(*new_entry));
1958 if (!new_entry)
1959 return ENOMEM;
1960
1961 new_entry->cb = cb;
1962 new_entry->cb_data = cb_data;
1963 new_entry->next = NULL;
1964
1965 if (!iter) {
1966 tx->op_callback_list = new_entry;
1967 } else {
1968 while (NULL != iter->next)
1969 iter = iter->next;
1970
1971 /*
1972 * iter points to the end of the list.
1973 */
1974 iter->next = new_entry;
1975 }
1976 return 0;
1977 }
1978
1979 static int
transmitter_startup(ipmi_sol_transmitter_context_t * transmitter)1980 transmitter_startup(ipmi_sol_transmitter_context_t *transmitter)
1981 {
1982 transmitter->scratch_area = ipmi_mem_alloc(transmitter->scratch_area_size);
1983 if (!transmitter->scratch_area) {
1984 /* Alloc failed! */
1985 ipmi_log(IPMI_LOG_SEVERE, "ipmi_sol.c(transmitter_startup): "
1986 "Insufficient memory for transmitter scratch area.");
1987
1988 return ENOMEM;
1989 }
1990
1991 return 0;
1992 }
1993
1994 static void
transmitter_shutdown(ipmi_sol_transmitter_context_t * transmitter,int error)1995 transmitter_shutdown(ipmi_sol_transmitter_context_t *transmitter, int error)
1996 {
1997 transmitter_flush_outbound(transmitter, error);
1998
1999 /* Free the memory being used by sundry parts */
2000 if (transmitter->scratch_area) {
2001 ipmi_mem_free(transmitter->scratch_area);
2002 transmitter->scratch_area = NULL;
2003 }
2004 }
2005
2006
2007 /*
2008 * ipmi_sol_write -
2009 *
2010 * Send a sequence of bytes to the remote.
2011 * buf - the bytes to send.
2012 * count - the number of bytes to send from the buffer.
2013 * This function (like all the others!) will either return an ERROR
2014 * and never call the callback, or will return no error and then WILL
2015 * call the callback, indicating an error later if necessary. The
2016 * callback is an indication that the BMC has ACKed *all* of the bytes
2017 * in this request. There is no guarantee that the packet will not be
2018 * fragmented or coalesced in transmission.
2019 */
2020 int
ipmi_sol_write(ipmi_sol_conn_t * conn,const void * buf,int count,ipmi_sol_transmit_complete_cb cb,void * cb_data)2021 ipmi_sol_write(ipmi_sol_conn_t *conn,
2022 const void *buf,
2023 int count,
2024 ipmi_sol_transmit_complete_cb cb,
2025 void *cb_data)
2026 {
2027 int rv;
2028
2029 if (count <= 0)
2030 return EINVAL;
2031
2032 ipmi_lock(conn->transmitter.packet_lock);
2033 if ((conn->state == ipmi_sol_state_connected)
2034 || (conn->state == ipmi_sol_state_connected_ctu))
2035 {
2036 rv = add_to_transmit_queue(&conn->transmitter, buf, count, 0,
2037 cb, cb_data);
2038 } else {
2039 rv = EINVAL;
2040 }
2041 ipmi_unlock(conn->transmitter.packet_lock);
2042 return rv;
2043 }
2044
2045
2046 /*
2047 * ipmi_sol_release_nack -
2048 *
2049 * Remove any pending nacks.
2050 */
2051 int
ipmi_sol_release_nack(ipmi_sol_conn_t * conn)2052 ipmi_sol_release_nack(ipmi_sol_conn_t *conn)
2053 {
2054 int rv = 0;
2055
2056 ipmi_lock(conn->transmitter.packet_lock);
2057 if (conn->transmitter.in_recv_cb) {
2058 /* Raced with the receive callback, just mark it for the
2059 receive callback to handle. */
2060 conn->transmitter.nack_count--;
2061 goto out;
2062 }
2063 if (! conn->transmitter.nack_count) {
2064 /* Nothing to NACK. */
2065 rv = EINVAL;
2066 goto out;
2067 }
2068 conn->transmitter.nack_count--;
2069 if (! conn->transmitter.nack_count) {
2070 /* Time to kick things off again. */
2071 conn->transmitter.oob_transient_op &= ~IPMI_SOL_OPERATION_NACK_PACKET;
2072
2073 /* This is here just in case we decide that the accepted
2074 character count in a NACK packet is the number of bytes
2075 nack-ed. */
2076 conn->transmitter.accepted_character_count = 0;
2077 transmitter_prod_nolock(&conn->transmitter);
2078 }
2079 out:
2080 ipmi_unlock(conn->transmitter.packet_lock);
2081 return rv;
2082 }
2083
2084 /*
2085 * ipmi_sol_send_break -
2086 *
2087 * See ipmi_sol_write, except we're not sending any bytes, just a
2088 * serial "break". Callback contract is the same as for
2089 * ipmi_sol_write.
2090 */
2091 int
ipmi_sol_send_break(ipmi_sol_conn_t * conn,ipmi_sol_transmit_complete_cb cb,void * cb_data)2092 ipmi_sol_send_break(ipmi_sol_conn_t *conn,
2093 ipmi_sol_transmit_complete_cb cb,
2094 void *cb_data)
2095 {
2096 int rv;
2097
2098 ipmi_lock(conn->transmitter.packet_lock);
2099 if ((conn->state == ipmi_sol_state_connected)
2100 || (conn->state == ipmi_sol_state_connected_ctu))
2101 {
2102 rv = add_to_transmit_queue(&conn->transmitter, NULL, 0,
2103 IPMI_SOL_OPERATION_GENERATE_BREAK,
2104 cb, cb_data);
2105 } else
2106 rv = EINVAL;
2107 ipmi_unlock(conn->transmitter.packet_lock);
2108 return rv;
2109 }
2110
2111
2112 /*
2113 * ipmi_sol_set_CTS_assertable -
2114 *
2115 * Asserts CTS at the BMC, to request that the system attached to the
2116 * BMC ceases transmitting characters. No guarantee is given that the
2117 * BMC will honour this request. Further buffered characters might
2118 * still be received after CTS is asserted. See ipmi_sol_write,
2119 * except we're not sending any bytes, just changing control lines.
2120 * Callback contract is the same as for ipmi_sol_write.
2121 */
2122 int
ipmi_sol_set_CTS_assertable(ipmi_sol_conn_t * conn,int assertable,ipmi_sol_transmit_complete_cb cb,void * cb_data)2123 ipmi_sol_set_CTS_assertable(ipmi_sol_conn_t *conn,
2124 int assertable,
2125 ipmi_sol_transmit_complete_cb cb,
2126 void *cb_data)
2127 {
2128 int rv;
2129
2130 ipmi_lock(conn->transmitter.packet_lock);
2131 if ((conn->state == ipmi_sol_state_connected)
2132 || (conn->state == ipmi_sol_state_connected_ctu))
2133 {
2134 ipmi_lock(conn->transmitter.oob_op_lock);
2135 if (assertable)
2136 conn->transmitter.oob_persistent_op
2137 &= ~IPMI_SOL_OPERATION_CTS_PAUSE;
2138 else
2139 conn->transmitter.oob_persistent_op
2140 |= IPMI_SOL_OPERATION_CTS_PAUSE;
2141
2142 rv = add_op_control_callback(&conn->transmitter, cb, cb_data);
2143 ipmi_unlock(conn->transmitter.oob_op_lock);
2144
2145 if (!rv)
2146 transmitter_prod(&conn->transmitter);
2147 } else
2148 rv = EINVAL;
2149 ipmi_unlock(conn->transmitter.packet_lock);
2150
2151 return rv;
2152 }
2153
2154
2155 /*
2156 * ipmi_sol_set_DCD_DSR_asserted -
2157 *
2158 * Asserts DCD and DSR, as if we've answered the phone line.
2159 *
2160 * See ipmi_sol_write, except we're not sending any bytes, just
2161 * changing control lines. Callback contract is the same as for
2162 * ipmi_sol_write.
2163 */
2164 int
ipmi_sol_set_DCD_DSR_asserted(ipmi_sol_conn_t * conn,int asserted,ipmi_sol_transmit_complete_cb cb,void * cb_data)2165 ipmi_sol_set_DCD_DSR_asserted(ipmi_sol_conn_t *conn,
2166 int asserted,
2167 ipmi_sol_transmit_complete_cb cb,
2168 void *cb_data)
2169 {
2170 int rv;
2171
2172 ipmi_lock(conn->transmitter.packet_lock);
2173 if ((conn->state == ipmi_sol_state_connected)
2174 || (conn->state == ipmi_sol_state_connected_ctu))
2175 {
2176 ipmi_lock(conn->transmitter.oob_op_lock);
2177 if (asserted)
2178 conn->transmitter.oob_persistent_op
2179 &= ~IPMI_SOL_OPERATION_DROP_DCD_DSR;
2180 else
2181 conn->transmitter.oob_persistent_op
2182 |= IPMI_SOL_OPERATION_DROP_DCD_DSR;
2183
2184 rv = add_op_control_callback(&conn->transmitter, cb, cb_data);
2185 ipmi_unlock(conn->transmitter.oob_op_lock);
2186
2187 if (!rv)
2188 transmitter_prod(&conn->transmitter);
2189 } else
2190 rv = EINVAL;
2191 ipmi_unlock(conn->transmitter.packet_lock);
2192
2193 return rv;
2194 }
2195
2196
2197 /*
2198 * ipmi_sol_set_RI_asserted -
2199 *
2200 * Asserts RI, as if the phone line is ringing.
2201 *
2202 * See ipmi_sol_write, except we're not sending any bytes, just
2203 * changing control lines. Callback contract is the same as for
2204 * ipmi_sol_write.
2205 */
2206 int
ipmi_sol_set_RI_asserted(ipmi_sol_conn_t * conn,int asserted,ipmi_sol_transmit_complete_cb cb,void * cb_data)2207 ipmi_sol_set_RI_asserted(ipmi_sol_conn_t *conn,
2208 int asserted,
2209 ipmi_sol_transmit_complete_cb cb,
2210 void *cb_data)
2211 {
2212 int rv;
2213
2214 ipmi_lock(conn->transmitter.packet_lock);
2215 if ((conn->state == ipmi_sol_state_connected)
2216 || (conn->state == ipmi_sol_state_connected_ctu))
2217 {
2218 ipmi_lock(conn->transmitter.oob_op_lock);
2219 if (asserted)
2220 conn->transmitter.oob_persistent_op
2221 |= IPMI_SOL_OPERATION_RING_REQUEST;
2222 else
2223 conn->transmitter.oob_persistent_op
2224 &= ~IPMI_SOL_OPERATION_RING_REQUEST;
2225
2226 rv = add_op_control_callback(&conn->transmitter, cb, cb_data);
2227 ipmi_unlock(conn->transmitter.oob_op_lock);
2228
2229 if (!rv)
2230 transmitter_prod(&conn->transmitter);
2231 } else
2232 rv = EINVAL;
2233 ipmi_unlock(conn->transmitter.packet_lock);
2234
2235 return rv;
2236 }
2237
2238
2239 /**
2240 * Requests a flush of the transmit queue(s) identified by
2241 * queue_selector, which is a bitwise-OR of the following:
2242 *
2243 * IPMI_SOL_BMC_TRANSMIT_QUEUE
2244 * IPMI_SOL_BMC_RECEIVE_QUEUE
2245 * IPMI_SOL_MANAGEMENT_CONSOLE_TRANSMIT_QUEUE
2246 * IPMI_SOL_MANAGEMENT_CONSOLE_RECEIVE_QUEUE
2247 *
2248 * This operation will never use the callback if it returns an error.
2249 *
2250 * If no error is returned, the callback will be called in a
2251 * synchronous fashion if it does not involve the BMC, asynchronous
2252 * otherwise.
2253 */
2254
2255 typedef struct ipmi_sol_flush_data_s {
2256 ipmi_sol_conn_t *conn;
2257 int selectors_flushed;
2258 int selectors_pending;
2259 ipmi_sol_flush_complete_cb cb;
2260 void *cb_data;
2261 } ipmi_sol_flush_data_t;
2262
2263
2264 static void
flush_finalize(ipmi_sol_conn_t * conn,int error,void * cb_data)2265 flush_finalize(ipmi_sol_conn_t *conn, int error, void *cb_data)
2266 {
2267 ipmi_sol_flush_data_t *my = (ipmi_sol_flush_data_t *)cb_data;
2268
2269 /*
2270 * Did the remote flush go OK?
2271 */
2272 if (!error) {
2273 /*
2274 * Yep, the BMC has confirmed that the data has been flushed (or
2275 * at least no error has occurred).
2276 */
2277 my->selectors_flushed |= my->selectors_pending;
2278 }
2279
2280 if (my->cb)
2281 my->cb(conn, error, my->selectors_flushed, my->cb_data);
2282
2283 ipmi_mem_free(cb_data);
2284 }
2285
2286
2287 int
ipmi_sol_flush(ipmi_sol_conn_t * conn,int queue_selectors,ipmi_sol_flush_complete_cb cb,void * cb_data)2288 ipmi_sol_flush(ipmi_sol_conn_t *conn,
2289 int queue_selectors,
2290 ipmi_sol_flush_complete_cb cb,
2291 void *cb_data)
2292 {
2293 int rv = 0;
2294 int need_callback = 0;
2295
2296 ipmi_lock(conn->transmitter.packet_lock);
2297 if ((conn->state != ipmi_sol_state_connected)
2298 && (conn->state != ipmi_sol_state_connected_ctu))
2299 {
2300 ipmi_unlock(conn->transmitter.packet_lock);
2301 return EINVAL;
2302 }
2303
2304 /*
2305 * Do we flush the local transmit queue?
2306 */
2307 if (!rv
2308 && (! (queue_selectors & IPMI_SOL_MANAGEMENT_CONSOLE_TRANSMIT_QUEUE)))
2309 {
2310 transmitter_flush_outbound(&conn->transmitter,
2311 IPMI_SOL_ERR_VAL(IPMI_SOL_FLUSHED));
2312 }
2313
2314 /*
2315 * Do we flush the local receive queue?
2316 */
2317 if (!rv
2318 && (! (queue_selectors & IPMI_SOL_MANAGEMENT_CONSOLE_RECEIVE_QUEUE)))
2319 {
2320 /* We don't HAVE a local RX queue... */
2321 /*VOID*/
2322 }
2323
2324 ipmi_lock(conn->transmitter.oob_op_lock);
2325 /*
2326 * Do we flush the remote transmit queue?
2327 */
2328 if (!rv && (! (queue_selectors & IPMI_SOL_BMC_TRANSMIT_QUEUE))) {
2329 conn->transmitter.oob_transient_op
2330 |= IPMI_SOL_OPERATION_FLUSH_BMC_TO_CONSOLE;
2331 need_callback = 1;
2332 }
2333
2334 /*
2335 * Do we flush the remote receive queue?
2336 */
2337 if (!rv && (! (queue_selectors & IPMI_SOL_BMC_RECEIVE_QUEUE))) {
2338 conn->transmitter.oob_transient_op
2339 |= IPMI_SOL_OPERATION_FLUSH_CONSOLE_TO_BMC;
2340 need_callback = 1;
2341 }
2342
2343 if (need_callback) {
2344 ipmi_sol_flush_data_t *flush_data;
2345
2346 flush_data = ipmi_mem_alloc(sizeof(*flush_data));
2347
2348 flush_data->cb = cb;
2349 flush_data->cb_data = cb_data;
2350
2351 /* FIXME - the below two had &&, not &. I assumed that was wrong. */
2352 flush_data->selectors_flushed
2353 = queue_selectors & IPMI_SOL_MANAGEMENT_CONSOLE_QUEUES;
2354 flush_data->selectors_pending = queue_selectors & IPMI_SOL_BMC_QUEUES;
2355
2356 rv = add_op_control_callback(&conn->transmitter, flush_finalize,
2357 flush_data);
2358 ipmi_unlock(conn->transmitter.oob_op_lock);
2359
2360 transmitter_prod(&conn->transmitter);
2361 } else {
2362 ipmi_unlock(conn->transmitter.oob_op_lock);
2363 }
2364
2365 ipmi_unlock(conn->transmitter.packet_lock);
2366 return rv;
2367 }
2368
2369
2370 /********************************************************
2371 ** IPMI SoL API
2372 *******************************************************/
2373
2374
2375 /**
2376 * Constructs a handle for managing an SoL session.
2377 *
2378 * This function does NOT communicate with the BMC or activate the SoL payload.
2379 *
2380 * @param [in] ipmi the existing IPMI over LAN session.
2381 * @param [out] sol_conn the address into which to store the allocated
2382 * IPMI SoL connection structure.
2383 * @return zero on success, or ENOMEM if memory allocation fails.
2384 */
2385 int
ipmi_sol_create(ipmi_con_t * ipmi,ipmi_sol_conn_t ** sol_conn)2386 ipmi_sol_create(ipmi_con_t *ipmi,
2387 ipmi_sol_conn_t **sol_conn)
2388 {
2389 ipmi_sol_conn_t *new_conn;
2390 os_handler_t *os_hnd = ipmi->os_hnd;
2391 ipmi_sol_transmitter_context_t *xmitter;
2392 int rv;
2393
2394 new_conn = ipmi_mem_alloc(sizeof(*new_conn));
2395 if (!new_conn)
2396 return ENOMEM;
2397
2398 memset(new_conn, 0, sizeof(*new_conn));
2399
2400 new_conn->refcount = 1;
2401
2402 xmitter = &new_conn->transmitter;
2403
2404 /* Enable authentication and encryption by default. */
2405 new_conn->auxiliary_payload_data = (IPMI_SOL_AUX_USE_ENCRYPTION
2406 | IPMI_SOL_AUX_USE_AUTHENTICATION);
2407
2408 rv = ipmi_create_lock_os_hnd(os_hnd, &xmitter->packet_lock);
2409 if (rv)
2410 goto out_err;
2411
2412 rv = ipmi_create_lock_os_hnd(os_hnd, &xmitter->queue_lock);
2413 if (rv)
2414 goto out_err;
2415
2416 rv = ipmi_create_lock_os_hnd(os_hnd, &xmitter->oob_op_lock);
2417 if (rv)
2418 goto out_err;
2419
2420 new_conn->ipmi = ipmi;
2421 new_conn->data_received_callback_list = locked_list_alloc(os_hnd);
2422 if (! new_conn->data_received_callback_list) {
2423 rv = ENOMEM;
2424 goto out_err;
2425 }
2426 new_conn->break_detected_callback_list = locked_list_alloc(os_hnd);
2427 if (! new_conn->break_detected_callback_list) {
2428 rv = ENOMEM;
2429 goto out_err;
2430 }
2431 new_conn->bmc_transmit_overrun_callback_list = locked_list_alloc(os_hnd);
2432 if (! new_conn->bmc_transmit_overrun_callback_list) {
2433 rv = ENOMEM;
2434 goto out_err;
2435 }
2436 new_conn->connection_state_callback_list = locked_list_alloc(os_hnd);
2437 if (! new_conn->connection_state_callback_list) {
2438 rv = ENOMEM;
2439 goto out_err;
2440 }
2441
2442 new_conn->prev_received_seqnr = 0;
2443 new_conn->prev_character_count = 0;
2444
2445 new_conn->state = ipmi_sol_state_closed;
2446 new_conn->try_fast_connect = 1;
2447
2448 xmitter->sol_conn = new_conn;
2449 xmitter->transmitted_packet = NULL;
2450 xmitter->latest_outgoing_seqnr = 1;
2451
2452 new_conn->ACK_retries = 10;
2453 new_conn->ACK_timeout_usec = 1000000;
2454
2455 rv = add_connection(new_conn);
2456 if (rv)
2457 goto out_err;
2458
2459 *sol_conn = new_conn;
2460
2461 return 0;
2462
2463 out_err:
2464 if (xmitter->packet_lock)
2465 ipmi_destroy_lock(xmitter->packet_lock);
2466 if (xmitter->queue_lock)
2467 ipmi_destroy_lock(xmitter->queue_lock);
2468 if (xmitter->oob_op_lock)
2469 ipmi_destroy_lock(xmitter->oob_op_lock);
2470 if (new_conn->data_received_callback_list)
2471 locked_list_destroy(new_conn->data_received_callback_list);
2472 if (new_conn->break_detected_callback_list)
2473 locked_list_destroy(new_conn->break_detected_callback_list);
2474 if (new_conn->bmc_transmit_overrun_callback_list)
2475 locked_list_destroy(new_conn->bmc_transmit_overrun_callback_list);
2476 if (new_conn->connection_state_callback_list)
2477 locked_list_destroy(new_conn->connection_state_callback_list);
2478 ipmi_mem_free(new_conn);
2479 return rv;
2480 }
2481
2482
2483 /**
2484 * Figure out the "correct" maximum payload size. This should *never*
2485 * be larger than 259 (0x0103) due to the constraint of the 8-bit
2486 * Accepted Character Count field plus the 4-byte payload header.
2487 * Some manufacturers (who shall remain nameless) have wrong-endianed
2488 * the maximum payload size fields, so we have to figure out which way
2489 * around they should be. b1 and b2 are in the order they are in the
2490 * packet. They should be little-endian, so we try that first.
2491 */
2492 static int
get_sane_payload_size(int b1,int b2)2493 get_sane_payload_size(int b1, int b2)
2494 {
2495 int result = (b2 << 8) + b1;
2496 if ((result > 0x0103) || (result < 5)) {
2497 result = (b1 << 8) + b2;
2498 if ((result > 0x0103) || (result < 5)) {
2499 ipmi_log(IPMI_LOG_WARNING, "ipmi_sol.c(get_sane_payload_size): "
2500 "BMC did not supply a sensible buffer size"
2501 " (0x%02x, 0x%02x). Defaulting to 16.",
2502 b1, b2);
2503 result = 0x10; /* 16 bytes should be a safe buffer size. */
2504 } else
2505 ipmi_log(IPMI_LOG_INFO, "ipmi_sol.c(get_sane_payload_size): "
2506 "BMC sent a byte-swapped buffer size (%d bytes)."
2507 " Using %d bytes.", (b2 << 8) + b1, result);
2508 }
2509 return result;
2510 }
2511
2512 static void
finish_activate_payload(ipmi_sol_conn_t * conn)2513 finish_activate_payload(ipmi_sol_conn_t *conn)
2514 {
2515 if (conn->max_outbound_payload_size > IPMI_SOL_MAX_DATA_SIZE)
2516 conn->transmitter.scratch_area_size = IPMI_SOL_MAX_DATA_SIZE;
2517 else
2518 conn->transmitter.scratch_area_size = conn->max_outbound_payload_size;
2519
2520 ipmi_log(IPMI_LOG_INFO,
2521 "ipmi_sol.c(handle_active_payload_response): "
2522 "Connected to BMC SoL through port %d.",
2523 /* conn->hostname,*/
2524 conn->payload_port_number);
2525
2526 #ifdef IPMI_SOL_VERBOSE
2527 ipmi_log(IPMI_LOG_INFO,
2528 "ipmi_sol.c(handle_active_payload_response): "
2529 "BMC requested transmit limit %d bytes, receive limit %d bytes.",
2530 conn->max_outbound_payload_size,
2531 conn->max_inbound_payload_size);
2532
2533 if (conn->max_outbound_payload_size > conn->transmitter.scratch_area_size)
2534 ipmi_log(IPMI_LOG_WARNING,
2535 "ipmi_sol.c(handle_active_payload_response): "
2536 "Limiting transmit to %d bytes.",
2537 conn->transmitter.scratch_area_size);
2538 #endif
2539
2540 /*
2541 * Set the hardware handshaking bits to match the "holdoff" option...
2542 */
2543 ipmi_lock(conn->transmitter.oob_op_lock);
2544 if (conn->auxiliary_payload_data & IPMI_SOL_AUX_DEASSERT_HANDSHAKE)
2545 conn->transmitter.oob_persistent_op
2546 |= (IPMI_SOL_OPERATION_CTS_PAUSE
2547 | IPMI_SOL_OPERATION_DROP_DCD_DSR);
2548 else
2549 conn->transmitter.oob_persistent_op
2550 &= ~(IPMI_SOL_OPERATION_CTS_PAUSE
2551 | IPMI_SOL_OPERATION_DROP_DCD_DSR);
2552 ipmi_unlock(conn->transmitter.oob_op_lock);
2553
2554 /*
2555 * And officially bring the connection "up"!
2556 */
2557 ipmi_sol_set_connection_state(conn, ipmi_sol_state_connected, 0);
2558 }
2559
ipmid_changed(ipmi_con_t * ipmid,int err,unsigned int port_num,int any_port_up,void * cb_data)2560 static void ipmid_changed(ipmi_con_t *ipmid,
2561 int err,
2562 unsigned int port_num,
2563 int any_port_up,
2564 void *cb_data)
2565 {
2566 ipmi_sol_conn_t *conn = cb_data;
2567
2568 ipmi_lock(conn->transmitter.packet_lock);
2569 if (err) {
2570 ipmi_log(IPMI_LOG_SEVERE,
2571 "ipmi_sol.c(handle_active_payload_response): "
2572 "Error setting up new port: %d", err);
2573 goto out_err;
2574 }
2575
2576 finish_activate_payload(conn);
2577 ipmi_unlock(conn->transmitter.packet_lock);
2578 return;
2579
2580 out_err:
2581 send_close(conn, NULL);
2582 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed, err);
2583 ipmi_unlock(conn->transmitter.packet_lock);
2584 }
2585
2586 /*
2587 * Create a new IPMI connection to the BMC on the port specified in
2588 * the payload port number.
2589 */
2590 static int
setup_new_ipmi(ipmi_sol_conn_t * conn)2591 setup_new_ipmi(ipmi_sol_conn_t *conn)
2592 {
2593 ipmi_args_t *args;
2594 int rv;
2595 char pname[20];
2596
2597 ipmi_log(IPMI_LOG_INFO,
2598 "ipmi_sol.c(setup_new_ipmi): "
2599 "Setting up new IPMI connection to port %d.",
2600 conn->payload_port_number);
2601
2602 if (!conn->ipmi->get_startup_args) {
2603 ipmi_log(IPMI_LOG_SEVERE,
2604 "ipmi_sol.c(handle_active_payload_response): "
2605 "Required a new port, but connection doesn't support "
2606 "fetching arguments.");
2607 return ENOSYS;
2608 }
2609
2610 args = conn->ipmi->get_startup_args(conn->ipmi);
2611 if (!args) {
2612 ipmi_log(IPMI_LOG_SEVERE,
2613 "ipmi_sol.c(handle_active_payload_response): "
2614 "Unable to get arguments from the IPMI connection.");
2615 return ENOMEM;
2616 }
2617
2618 snprintf(pname, sizeof(pname), "%d", conn->payload_port_number);
2619 rv = ipmi_args_set_val(args, -1, "Port", pname);
2620 if (rv) {
2621 ipmi_log(IPMI_LOG_SEVERE,
2622 "ipmi_sol.c(handle_active_payload_response): "
2623 "Error setting port argument: %d.", rv);
2624 return rv;
2625 }
2626
2627 rv = ipmi_args_setup_con(args, conn->ipmi->os_hnd, NULL, &conn->ipmid);
2628 if (rv) {
2629 ipmi_log(IPMI_LOG_SEVERE,
2630 "ipmi_sol.c(handle_active_payload_response): "
2631 "Error setting up new connection: %d.", rv);
2632 return rv;
2633 }
2634 ipmi_free_args(args);
2635
2636 rv = conn->ipmid->add_con_change_handler(conn->ipmid, ipmid_changed, conn);
2637 if (rv) {
2638 ipmi_log(IPMI_LOG_SEVERE,
2639 "ipmi_sol.c(handle_active_payload_response): "
2640 "Error adding connection change handler: %d.", rv);
2641 return rv;
2642 }
2643
2644 rv = conn->ipmid->start_con(conn->ipmid);
2645 if (rv) {
2646 ipmi_log(IPMI_LOG_SEVERE,
2647 "ipmi_sol.c(handle_active_payload_response): "
2648 "Error starting secondary connection: %d.", rv);
2649 return rv;
2650 }
2651
2652 return 0;
2653 }
2654
2655 static void
handle_activate_payload_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)2656 handle_activate_payload_response(ipmi_sol_conn_t *conn,
2657 ipmi_msg_t *msg_in)
2658 {
2659 /*
2660 * Did it work?
2661 */
2662 if (msg_in->data_len != 13) {
2663 if (msg_in->data_len != 1) {
2664 ipmi_log(IPMI_LOG_WARNING,
2665 "ipmi_sol.c(handle_active_payload_response): "
2666 "Received %d bytes... was expecting 13 bytes.\n",
2667 msg_in->data_len);
2668 dump_hex(msg_in->data, msg_in->data_len);
2669 }
2670
2671 if (msg_in->data_len > 0)
2672 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2673 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2674 else
2675 ipmi_sol_set_connection_state
2676 (conn, ipmi_sol_state_closed,
2677 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
2678 return;
2679 }
2680
2681 if (msg_in->data[0] != 0x00) {
2682 ipmi_log(IPMI_LOG_SEVERE,
2683 "ipmi_sol.c(handle_active_payload_response): "
2684 "Activate payload failed.");
2685 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2686 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2687 return;
2688 }
2689
2690 /* Recover payload sizes that might be wrong-endianed... */
2691
2692 /* outbound from here->BMC */
2693 conn->max_outbound_payload_size
2694 = get_sane_payload_size(msg_in->data[5], msg_in->data[6]);
2695
2696 /* inbound from BMC->here */
2697 conn->max_inbound_payload_size
2698 = get_sane_payload_size(msg_in->data[7], msg_in->data[8]);
2699
2700 conn->payload_port_number = (msg_in->data[10] << 8) + msg_in->data[9];
2701 if (conn->payload_port_number == 28418) {
2702 /* Bad byte-swapping */
2703 ipmi_log(IPMI_LOG_WARNING,
2704 "ipmi_sol.c(handle_active_payload_response): "
2705 "Got a badly byte-swapped UDP port, most likely. Setting"
2706 " it to the proper value.");
2707 conn->payload_port_number = IPMI_LAN_STD_PORT;
2708 }
2709
2710 if (conn->payload_port_number != IPMI_LAN_STD_PORT) {
2711 int rv = setup_new_ipmi(conn);
2712 if (rv) {
2713 send_close(conn, NULL);
2714 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed, rv);
2715 }
2716 } else {
2717 conn->ipmid = conn->ipmi;
2718 finish_activate_payload(conn);
2719 }
2720 }
2721
2722 static int
send_activate_payload(ipmi_sol_conn_t * conn)2723 send_activate_payload(ipmi_sol_conn_t *conn)
2724 {
2725 ipmi_msg_t msg_out;
2726 unsigned char data[6];
2727
2728 /*
2729 * Send an Activate Payload command
2730 */
2731 msg_out.data_len = 6;
2732 msg_out.data = data;
2733
2734 msg_out.data[0] = IPMI_RMCPP_PAYLOAD_TYPE_SOL & 0x3f; /* payload type */
2735 msg_out.data[1] = conn->payload_instance; /* payload instance number */
2736 /* NOTE: Can't connect to an Intel AXXIMMADV with the
2737 "Serial/Modem alerts fail" option, it seems. */
2738
2739 /* enc, auth, Serial alerts behavior, deassert CTS and DCD/DSR */
2740 msg_out.data[2] = conn->auxiliary_payload_data;
2741 msg_out.data[3] = 0x00;
2742 msg_out.data[4] = 0x00;
2743 msg_out.data[5] = 0x00;
2744
2745 msg_out.netfn = IPMI_APP_NETFN;
2746 msg_out.cmd = IPMI_ACTIVATE_PAYLOAD_CMD;
2747 return send_message(conn, &msg_out,
2748 handle_activate_payload_response);
2749 }
2750
2751
2752 static void
handle_set_volatile_bitrate_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)2753 handle_set_volatile_bitrate_response(ipmi_sol_conn_t *conn,
2754 ipmi_msg_t *msg_in)
2755 {
2756 if (msg_in->data_len != 1) {
2757 ipmi_log(IPMI_LOG_WARNING,
2758 "ipmi_sol.c(handle_set_volatile_bitrate_response): "
2759 "Received %d bytes... was expecting 1 byte.\n",
2760 msg_in->data_len);
2761 dump_hex(msg_in->data, msg_in->data_len);
2762
2763 if (msg_in->data_len > 0)
2764 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2765 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2766 else
2767 ipmi_sol_set_connection_state
2768 (conn, ipmi_sol_state_closed,
2769 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
2770 return;
2771 }
2772
2773 if (msg_in->data[0] != 0x00) {
2774 ipmi_log(IPMI_LOG_SEVERE,
2775 "ipmi_sol.c(handle_set_volatile_bitrate_response): "
2776 "Set SoL configuration[Volatile bit rate] failed.");
2777 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2778 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2779 return;
2780 }
2781
2782 #ifdef IPMI_SOL_VERBOSE
2783 ipmi_log(IPMI_LOG_INFO,
2784 "ipmi_sol.c(handle_set_volatile_bitrate_response): "
2785 "Volatile bit rate set.");
2786 #endif
2787 send_activate_payload(conn);
2788 }
2789
2790 static int
send_set_volatile_bitrate(ipmi_sol_conn_t * conn)2791 send_set_volatile_bitrate(ipmi_sol_conn_t *conn)
2792 {
2793 ipmi_msg_t msg_out;
2794 unsigned char data[3];
2795 /*
2796 * Send a Set SoL Configuration command
2797 */
2798 msg_out.data_len = 3;
2799 msg_out.data = data;
2800 msg_out.data[0] = IPMI_SELF_CHANNEL; /* own channel, set param */
2801 msg_out.data[1] = 6; /* parameter selector = SOL volatile bit rate */
2802 msg_out.data[2] = conn->initial_bit_rate;
2803
2804 msg_out.netfn = IPMI_TRANSPORT_NETFN;
2805 msg_out.cmd = IPMI_SET_SOL_CONFIGURATION_PARAMETERS;
2806
2807 return send_message(conn, &msg_out,
2808 handle_set_volatile_bitrate_response);
2809 }
2810
2811 static void
handle_get_payload_activation_status_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)2812 handle_get_payload_activation_status_response(ipmi_sol_conn_t *conn,
2813 ipmi_msg_t *msg_in)
2814 {
2815 int count = 0, found, max, byte, index;
2816
2817 if (msg_in->data_len != 4) {
2818 ipmi_log(IPMI_LOG_SEVERE,
2819 "ipmi_sol.c(handle_get_payload_activation_status_response): "
2820 "Get Payload Activation Status command failed.");
2821 if (msg_in->data_len > 0)
2822 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2823 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2824 else
2825 ipmi_sol_set_connection_state
2826 (conn, ipmi_sol_state_closed,
2827 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
2828 return;
2829 }
2830
2831 found = 0;
2832 for (byte = 0; byte <= 1; byte++) {
2833 for (index = 0; index < 7; index++) {
2834 if (msg_in->data[2 + byte] & (1 << index)) {
2835 /* This payload instance slot is in use */
2836 count++;
2837 } else if (!found) {
2838 found = 1;
2839 conn->payload_instance = 8 * byte + index + 1;
2840 }
2841 }
2842 }
2843
2844 max = msg_in->data[1] & 0x0f;
2845
2846 #ifdef IPMI_SOL_VERBOSE
2847 ipmi_log(IPMI_LOG_INFO,
2848 "ipmi_sol.c(handle_get_payload_activation_status_response): "
2849 "BMC currently using %d SoL payload instances; limit is %d.",
2850 count, max);
2851 #endif
2852
2853 if (!found || (count >= max)) {
2854 ipmi_log(IPMI_LOG_SEVERE,
2855 "ipmi_sol.c(handle_get_payload_activation_status_response): "
2856 "BMC can't accept any more SoL sessions.");
2857 ipmi_sol_set_connection_state
2858 (conn, ipmi_sol_state_closed,
2859 IPMI_RMCPP_ERR_VAL(IPMI_RMCPP_INVALID_PAYLOAD_TYPE));
2860 return;
2861 }
2862 #ifdef IPMI_SOL_VERBOSE
2863 ipmi_log(IPMI_LOG_INFO,
2864 "ipmi_sol.c(handle_get_payload_activation_status_response): "
2865 "SoL sessions are available; Using instance slot %d.",
2866 conn->payload_instance);
2867 #endif
2868
2869 if (conn->initial_bit_rate)
2870 send_set_volatile_bitrate(conn);
2871 else
2872 send_activate_payload(conn);
2873 }
2874
2875 static int
send_get_payload_activation_status_command(ipmi_sol_conn_t * conn)2876 send_get_payload_activation_status_command(ipmi_sol_conn_t *conn)
2877 {
2878 ipmi_msg_t msg_out;
2879 unsigned char data[1];
2880
2881 /*
2882 * Send a Get Payload Activation Status command
2883 */
2884 msg_out.data_len = 1;
2885 msg_out.data = data;
2886
2887 msg_out.data[0] = IPMI_RMCPP_PAYLOAD_TYPE_SOL; /* Payload type */
2888
2889 msg_out.netfn = IPMI_APP_NETFN;
2890 msg_out.cmd = IPMI_GET_PAYLOAD_ACTIVATION_STATUS_CMD;
2891
2892 return send_message(conn, &msg_out,
2893 handle_get_payload_activation_status_response);
2894 }
2895
2896
2897 static void
handle_session_info_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)2898 handle_session_info_response(ipmi_sol_conn_t *conn,
2899 ipmi_msg_t *msg_in)
2900 {
2901 #ifdef IPMI_SOL_VERBOSE
2902 char *privilege_level[16] = {
2903 "Unknown", "Callback", "User", "Operator", "Administrator",
2904 "OEM Proprietary", "Unknown", "Unknown", "Unknown", "Unknown",
2905 "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown"};
2906 #endif
2907
2908 if (msg_in->data_len < 7) {
2909 ipmi_log(IPMI_LOG_SEVERE,
2910 "ipmi_sol.c(handle_session_info_response): "
2911 "Get Session Info command failed.");
2912 if (msg_in->data_len > 0)
2913 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2914 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2915 else
2916 ipmi_sol_set_connection_state
2917 (conn, ipmi_sol_state_closed,
2918 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
2919
2920 return;
2921 }
2922
2923 #ifdef IPMI_SOL_VERBOSE
2924 ipmi_log(IPMI_LOG_INFO,
2925 "ipmi_sol.c(handle_session_info_response): "
2926 "This session handle: 0x%02x"
2927 " BMC currently using %d of %d sessions",
2928 msg_in->data[1], msg_in->data[3], msg_in->data[2]);
2929 ipmi_log(IPMI_LOG_INFO,
2930 "ipmi_sol.c(handle_session_info_response): "
2931 "Current UserID: 0x%02x (%s) Channel number: 0x%02x",
2932 msg_in->data[4] & 0x3f, privilege_level[msg_in->data[5] & 0x0f],
2933 msg_in->data[6] & 0x0f);
2934 #endif
2935 send_get_payload_activation_status_command(conn);
2936 }
2937
2938 static int
send_get_session_info(ipmi_sol_conn_t * conn)2939 send_get_session_info(ipmi_sol_conn_t *conn)
2940 {
2941 /*
2942 * Send a Get Session Info command (gives us our User ID, among
2943 * other things)
2944 */
2945 ipmi_msg_t msg_out;
2946 unsigned char data[1];
2947
2948 msg_out.data_len = 1;
2949 msg_out.data = data;
2950
2951 msg_out.data[0] = 0x00; /* current session */
2952
2953 msg_out.netfn = IPMI_APP_NETFN;
2954 msg_out.cmd = IPMI_GET_SESSION_INFO_CMD;
2955
2956 return send_message(conn, &msg_out, handle_session_info_response);
2957 }
2958
2959 static void
handle_commit_write_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)2960 handle_commit_write_response(ipmi_sol_conn_t *conn,
2961 ipmi_msg_t *msg_in)
2962 {
2963 send_get_session_info(conn);
2964 }
2965
2966 static int
send_commit_write(ipmi_sol_conn_t * conn)2967 send_commit_write(ipmi_sol_conn_t *conn)
2968 {
2969 ipmi_msg_t msg_out;
2970 unsigned char data[3];
2971
2972 msg_out.data_len = 3;
2973 msg_out.data = data;
2974
2975 /* own channel, get param (not just version) */
2976 msg_out.data[0] = IPMI_SELF_CHANNEL;
2977 msg_out.data[1] = 0; /* parameter selector = Set In Progress */
2978 msg_out.data[2] = 0; /* Commit write */
2979
2980 msg_out.netfn = IPMI_TRANSPORT_NETFN;
2981 msg_out.cmd = IPMI_SET_SOL_CONFIGURATION_PARAMETERS;
2982
2983 return send_message(conn, &msg_out, handle_commit_write_response);
2984 }
2985
2986 static void
handle_set_sol_enabled_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)2987 handle_set_sol_enabled_response(ipmi_sol_conn_t *conn,
2988 ipmi_msg_t *msg_in)
2989 {
2990 #if 0
2991 if ((msg_in->data_len != 1) || (msg_in->data[0])) {
2992 if (msg_in->data_len > 0)
2993 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
2994 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
2995 else
2996 ipmi_sol_set_connection_state
2997 (conn, ipmi_sol_state_closed,
2998 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
2999
3000 return 0;
3001 }
3002 #endif
3003
3004 send_commit_write(conn);
3005 }
3006
3007 static int
send_enable_sol_command(ipmi_sol_conn_t * conn)3008 send_enable_sol_command(ipmi_sol_conn_t *conn)
3009 {
3010 ipmi_msg_t msg_out;
3011 unsigned char data[3];
3012
3013 /*
3014 * Send a Set SoL Configuration command
3015 */
3016 ipmi_log(IPMI_LOG_INFO,
3017 "ipmi_sol.c(send_enable_sol_command): "
3018 "Attempting to enable SoL on BMC.");
3019
3020 msg_out.data_len = 3;
3021 msg_out.data = data;
3022
3023 /* own channel, get param (not just version) */
3024 msg_out.data[0] = IPMI_SELF_CHANNEL;
3025 msg_out.data[1] = 2; /* parameter selector = SOL Auth */
3026 msg_out.data[2] = 0x02; /* Enable SoL! */
3027
3028 msg_out.netfn = IPMI_TRANSPORT_NETFN;
3029 msg_out.cmd = IPMI_SET_SOL_CONFIGURATION_PARAMETERS;
3030
3031 return send_message(conn, &msg_out,
3032 handle_set_sol_enabled_response);
3033 }
3034
3035 static void
handle_get_sol_enabled_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)3036 handle_get_sol_enabled_response(ipmi_sol_conn_t *conn,
3037 ipmi_msg_t *msg_in)
3038 {
3039 if (msg_in->data_len != 3) {
3040 ipmi_log(IPMI_LOG_SEVERE,
3041 "ipmi_sol.c(handle_get_sol_enabled_response): "
3042 "Get SoL Configuration[SoL Enabled] failed.");
3043 if (msg_in->data_len > 0)
3044 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
3045 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
3046 else
3047 ipmi_sol_set_connection_state
3048 (conn, ipmi_sol_state_closed,
3049 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
3050
3051 return;
3052 }
3053
3054 if ((msg_in->data[2] && 1)) {
3055 #ifdef IPMI_SOL_VERBOSE
3056 ipmi_log(IPMI_LOG_INFO,
3057 "ipmi_sol.c(handle_get_sol_enabled_response): "
3058 "BMC says SoL is enabled.");
3059 #endif
3060 send_get_session_info(conn);
3061 return;
3062 }
3063 ipmi_log(IPMI_LOG_SEVERE,
3064 "ipmi_sol.c(handle_get_sol_enabled_response): "
3065 "BMC says SoL is disabled.");
3066
3067 if (conn->force_connection_configure)
3068 send_enable_sol_command(conn);
3069 else
3070 ipmi_sol_set_connection_state
3071 (conn, ipmi_sol_state_closed,
3072 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
3073 }
3074
3075 static void
send_get_sol_configuration_command(ipmi_sol_conn_t * conn)3076 send_get_sol_configuration_command(ipmi_sol_conn_t *conn)
3077 {
3078 ipmi_msg_t msg_out;
3079 unsigned char data[4];
3080
3081 /*
3082 * Send a Get SoL Configuration command
3083 */
3084 msg_out.data_len = 4;
3085 msg_out.data = data;
3086
3087 /* own channel, get param (not just version) */
3088 msg_out.data[0] = IPMI_SELF_CHANNEL;
3089 msg_out.data[1] = 1; /* parameter selector, 1 = SOL Enabled */
3090 msg_out.data[2] = 0; /* set selector */
3091 msg_out.data[3] = 0; /* block selector */
3092
3093 msg_out.netfn = IPMI_TRANSPORT_NETFN;
3094 msg_out.cmd = IPMI_GET_SOL_CONFIGURATION_PARAMETERS;
3095
3096 send_message(conn, &msg_out, handle_get_sol_enabled_response);
3097 }
3098
3099
3100 static void
handle_get_channel_payload_support_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)3101 handle_get_channel_payload_support_response(ipmi_sol_conn_t *conn,
3102 ipmi_msg_t *msg_in)
3103 {
3104 if (msg_in->data_len != 9) {
3105 ipmi_log(IPMI_LOG_SEVERE,
3106 "ipmi_sol.c(handle_get_channel_payload_support_response): "
3107 "Get Channel Payload Support command failed.");
3108 if (msg_in->data_len > 0)
3109 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
3110 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
3111 else
3112 ipmi_sol_set_connection_state
3113 (conn, ipmi_sol_state_closed,
3114 IPMI_SOL_ERR_VAL(IPMI_SOL_NOT_AVAILABLE));
3115
3116 return;
3117 }
3118
3119 if (!(msg_in->data[1] & (1 << IPMI_RMCPP_PAYLOAD_TYPE_SOL))) {
3120 /* SoL is not supported! */
3121 ipmi_log(IPMI_LOG_ERR_INFO,
3122 "ipmi_sol.c(handle_get_channel_payload_support_response): "
3123 "BMC says SoL is not supported.");
3124 ipmi_sol_set_connection_state
3125 (conn, ipmi_sol_state_closed,
3126 IPMI_RMCPP_ERR_VAL(IPMI_RMCPP_INVALID_PAYLOAD_TYPE));
3127 return;
3128 }
3129 #ifdef IPMI_SOL_VERBOSE
3130 ipmi_log(IPMI_LOG_INFO,
3131 "ipmi_sol.c(handle_get_channel_payload_support_response): "
3132 "BMC says SoL is supported.");
3133 #endif
3134 send_get_sol_configuration_command(conn);
3135 }
3136
3137 static int
send_get_channel_payload_support_command(ipmi_sol_conn_t * conn)3138 send_get_channel_payload_support_command(ipmi_sol_conn_t *conn)
3139 {
3140 ipmi_msg_t msg_out;
3141 unsigned char data[1];
3142
3143 /*
3144 * Send a Get Payload Support command
3145 */
3146 msg_out.data_len = 1;
3147 msg_out.data = data;
3148
3149 msg_out.data[0] = IPMI_SELF_CHANNEL; /* current channel */
3150
3151 msg_out.netfn = IPMI_APP_NETFN;
3152 msg_out.cmd = IPMI_GET_CHANNEL_PAYLOAD_SUPPORT_CMD;
3153
3154 return send_message(conn, &msg_out,
3155 handle_get_channel_payload_support_response);
3156 }
3157
3158
3159 int
ipmi_sol_open(ipmi_sol_conn_t * conn)3160 ipmi_sol_open(ipmi_sol_conn_t *conn)
3161 {
3162 int rv;
3163
3164 ipmi_lock(conn->transmitter.packet_lock);
3165 if (conn->state != ipmi_sol_state_closed) {
3166 /* It's an error to try to connect when not in closed state. */
3167 ipmi_unlock(conn->transmitter.packet_lock);
3168 ipmi_log(IPMI_LOG_ERR_INFO,
3169 "ipmi_sol.c(ipmi_sol_open): "
3170 "An attempt was made to open an SoL connection"
3171 " that's already open.");
3172 return EINVAL;
3173 }
3174
3175 conn->addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
3176 conn->addr.channel = IPMI_BMC_CHANNEL;
3177 conn->addr.lun = 0;
3178
3179 /*
3180 * Note: For SoL over IPMI 1.5, the ipmi_lan code will translate this
3181 * RMCP+ address into the right packet format over RMCP (instead of
3182 * RMCP+).
3183 */
3184 conn->sol_payload_addr.addr_type = IPMI_RMCPP_ADDR_SOL;
3185
3186 if (conn->try_fast_connect)
3187 rv = send_get_payload_activation_status_command(conn);
3188 else
3189 rv = send_get_channel_payload_support_command(conn);
3190
3191 if (!rv)
3192 ipmi_sol_set_connection_state(conn, ipmi_sol_state_connecting, 0);
3193
3194 conn->transmitter.nack_count = 0;
3195 conn->transmitter.packet_to_acknowledge = 0;
3196 conn->transmitter.accepted_character_count = 0;
3197 conn->transmitter.bytes_acked_at_head = 0;
3198
3199 ipmi_unlock(conn->transmitter.packet_lock);
3200 return rv;
3201 }
3202
3203
3204 static void
handle_deactivate_payload_response(ipmi_sol_conn_t * conn,ipmi_msg_t * msg_in)3205 handle_deactivate_payload_response(ipmi_sol_conn_t *conn,
3206 ipmi_msg_t *msg_in)
3207 {
3208 /*
3209 * We assume that conn hasn't gone away already, since we got the message
3210 * through the connection table.
3211 */
3212 if (conn->state == ipmi_sol_state_closed)
3213 return;
3214
3215 /*
3216 * Did it work? (Do we care?)
3217 */
3218 if (msg_in->data_len != 1)
3219 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
3220 IPMI_SOL_ERR_VAL(IPMI_SOL_DISCONNECTED));
3221 else
3222 if (msg_in->data[0] != 0x00)
3223 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
3224 IPMI_IPMI_ERR_VAL(msg_in->data[0]));
3225 else
3226 /* Success! */
3227 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed, 0);
3228
3229 transmitter_shutdown(&conn->transmitter, 0);
3230 }
3231
3232 int
ipmi_sol_close(ipmi_sol_conn_t * conn)3233 ipmi_sol_close(ipmi_sol_conn_t *conn)
3234 {
3235 ipmi_lock(conn->transmitter.packet_lock);
3236 if ((conn->state == ipmi_sol_state_closing)
3237 || (conn->state == ipmi_sol_state_closed))
3238 {
3239 ipmi_unlock(conn->transmitter.packet_lock);
3240 return EINVAL;
3241 }
3242
3243 send_close(conn, handle_deactivate_payload_response);
3244 ipmi_unlock(conn->transmitter.packet_lock);
3245 return 0;
3246 }
3247
3248
3249 int
ipmi_sol_force_close_wsend(ipmi_sol_conn_t * conn,int rem_close)3250 ipmi_sol_force_close_wsend(ipmi_sol_conn_t *conn, int rem_close)
3251 {
3252 ipmi_lock(conn->transmitter.packet_lock);
3253 if (conn->state == ipmi_sol_state_closed) {
3254 ipmi_unlock(conn->transmitter.packet_lock);
3255 return EINVAL;
3256 }
3257
3258 if (rem_close && conn->state != ipmi_sol_state_closing)
3259 /*
3260 * Try to be polite to the BMC. Don't ask for a callback,
3261 * cos we'll be gone!
3262 */
3263 send_close(conn, NULL);
3264
3265 transmitter_shutdown(&conn->transmitter,
3266 IPMI_SOL_ERR_VAL(IPMI_SOL_DISCONNECTED));
3267
3268 ipmi_sol_set_connection_state(conn, ipmi_sol_state_closed,
3269 IPMI_SOL_ERR_VAL(IPMI_SOL_DISCONNECTED));
3270 ipmi_unlock(conn->transmitter.packet_lock);
3271
3272 return 0;
3273 }
3274
3275 int
ipmi_sol_force_close(ipmi_sol_conn_t * conn)3276 ipmi_sol_force_close(ipmi_sol_conn_t *conn)
3277 {
3278 return ipmi_sol_force_close_wsend(conn, 1);
3279 }
3280
3281 int
ipmi_sol_free(ipmi_sol_conn_t * conn)3282 ipmi_sol_free(ipmi_sol_conn_t *conn)
3283 {
3284 sol_put_connection(conn);
3285 return 0;
3286 }
3287
3288
3289 /********************************************************************
3290 ** IPMI SoL Payload handling *****************************
3291 ********************************************************************/
3292
3293 /* Format a message for transmit on this payload. The address and
3294 message is the one specified by the user. The out_data is a
3295 pointer to where to store the output, out_data_len will point
3296 to the length of the buffer to store the output and should be
3297 updatated to be the actual length. The seq is a 6-bit value
3298 that should be store somewhere so the that response to this
3299 message can be identified. If the netfn is odd, the sequence
3300 number is not used. The out_of_session variable is set to zero
3301 by default; if the message is meant to be sent out of session,
3302 then the formatter should set this value to 1. */
3303
3304 static int
sol_format_msg(ipmi_con_t * conn,const ipmi_addr_t * addr,unsigned int addr_len,const ipmi_msg_t * msg,unsigned char * out_data,unsigned int * out_data_len,int * out_of_session,unsigned char seq)3305 sol_format_msg(ipmi_con_t *conn,
3306 const ipmi_addr_t *addr,
3307 unsigned int addr_len,
3308 const ipmi_msg_t *msg,
3309 unsigned char *out_data,
3310 unsigned int *out_data_len,
3311 int *out_of_session,
3312 unsigned char seq)
3313 {
3314 if (*out_data_len < msg->data_len)
3315 return E2BIG;
3316
3317 memcpy(out_data, msg->data, msg->data_len);
3318
3319 *out_data_len = msg->data_len;
3320
3321 out_of_session = 0;
3322 return 0;
3323 }
3324
3325
3326 /* Get the recv sequence number from the message. Return ENOSYS
3327 if the sequence number is not valid for the message (it is
3328 asynchronous), zero otherwise */
sol_get_recv_seq(ipmi_con_t * conn,unsigned char * data,unsigned int data_len,unsigned char * seq)3329 static int sol_get_recv_seq(ipmi_con_t *conn,
3330 unsigned char *data,
3331 unsigned int data_len,
3332 unsigned char *seq)
3333 {
3334 /*
3335 * We force the packets to go through to sol_handle_recv_async for
3336 * our processing. This is because we can't use the OpenIPMI payload
3337 * sequence number interface.
3338 */
3339 return ENOSYS;
3340 }
3341
3342
3343 /* Fill in the rspi data structure from the given data, responses
3344 only. This does *not* deliver the message, that is done by the
3345 LAN code. */
3346 static int
sol_handle_recv(ipmi_con_t * conn,ipmi_msgi_t * rspi,ipmi_addr_t * orig_addr,unsigned int orig_addr_len,ipmi_msg_t * orig_msg,unsigned char * data,unsigned int data_len)3347 sol_handle_recv(ipmi_con_t *conn,
3348 ipmi_msgi_t *rspi,
3349 ipmi_addr_t *orig_addr,
3350 unsigned int orig_addr_len,
3351 ipmi_msg_t *orig_msg,
3352 unsigned char *data,
3353 unsigned int data_len)
3354 {
3355 /*
3356 * This should NEVER be called.
3357 */
3358 return ENOSYS;
3359 }
3360
3361 static void
process_packet(ipmi_sol_conn_t * conn,unsigned char * packet,unsigned int data_len)3362 process_packet(ipmi_sol_conn_t *conn,
3363 unsigned char *packet,
3364 unsigned int data_len)
3365 {
3366 ipmi_sol_transmitter_context_t *xmitter;
3367 int nack = 0;
3368
3369 xmitter = &conn->transmitter;
3370
3371 nack = (packet[PACKET_STATUS] & IPMI_SOL_STATUS_NACK_PACKET) != 0;
3372
3373 /* If NACK && CTU != prev CTU, do a conn state change */
3374
3375 if (nack) {
3376 /* Check CTU */
3377 int new_state;
3378
3379 if (packet[PACKET_STATUS]
3380 & IPMI_SOL_STATUS_CHARACTER_TRANSFER_UNAVAIL)
3381 new_state = ipmi_sol_state_connected_ctu;
3382 else
3383 new_state = ipmi_sol_state_connected;
3384
3385 ipmi_sol_set_connection_state(conn, new_state, 0);
3386 }
3387
3388 if (data_len > 4) {
3389 data_len -= 4; /* Skip over header */
3390
3391 if (0 == packet[PACKET_SEQNR]) {
3392 /* Can't have data in a packet with zero seqnr: error */
3393 ipmi_log(IPMI_LOG_WARNING,
3394 "ipmi_sol.c(sol_handle_recv_async): "
3395 "Broken BMC: Received a packet with non-empty data"
3396 " and a sequence number of zero.");
3397 } else {
3398 int character_count;
3399 int do_nack;
3400
3401 /* FIXME - validate that the sequence numbers are
3402 sequentially increasing. */
3403 if (conn->prev_received_seqnr == packet[PACKET_SEQNR]) {
3404 /* overlapping packets... yummy */
3405 character_count = data_len - conn->prev_character_count;
3406 } else {
3407 /* This whole packet goes to the client(s) */
3408 character_count = data_len;
3409 conn->prev_received_seqnr = packet[PACKET_SEQNR];
3410 }
3411 if (xmitter->nack_count) {
3412 /* The user already sent a NACK, no reason to send any
3413 more til they release it. */
3414 } else {
3415 xmitter->in_recv_cb = 1;
3416 ipmi_unlock(xmitter->packet_lock);
3417 do_nack = do_data_received_callbacks
3418 (conn, &packet[PACKET_DATA + data_len - character_count],
3419 character_count);
3420 ipmi_lock(xmitter->packet_lock);
3421 xmitter->in_recv_cb = 0;
3422
3423 xmitter->nack_count += do_nack;
3424 if (xmitter->nack_count < 0) {
3425 ipmi_log(IPMI_LOG_WARNING,
3426 "ipmi_sol.c(process_packet): "
3427 "Too many NACK releases.");
3428 xmitter->nack_count = 0;
3429 }
3430
3431 if (conn->state == ipmi_sol_state_closed)
3432 return;
3433 }
3434
3435 conn->prev_received_seqnr = packet[PACKET_SEQNR];
3436 xmitter->packet_to_acknowledge = packet[PACKET_SEQNR];
3437
3438 if (xmitter->nack_count) {
3439 conn->prev_character_count = 0;
3440 /* FIXME: It is unclear from the spec whether the
3441 accepted character count on a NACK should be 0 or
3442 the number of bytes not accepted. Zero seems more
3443 reasonable, but neither works with my machine, it
3444 just keeps retransmitting then gives up when it
3445 gets a NACK. - Corey */
3446 xmitter->accepted_character_count = 0;
3447 ipmi_lock(xmitter->oob_op_lock);
3448 xmitter->oob_transient_op |= IPMI_SOL_OPERATION_NACK_PACKET;
3449 ipmi_unlock(xmitter->oob_op_lock);
3450 } else {
3451 conn->prev_character_count = data_len;
3452 xmitter->accepted_character_count = data_len;
3453 }
3454 }
3455 }
3456
3457
3458 if (packet[PACKET_ACK_NACK_SEQNR] &&
3459 xmitter->transmitted_packet &&
3460 (packet[PACKET_ACK_NACK_SEQNR]
3461 == xmitter->transmitted_packet->packet[PACKET_SEQNR]))
3462 {
3463 /*
3464 * The op callbacks are always successful if we got an ACK.
3465 */
3466 do_outstanding_op_callbacks(xmitter, 0);
3467
3468 /* NACK and Char Trans Unavail? */
3469 if ((packet[PACKET_STATUS] & IPMI_SOL_STATUS_NACK_PACKET)
3470 && (packet[PACKET_STATUS] & IPMI_SOL_STATUS_CHARACTER_TRANSFER_UNAVAIL))
3471 {
3472 /*
3473 * This will never send CTU error code to a control
3474 * callback, cos they have been done-and-destroyed just
3475 * above!
3476 */
3477 transmitter_flush_outbound
3478 (xmitter,
3479 IPMI_SOL_ERR_VAL(IPMI_SOL_CHARACTER_TRANSFER_UNAVAILABLE));
3480 } else if (packet[PACKET_ACCEPTED_CHARACTER_COUNT] > 0) {
3481 /* Accepted chars? */
3482 transmitter_handle_acknowledge
3483 (conn, 0, packet[PACKET_ACCEPTED_CHARACTER_COUNT]);
3484 } else if (!(packet[PACKET_STATUS] & IPMI_SOL_STATUS_NACK_PACKET)) {
3485 /* FIXME: Intel hack */
3486 /*
3487 * If the packet wasn't NACKed, and the accepted char
3488 * count was zero, assume they meant to ACK the whole
3489 * packet.
3490 */
3491 transmitter_handle_acknowledge
3492 (conn, 0, xmitter->transmitted_packet->packet_size - 4);
3493 }
3494
3495 /*
3496 * Destroy the packet, reporting success on anything else we've missed.
3497 */
3498 dispose_of_outstanding_packet(xmitter, 0);
3499 }
3500
3501 if (packet[PACKET_STATUS] & IPMI_SOL_STATUS_BREAK_DETECTED) {
3502 ipmi_unlock(xmitter->packet_lock);
3503 do_break_detected_callbacks(conn);
3504 ipmi_lock(xmitter->packet_lock);
3505 if (conn->state == ipmi_sol_state_closed)
3506 return;
3507 }
3508
3509 if (packet[PACKET_STATUS] & IPMI_SOL_STATUS_BMC_TX_OVERRUN) {
3510 ipmi_unlock(xmitter->packet_lock);
3511 do_transmit_overrun_callbacks(conn);
3512 ipmi_lock(xmitter->packet_lock);
3513 if (conn->state == ipmi_sol_state_closed)
3514 return;
3515 }
3516
3517 if (nack && (packet[PACKET_STATUS] & IPMI_SOL_STATUS_DEACTIVATED)) {
3518 transmitter_shutdown(xmitter, IPMI_SOL_ERR_VAL(IPMI_SOL_DEACTIVATED));
3519 /* Success! */
3520 ipmi_sol_set_connection_state(conn,
3521 ipmi_sol_state_closed,
3522 IPMI_SOL_ERR_VAL(IPMI_SOL_DEACTIVATED));
3523 } else {
3524 transmitter_prod_nolock(xmitter);
3525 }
3526 }
3527
3528
3529 /* Handle an asynchronous message. This *should* deliver the
3530 message, if possible. */
3531 static void
sol_handle_recv_async(ipmi_con_t * ipmi_conn,unsigned char * packet,unsigned int data_len)3532 sol_handle_recv_async(ipmi_con_t *ipmi_conn,
3533 unsigned char *packet,
3534 unsigned int data_len)
3535 {
3536 ipmi_sol_transmitter_context_t *xmitter;
3537 ipmi_sol_conn_t *conn;
3538
3539 conn = find_sol_connection_for_ipmi(ipmi_conn);
3540 if (!conn) {
3541 ipmi_log(IPMI_LOG_WARNING,
3542 "ipmi_sol.c(sol_handle_recv_async): "
3543 "Dropped incoming SoL packet: Unrecognized connection.");
3544 return;
3545 }
3546
3547 xmitter = &conn->transmitter;
3548
3549 ipmi_lock(xmitter->packet_lock);
3550
3551 if (data_len < 4) {
3552 ipmi_log(IPMI_LOG_WARNING,
3553 "ipmi_sol.c(sol_handle_recv_async): "
3554 "Dropped incoming SoL packet: Too short, at %d bytes.",
3555 data_len);
3556 goto out_unlock;
3557 }
3558
3559 #ifdef IPMI_SOL_DEBUG_RECEIVE
3560 ipmi_log(IPMI_LOG_INFO,
3561 "ipmi_sol.c(sol_handle_recv_async): "
3562 "Received SoL packet, %d bytes", data_len);
3563 dump_hex(packet, data_len);
3564 #endif
3565
3566 if ((conn->state != ipmi_sol_state_connected)
3567 && (conn->state != ipmi_sol_state_connected_ctu)) {
3568 ipmi_log(IPMI_LOG_WARNING,
3569 "ipmi_sol.c(sol_handle_recv_async): "
3570 "Dropped incoming SoL packet: connection closed.");
3571 goto out_unlock;
3572 }
3573
3574 if (conn->processing_packet) {
3575 /* Some other thread is already processing packets. Tack this
3576 packet onto the end of waiting packets for the other thread
3577 to handle. */
3578 sol_in_packet_info_t *packet, *epacket;
3579 unsigned char *pdata;
3580
3581 packet = ipmi_mem_alloc(sizeof(*packet) + data_len);
3582 if (!packet)
3583 goto out_unlock;
3584 packet->data_len = data_len;
3585 packet->next = NULL;
3586 pdata = ((unsigned char *) packet) + sizeof(*packet);
3587 memcpy(pdata, packet, data_len);
3588
3589 if (conn->waiting_packets) {
3590 conn->waiting_packets = packet;
3591 } else {
3592 epacket = conn->waiting_packets;
3593 while (epacket->next)
3594 epacket = epacket->next;
3595 epacket->next = packet;
3596 }
3597 goto out_unlock;
3598 }
3599
3600 conn->processing_packet = 1;
3601
3602 /* At this point we are single-threaded. No other process can be
3603 running this code but me, even if I release the packet_lock. */
3604
3605 process_packet(conn, packet, data_len);
3606
3607 /* See if some other thread stuck some packets in for me to
3608 process. Do that now. */
3609 process_waiting_packets(conn);
3610
3611 conn->processing_packet = 0;
3612
3613 out_unlock:
3614 ipmi_unlock(xmitter->packet_lock);
3615 sol_put_connection(conn);
3616 }
3617
3618 static ipmi_payload_t ipmi_sol_payload =
3619 { sol_format_msg, sol_get_recv_seq, sol_handle_recv,
3620 sol_handle_recv_async, NULL /*sol_get_msg_tag*/ };
3621
3622 int
i_ipmi_sol_init()3623 i_ipmi_sol_init()
3624 {
3625 int rv;
3626
3627 rv = ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_SOL,
3628 &ipmi_sol_payload);
3629 if (rv)
3630 goto out;
3631
3632 rv = ipmi_create_global_lock(&conn_lock);
3633 if (rv) {
3634 ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_SOL, NULL);
3635 goto out;
3636 }
3637
3638 out:
3639 return rv;
3640 }
3641
3642 void
i_ipmi_sol_shutdown(void)3643 i_ipmi_sol_shutdown(void)
3644 {
3645 if (conn_lock) {
3646 ipmi_destroy_lock(conn_lock);
3647 conn_lock = NULL;
3648 }
3649 ipmi_rmcpp_register_payload(IPMI_RMCPP_PAYLOAD_TYPE_SOL, NULL);
3650 }
3651