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