/OpenIPMI-2.0.18/lib/ipmi_lan.c
C | 7041 lines | 5799 code | 902 blank | 340 comment | 1110 complexity | fde67a6e79a3f878053cd89526877d82 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /*
- * ipmi_lan.c
- *
- * MontaVista IPMI code for handling IPMI LAN connections
- *
- * Author: MontaVista Software, Inc.
- * Corey Minyard <minyard@mvista.com>
- * source@mvista.com
- *
- * Copyright 2002,2003,2004 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <config.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/stat.h>
- #include <sys/poll.h>
- #include <sys/time.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <OpenIPMI/ipmi_conn.h>
- #include <OpenIPMI/ipmi_msgbits.h>
- #include <OpenIPMI/ipmi_auth.h>
- #include <OpenIPMI/ipmi_err.h>
- #include <OpenIPMI/ipmi_lan.h>
- #include <OpenIPMI/internal/ipmi_event.h>
- #include <OpenIPMI/internal/ipmi_int.h>
- #include <OpenIPMI/internal/locked_list.h>
- #if defined(DEBUG_MSG) || defined(DEBUG_RAWMSG)
- static void
- dump_hex(void *vdata, int len)
- {
- unsigned char *data = vdata;
- int i;
- for (i=0; i<len; i++) {
- if ((i != 0) && ((i % 16) == 0)) {
- ipmi_log(IPMI_LOG_DEBUG_CONT, "\n ");
- }
- ipmi_log(IPMI_LOG_DEBUG_CONT, " %2.2x", data[i]);
- }
- }
- #endif
- #define LAN_AUDIT_TIMEOUT 10000000
- /* Timeout to wait for IPMI responses, in microseconds. For commands
- with side effects, we wait 5 seconds, not one. */
- #define LAN_RSP_TIMEOUT 1000000
- #define LAN_RSP_TIMEOUT_SIDEEFF 5000000
- /* # of times to try a message before we fail it. */
- #define LAN_RSP_RETRIES 6
- /* Number of microseconds of consecutive failures allowed on an IP
- before it is considered failed. */
- #define IP_FAIL_TIME 7000000
- /* Number of consecutive failures that must occur before an IP is
- considered failed. */
- #define IP_FAIL_COUNT 4
- /* The default for the maximum number of messages that are allowed to be
- outstanding. This is a pretty conservative number. */
- #define DEFAULT_MAX_OUTSTANDING_MSG_COUNT 2
- #define MAX_POSSIBLE_OUTSTANDING_MSG_COUNT 63
- typedef struct lan_data_s lan_data_t;
- typedef struct audit_timer_info_s
- {
- int cancelled;
- ipmi_con_t *ipmi;
- } audit_timer_info_t;
- typedef struct lan_timer_info_s
- {
- int cancelled;
- ipmi_con_t *ipmi;
- os_hnd_timer_id_t *timer;
- unsigned int seq;
- } lan_timer_info_t;
- typedef struct lan_wait_queue_s
- {
- lan_timer_info_t *info;
- ipmi_addr_t addr;
- unsigned int addr_len;
- ipmi_msg_t msg;
- unsigned char data[IPMI_MAX_MSG_LENGTH];
- ipmi_ll_rsp_handler_t rsp_handler;
- ipmi_msgi_t *rsp_item;
- int side_effects;
- struct lan_wait_queue_s *next;
- } lan_wait_queue_t;
- #define MAX_IP_ADDR 2
- /* We must keep this number small, if it's too big and a failure
- occurs, we will be outside the sequence number before we switch. */
- #define SENDS_BETWEEN_IP_SWITCHES 3
- /* Because sizeof(sockaddr_in6) > sizeof(sockaddr_in), this structure
- * is used as a replacement of struct sockaddr. */
- typedef struct sockaddr_ip_s {
- union
- {
- struct sockaddr s_addr;
- struct sockaddr_in s_addr4;
- #ifdef PF_INET6
- struct sockaddr_in6 s_addr6;
- #endif
- } s_ipsock;
- socklen_t ip_addr_len;
- } sockaddr_ip_t;
- struct ipmi_rmcpp_auth_s
- {
- lan_data_t *lan;
- int addr_num;
- uint8_t role;
- /* Filled in by the auth algorithm. */
- unsigned char my_rand[16];
- unsigned int my_rand_len;
- unsigned char mgsys_rand[16];
- unsigned int mgsys_rand_len;
- unsigned char mgsys_guid[16];
- unsigned int mgsys_guid_len;
- unsigned char sik[20];
- unsigned int sik_len;
- unsigned char k1[20];
- unsigned int k1_len;
- unsigned char k2[20];
- unsigned int k2_len;
- };
- typedef struct lan_conn_parms_s
- {
- unsigned int num_ip_addr;
- char *ip_addr_str[MAX_IP_ADDR];
- char *ip_port_str[MAX_IP_ADDR];
- sockaddr_ip_t ip_addr[MAX_IP_ADDR];
- unsigned int authtype;
- unsigned int privilege;
- unsigned char username[IPMI_USERNAME_MAX];
- unsigned int username_len;
- unsigned char password[IPMI_PASSWORD_MAX];
- unsigned int password_len;
- unsigned int conf;
- unsigned int integ;
- unsigned int auth;
- unsigned int name_lookup_only;
- unsigned char bmc_key[IPMI_PASSWORD_MAX];
- unsigned int bmc_key_len;
- } lan_conn_parms_t;
- typedef struct lan_link_s lan_link_t;
- struct lan_link_s
- {
- lan_link_t *next, *prev;
- lan_data_t *lan;
- };
- typedef struct lan_fd_s lan_fd_t;
- typedef struct lan_stat_info_s
- {
- #define STAT_RECV_PACKETS 0
- #define STAT_XMIT_PACKETS 1
- #define STAT_REXMITS 2
- #define STAT_TIMED_OUT 3
- #define STAT_INVALID_RMCP 4
- #define STAT_TOO_SHORT 5
- #define STAT_INVALID_AUTH 6
- #define STAT_BAD_SESSION_ID 7
- #define STAT_AUTH_FAIL 8
- #define STAT_DUPLICATES 9
- #define STAT_SEQ_OUT_OF_RANGE 10
- #define STAT_ASYNC_EVENTS 11
- #define STAT_CONN_DOWN 12
- #define STAT_CONN_UP 13
- #define STAT_BAD_SIZE 14
- #define STAT_DECRYPT_FAIL 15
- #define STAT_INVALID_PAYLOAD 16
- #define STAT_SEQ_ERR 17
- #define STAT_RSP_NO_CMD 18
- #define NUM_STATS 19
- /* Statistics */
- void *stats[NUM_STATS];
- } lan_stat_info_t;
- static const char *lan_stat_names[NUM_STATS] =
- {
- "lan_recv_packets",
- "lan_xmit_packets",
- "lan_rexmits",
- "lan_timed_out",
- "lan_invalid_rmcp",
- "lan_too_short",
- "lan_invalid_auth",
- "lan_bad_session_id",
- "lan_auth_fail",
- "lan_duplicates",
- "lan_seq_out_of_range",
- "lan_async_events",
- "lan_conn_down",
- "lan_conn_up",
- "lan_bad_size",
- "lan_decrypt_fail",
- "lan_invalid_payload",
- "lan_seq_err",
- "lan_rsp_no_cmd"
- };
- /* Per-IP specific information. */
- typedef struct lan_ip_data_s
- {
- int working;
- unsigned int consecutive_failures;
- struct timeval failure_time;
- /* For both RMCP and RMCP+. For RMCP+, the session id is the one
- I receive and the sequence numbers are the authenticated
- ones. */
- unsigned char working_authtype;
- uint32_t session_id;
- uint32_t outbound_seq_num;
- uint32_t inbound_seq_num;
- uint16_t recv_msg_map;
- /* RMCP+ specific info */
- uint32_t unauth_out_seq_num;
- uint32_t unauth_in_seq_num;
- uint16_t unauth_recv_msg_map;
- unsigned char working_integ;
- unsigned char working_conf;
- uint32_t mgsys_session_id;
- ipmi_rmcpp_auth_t ainfo;
- /* Used to hold the session id before the connection is up. */
- uint32_t precon_session_id;
- uint32_t precon_mgsys_session_id;
- ipmi_rmcpp_confidentiality_t *conf_info;
- void *conf_data;
- ipmi_rmcpp_integrity_t *integ_info;
- void *integ_data;
- /* Use for linked-lists of IP addresses. */
- lan_link_t ip_link;
- } lan_ip_data_t;
- #if IPMI_MAX_MSG_LENGTH > 80
- # define LAN_MAX_RAW_MSG IPMI_MAX_MSG_LENGTH
- #else
- # define LAN_MAX_RAW_MSG 80 /* Enough to hold the rmcp+ session messages */
- #endif
- struct lan_data_s
- {
- unsigned int refcount;
- unsigned int users;
- ipmi_con_t *ipmi;
- lan_fd_t *fd;
- int fd_slot;
- unsigned char slave_addr[MAX_IPMI_USED_CHANNELS];
- int is_active;
- /* Have we already been started? */
- int started;
- /* Are we currently in cleanup? Don't allow any outgoing messages. */
- int in_cleanup;
- /* Protects modifiecations to working, curr_ip_addr, RMCP
- sequence numbers, the con_change_handler, and other
- connection-related data. Note that if the seq_num_lock must
- also be held, it must be locked before this lock. */
- ipmi_lock_t *ip_lock;
- /* If 0, we don't have a connection to the BMC right now. */
- int connected;
- /* If 0, we have not yet initialized */
- int initialized;
- /* If 0, the OEM handlers have not been called. */
- int oem_conn_handlers_called;
- /* Number of packets sent on the connection. Used to track when
- to switch between IP addresses. */
- unsigned int num_sends;
- /* The IP address we are currently using. */
- unsigned int curr_ip_addr;
- /* Data about each IP address */
- lan_ip_data_t ip[MAX_IP_ADDR];
- /* We keep a session on each LAN connection. I don't think all
- systems require that, but it's safer. */
- /* From the get channel auth */
- unsigned char oem_iana[3];
- unsigned char oem_aux;
- /* Parms we were configured with. */
- lan_conn_parms_t cparm;
- /* IPMI LAN 1.5 specific info. */
- unsigned char chosen_authtype;
- unsigned char challenge_string[16];
- ipmi_authdata_t authdata;
- /* RMCP+ specific info */
- unsigned int use_two_keys : 1;
- struct {
- unsigned int inuse : 1;
- ipmi_addr_t addr;
- unsigned int addr_len;
-
- ipmi_msg_t msg;
- unsigned char data[LAN_MAX_RAW_MSG];
- ipmi_ll_rsp_handler_t rsp_handler;
- ipmi_msgi_t *rsp_item;
- int use_orig_addr;
- ipmi_addr_t orig_addr;
- unsigned int orig_addr_len;
- os_hnd_timer_id_t *timer;
- lan_timer_info_t *timer_info;
- int retries_left;
- int side_effects;
- /* If -1, just use the normal algorithm. If not -1, force to
- this address. */
- int addr_num;
- /* The number of the last IP address sent on. */
- int last_ip_num;
- } seq_table[64];
- ipmi_lock_t *seq_num_lock;
- /* The current sequence number. Note that we reserve sequence
- number 0 for our own neferous purposes. */
- unsigned int last_seq;
- /* The number of messages that are outstanding with the remote
- MC. */
- unsigned int outstanding_msg_count;
- /* The maximum number of outstanding messages. This must NEVER be
- larger than 63 (64 sequence numbers minus 1 for our reserved
- sequence zero. */
- unsigned int max_outstanding_msg_count;
- /* List of messages waiting to be sent. */
- lan_wait_queue_t *wait_q, *wait_q_tail;
- locked_list_t *event_handlers;
- os_hnd_timer_id_t *audit_timer;
- audit_timer_info_t *audit_info;
- /* Handles connection shutdown reporting. */
- ipmi_ll_con_closed_cb close_done;
- void *close_cb_data;
- /* This lock is used to assure that the conn changes occur in
- proper order. The user code is called with this lock held, but
- it should be harmless to the user as this is the only use for
- it. But the user cannot do a wait on I/O in the handler. */
- ipmi_lock_t *con_change_lock;
- locked_list_t *con_change_handlers;
- locked_list_t *ipmb_change_handlers;
- lan_link_t link;
- locked_list_t *lan_stat_list;
- };
- /************************************************************************
- *
- * Authentication and encryption information and functions.
- *
- ***********************************************************************/
- extern ipmi_payload_t _ipmi_payload;
- static int
- open_format_msg(ipmi_con_t *ipmi,
- 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)
- {
- unsigned char *tmsg = out_data;
- if (msg->data_len > *out_data_len)
- return E2BIG;
- memcpy(tmsg, msg->data, msg->data_len);
- tmsg[0] = seq; /* We use the message tag for the sequence # */
- *out_of_session = 1;
- *out_data_len = msg->data_len;
- return 0;
- }
- static int
- open_get_recv_seq(ipmi_con_t *ipmi,
- unsigned char *data,
- unsigned int data_len,
- unsigned char *seq)
- {
- if (data_len < 1) { /* Minimum size of an IPMI msg. */
- if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
- ipmi_log(IPMI_LOG_DEBUG,
- "%sDropped message because too small(7)",
- IPMI_CONN_NAME(ipmi));
- return EINVAL;
- }
- *seq = data[0];
- return 0;
- }
- static int
- open_handle_recv(ipmi_con_t *ipmi,
- 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)
- {
- ipmi_msg_t *msg = &(rspi->msg);
- if (data_len > sizeof(rspi->data))
- return E2BIG;
- memcpy(rspi->data, data, data_len);
- msg->data = rspi->data;
- msg->data_len = data_len;
- return 0;
- }
- static void
- open_handle_recv_async(ipmi_con_t *ipmi,
- unsigned char *tmsg,
- unsigned int data_len)
- {
- }
- static int
- open_get_msg_tag(unsigned char *tmsg,
- unsigned int data_len,
- unsigned char *tag)
- {
- if (data_len < 8)
- return EINVAL;
- *tag = ipmi_get_uint32(tmsg+4) - 1; /* session id */
- return 0;
- }
- static ipmi_payload_t open_payload =
- { open_format_msg, open_get_recv_seq, open_handle_recv,
- open_handle_recv_async, open_get_msg_tag };
- static ipmi_payload_t *payloads[64] =
- {
- &_ipmi_payload,
- [IPMI_RMCPP_PAYLOAD_TYPE_OPEN_SESSION_REQUEST] = &open_payload,
- [IPMI_RMCPP_PAYLOAD_TYPE_OPEN_SESSION_RESPONSE] = &open_payload
- };
- typedef struct payload_entry_s payload_entry_t;
- struct payload_entry_s
- {
- unsigned int payload_type;
- unsigned char iana[3];
- unsigned int payload_id;
- ipmi_payload_t *payload;
- payload_entry_t *next;
- };
- /* Note that we only add payloads to the head, so no lock is required
- except for addition. */
- static ipmi_lock_t *lan_payload_lock = NULL;
- payload_entry_t *oem_payload_list = NULL;
- int
- ipmi_rmcpp_register_payload(unsigned int payload_type,
- ipmi_payload_t *payload)
- {
- if ((payload_type == IPMI_RMCPP_PAYLOAD_TYPE_IPMI)
- || (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OEM_EXPLICIT)
- || (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OPEN_SESSION_REQUEST)
- || (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OPEN_SESSION_RESPONSE)
- || (payload_type >= 64)
- || ((payload_type >= 0x20) && (payload_type <= 0x27))) /* No OEM here*/
- {
- return EINVAL;
- }
- ipmi_lock(lan_payload_lock);
- if (payloads[payload_type] && payload) {
- ipmi_unlock(lan_payload_lock);
- return EAGAIN;
- }
- payloads[payload_type] = payload;
- ipmi_unlock(lan_payload_lock);
- return 0;
- }
- int
- ipmi_rmcpp_register_oem_payload(unsigned int payload_type,
- unsigned char iana[3],
- unsigned int payload_id,
- ipmi_payload_t *payload)
- {
- payload_entry_t *e;
- payload_entry_t *c;
- e = ipmi_mem_alloc(sizeof(*e));
- if (!e)
- return ENOMEM;
- e->payload_type = payload_type;
- memcpy(e->iana, iana, 3);
- if (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OEM_EXPLICIT)
- e->payload_id = payload_id;
- else
- e->payload_id = 0;
- e->payload = payload;
- ipmi_lock(lan_payload_lock);
- c = oem_payload_list;
- while (c) {
- if ((c->payload_type == payload_type)
- && (memcmp(c->iana, iana, 3) == 0)
- && (c->payload_id == payload_id))
- {
- ipmi_unlock(lan_payload_lock);
- ipmi_mem_free(e);
- return EAGAIN;
- }
- c = c->next;
- }
- e->next = oem_payload_list;
- oem_payload_list = e;
- ipmi_unlock(lan_payload_lock);
- return 0;
- }
- static ipmi_lock_t *lan_auth_lock = NULL;
- typedef struct auth_entry_s auth_entry_t;
- struct auth_entry_s
- {
- unsigned int auth_num;
- unsigned char iana[3];
- ipmi_rmcpp_authentication_t *auth;
- auth_entry_t *next;
- };
- static auth_entry_t *oem_auth_list = NULL;
- static ipmi_rmcpp_authentication_t *auths[64];
- int
- ipmi_rmcpp_register_authentication(unsigned int auth_num,
- ipmi_rmcpp_authentication_t *auth)
- {
- if (auth_num >= 64)
- return EINVAL;
- if (auths[auth_num] && auth)
- return EAGAIN;
-
- auths[auth_num] = auth;
- return 0;
- }
- int
- ipmi_rmcpp_register_oem_authentication(unsigned int auth_num,
- unsigned char iana[3],
- ipmi_rmcpp_authentication_t *auth)
- {
- auth_entry_t *e;
- auth_entry_t *c;
- e = ipmi_mem_alloc(sizeof(*e));
- if (!e)
- return ENOMEM;
- e->auth_num = auth_num;
- memcpy(e->iana, iana, 3);
- e->auth = auth;
- ipmi_lock(lan_auth_lock);
- c = oem_auth_list;
- while (c) {
- if ((c->auth_num == auth_num)
- && (memcmp(c->iana, iana, 3) == 0))
- {
- ipmi_unlock(lan_auth_lock);
- ipmi_mem_free(e);
- return EAGAIN;
- }
- }
- e->next = oem_auth_list;
- oem_auth_list = e;
- ipmi_unlock(lan_auth_lock);
- return 0;
- }
- typedef struct conf_entry_s conf_entry_t;
- struct conf_entry_s
- {
- unsigned int conf_num;
- unsigned char iana[3];
- ipmi_rmcpp_confidentiality_t *conf;
- conf_entry_t *next;
- };
- static conf_entry_t *oem_conf_list = NULL;
- static int
- conf_none_init(ipmi_con_t *ipmi, ipmi_rmcpp_auth_t *ainfo, void **conf_data)
- {
- *conf_data = NULL;
- return 0;
- }
- static void
- conf_none_free(ipmi_con_t *ipmi, void *conf_data)
- {
- }
- static int
- conf_none_encrypt(ipmi_con_t *ipmi,
- void *conf_data,
- unsigned char **payload,
- unsigned int *header_len,
- unsigned int *payload_len,
- unsigned int *max_payload_len)
- {
- return 0;
- }
- static int
- conf_none_decrypt(ipmi_con_t *ipmi,
- void *conf_data,
- unsigned char **payload,
- unsigned int *payload_len)
- {
- return 0;
- }
- static ipmi_rmcpp_confidentiality_t conf_none =
- { conf_none_init, conf_none_free, conf_none_encrypt, conf_none_decrypt};
- static ipmi_rmcpp_confidentiality_t *confs[64] =
- {
- &conf_none
- };
- int ipmi_rmcpp_register_confidentiality(unsigned int conf_num,
- ipmi_rmcpp_confidentiality_t *conf)
- {
- if ((conf_num == 0) || (conf_num >= 64))
- return EINVAL;
- if (confs[conf_num] && conf)
- return EAGAIN;
-
- confs[conf_num] = conf;
- return 0;
- }
- int
- ipmi_rmcpp_register_oem_confidentiality(unsigned int conf_num,
- unsigned char iana[3],
- ipmi_rmcpp_confidentiality_t *conf)
- {
- conf_entry_t *e;
- conf_entry_t *c;
- e = ipmi_mem_alloc(sizeof(*e));
- if (!e)
- return ENOMEM;
- e->conf_num = conf_num;
- memcpy(e->iana, iana, 3);
- e->conf = conf;
- ipmi_lock(lan_auth_lock);
- c = oem_conf_list;
- while (c) {
- if ((c->conf_num == conf_num)
- && (memcmp(c->iana, iana, 3) == 0))
- {
- ipmi_unlock(lan_auth_lock);
- ipmi_mem_free(e);
- return EAGAIN;
- }
- }
- e->next = oem_conf_list;
- oem_conf_list = e;
- ipmi_unlock(lan_auth_lock);
- return 0;
- }
- typedef struct integ_entry_s integ_entry_t;
- struct integ_entry_s
- {
- unsigned int integ_num;
- unsigned char iana[3];
- ipmi_rmcpp_integrity_t *integ;
- integ_entry_t *next;
- };
- static integ_entry_t *oem_integ_list = NULL;
- static int
- integ_none_init(ipmi_con_t *ipmi,
- ipmi_rmcpp_auth_t *ainfo,
- void **integ_data)
- {
- *integ_data = NULL;
- return 0;
- }
- static void
- integ_none_free(ipmi_con_t *ipmi,
- void *integ_data)
- {
- }
- static int
- integ_none_pad(ipmi_con_t *ipmi,
- void *integ_data,
- unsigned char *payload,
- unsigned int *payload_len,
- unsigned int max_payload_len)
- {
- return 0;
- }
- static int
- integ_none_add(ipmi_con_t *ipmi,
- void *integ_data,
- unsigned char *payload,
- unsigned int *payload_len,
- unsigned int max_payload_len)
- {
- return 0;
- }
- static int
- integ_none_check(ipmi_con_t *ipmi,
- void *integ_data,
- unsigned char *payload,
- unsigned int payload_len,
- unsigned int total_len)
- {
- return 0;
- }
- static ipmi_rmcpp_integrity_t integ_none =
- { integ_none_init, integ_none_free, integ_none_pad, integ_none_add,
- integ_none_check };
- static ipmi_rmcpp_integrity_t *integs[64] =
- {
- &integ_none
- };
- int ipmi_rmcpp_register_integrity(unsigned int integ_num,
- ipmi_rmcpp_integrity_t *integ)
- {
- if ((integ_num == 0) || (integ_num >= 64))
- return EINVAL;
- if (integs[integ_num] && integ)
- return EAGAIN;
-
- integs[integ_num] = integ;
- return 0;
- }
- int
- ipmi_rmcpp_register_oem_integrity(unsigned int integ_num,
- unsigned char iana[3],
- ipmi_rmcpp_integrity_t *integ)
- {
- integ_entry_t *e;
- integ_entry_t *c;
- e = ipmi_mem_alloc(sizeof(*e));
- if (!e)
- return ENOMEM;
- e->integ_num = integ_num;
- memcpy(e->iana, iana, 3);
- e->integ = integ;
- ipmi_lock(lan_auth_lock);
- c = oem_integ_list;
- while (c) {
- if ((c->integ_num == integ_num)
- && (memcmp(c->iana, iana, 3) == 0))
- {
- ipmi_unlock(lan_auth_lock);
- ipmi_mem_free(e);
- return EAGAIN;
- }
- }
- e->next = oem_integ_list;
- oem_integ_list = e;
- ipmi_unlock(lan_auth_lock);
- return 0;
- }
- uint32_t
- ipmi_rmcpp_auth_get_my_session_id(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->lan->ip[ainfo->addr_num].precon_session_id;
- }
- uint32_t
- ipmi_rmcpp_auth_get_mgsys_session_id(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->lan->ip[ainfo->addr_num].precon_mgsys_session_id;
- }
- uint8_t
- ipmi_rmcpp_auth_get_role(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->role;
- }
- const unsigned char *
- ipmi_rmcpp_auth_get_username(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 16;
- return ainfo->lan->cparm.username;
- }
- unsigned int
- ipmi_rmcpp_auth_get_username_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->lan->cparm.username_len;
- }
- const unsigned char *
- ipmi_rmcpp_auth_get_password(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 20;
- return ainfo->lan->cparm.password;
- }
- unsigned int
- ipmi_rmcpp_auth_get_password_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->lan->cparm.password_len;
- }
- int
- ipmi_rmcpp_auth_get_use_two_keys(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->lan->use_two_keys;
- }
- const unsigned char *
- ipmi_rmcpp_auth_get_bmc_key(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 20;
- if (ainfo->lan->use_two_keys)
- return ainfo->lan->cparm.bmc_key;
- else
- return ainfo->lan->cparm.password;
- }
- unsigned int
- ipmi_rmcpp_auth_get_bmc_key_len(ipmi_rmcpp_auth_t *ainfo)
- {
- if (ainfo->lan->use_two_keys)
- return ainfo->lan->cparm.bmc_key_len;
- else
- return ainfo->lan->cparm.password_len;
- }
- /* From the get channel auth. */
- const unsigned char *
- ipmi_rmcpp_auth_get_oem_iana(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *len)
- {
- *len = 3;
- return ainfo->lan->oem_iana;
- }
- unsigned char
- ipmi_rmcpp_auth_get_oem_aux(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->lan->oem_aux;
- }
- /* Should be filled in by the auth algorithm. */
- unsigned char *
- ipmi_rmcpp_auth_get_my_rand(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 16;
- return ainfo->my_rand;
- }
- unsigned int
- ipmi_rmcpp_auth_get_my_rand_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->my_rand_len;
- }
- void
- ipmi_rmcpp_auth_set_my_rand_len(ipmi_rmcpp_auth_t *ainfo,
- unsigned int length)
- {
- ainfo->my_rand_len = length;
- }
- unsigned char *
- ipmi_rmcpp_auth_get_mgsys_rand(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 16;
- return ainfo->mgsys_rand;
- }
- unsigned int
- ipmi_rmcpp_auth_get_mgsys_rand_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->mgsys_rand_len;
- }
- void
- ipmi_rmcpp_auth_set_mgsys_rand_len(ipmi_rmcpp_auth_t *ainfo,
- unsigned int length)
- {
- ainfo->mgsys_rand_len = length;
- }
- unsigned char *
- ipmi_rmcpp_auth_get_mgsys_guid(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 16;
- return ainfo->mgsys_guid;
- }
- unsigned int
- ipmi_rmcpp_auth_get_mgsys_guid_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->mgsys_guid_len;
- }
- void
- ipmi_rmcpp_auth_set_mgsys_guid_len(ipmi_rmcpp_auth_t *ainfo,
- unsigned int length)
- {
- ainfo->mgsys_guid_len = length;
- }
- unsigned char *
- ipmi_rmcpp_auth_get_sik(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 20;
- return ainfo->sik;
- }
- unsigned int
- ipmi_rmcpp_auth_get_sik_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->sik_len;
- }
- void
- ipmi_rmcpp_auth_set_sik_len(ipmi_rmcpp_auth_t *ainfo,
- unsigned int length)
- {
- ainfo->sik_len = length;
- }
- unsigned char *
- ipmi_rmcpp_auth_get_k1(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 20;
- return ainfo->k1;
- }
- unsigned int
- ipmi_rmcpp_auth_get_k1_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->k1_len;
- }
- void
- ipmi_rmcpp_auth_set_k1_len(ipmi_rmcpp_auth_t *ainfo,
- unsigned int length)
- {
- ainfo->k1_len = length;
- }
- unsigned char *
- ipmi_rmcpp_auth_get_k2(ipmi_rmcpp_auth_t *ainfo,
- unsigned int *max_len)
- {
- *max_len = 20;
- return ainfo->k2;
- }
- unsigned int
- ipmi_rmcpp_auth_get_k2_len(ipmi_rmcpp_auth_t *ainfo)
- {
- return ainfo->k2_len;
- }
- void
- ipmi_rmcpp_auth_set_k2_len(ipmi_rmcpp_auth_t *ainfo,
- unsigned int length)
- {
- ainfo->k2_len = length;
- }
- static void check_command_queue(ipmi_con_t *ipmi, lan_data_t *lan);
- static int send_auth_cap(ipmi_con_t *ipmi, lan_data_t *lan, int addr_num,
- int force_ipmiv15);
- static os_handler_t *lan_os_hnd;
- #define MAX_CONS_PER_FD 32
- struct lan_fd_s
- {
- int fd;
- os_hnd_fd_id_t *fd_wait_id;
- unsigned int cons_in_use;
- lan_data_t *lan[MAX_CONS_PER_FD];
- lan_fd_t *next, *prev;
- ipmi_lock_t *con_lock;
- /* Main list info. */
- ipmi_lock_t *lock;
- lan_fd_t **free_list;
- lan_fd_t *list;
- };
- /* This is a list, but the only searching is to find an fd with a free
- slot (when creating a new lan). This is O(1) because the first
- entry is guaranteed to have a free slot if any have free slots.
- Note that once one of these is created, it is never destroyed
- (destruction is very difficult because of the race conditions). */
- static ipmi_lock_t *fd_list_lock = NULL;
- static lan_fd_t fd_list;
- static lan_fd_t *fd_free_list;
- #ifdef PF_INET6
- static ipmi_lock_t *fd6_list_lock = NULL;
- static lan_fd_t fd6_list;
- static lan_fd_t *fd6_free_list;
- #endif
- static void data_handler(int fd,
- void *cb_data,
- os_hnd_fd_id_t *id);
- static int
- lan_addr_same(sockaddr_ip_t *a1, sockaddr_ip_t *a2)
- {
- if (a1->ip_addr_len != a2->ip_addr_len)
- return 0;
- if (a1->s_ipsock.s_addr.sa_family != a2->s_ipsock.s_addr.sa_family) {
- if (DEBUG_RAWMSG || DEBUG_MSG_ERR)
- ipmi_log(IPMI_LOG_DEBUG, "Address family mismatch: %d %d",
- a1->s_ipsock.s_addr.sa_family,
- a2->s_ipsock.s_addr.sa_family);
- return 0;
- }
- switch (a1->s_ipsock.s_addr.sa_family) {
- case PF_INET:
- {
- struct sockaddr_in *ip1 = &a1->s_ipsock.s_addr4;
- struct sockaddr_in *ip2 = &a2->s_ipsock.s_addr4;
- if ((ip1->sin_port == ip2->sin_port)
- && (ip1->sin_addr.s_addr == ip2->sin_addr.s_addr))
- return 1;
- }
- break;
- #ifdef PF_INET6
- case PF_INET6:
- {
- struct sockaddr_in6 *ip1 = &a1->s_ipsock.s_addr6;
- struct sockaddr_in6 *ip2 = &a2->s_ipsock.s_addr6;
- if ((ip1->sin6_port == ip2->sin6_port)
- && (bcmp(ip1->sin6_addr.s6_addr, ip2->sin6_addr.s6_addr,
- sizeof(struct in6_addr)) == 0))
- return 1;
- }
- break;
- #endif
- default:
- ipmi_log(IPMI_LOG_ERR_INFO,
- "ipmi_lan: Unknown protocol family: 0x%x",
- a1->s_ipsock.s_addr.sa_family);
- break;
- }
- return 0;
- }
- static void
- move_to_lan_list_end(lan_fd_t *item)
- {
- lan_fd_t *list = item->list;
- item->next->prev = item->prev;
- item->prev->next = item->next;
- item->next = list;
- item->prev = list->prev;
- list->prev->next = item;
- list->prev = item;
- }
- static void
- move_to_lan_list_head(lan_fd_t *item)
- {
- lan_fd_t *list = item->list;
- item->next->prev = item->prev;
- item->prev->next = item->next;
- item->next = list->next;
- item->prev = list;
- list->next->prev = item;
- list->next = item;
- }
- static lan_fd_t *
- find_free_lan_fd(int family, lan_data_t *lan, int *slot)
- {
- ipmi_lock_t *lock;
- lan_fd_t *list, *item;
- lan_fd_t **free_list;
- int rv;
- int i;
- if (family == PF_INET) {
- lock = fd_list_lock;
- list = &fd_list;
- free_list = &fd_free_list;
- }
- #ifdef PF_INET6
- else if (family == PF_INET6) {
- lock = fd6_list_lock;
- list = &fd6_list;
- free_list = &fd6_free_list;
- }
- #endif
- else {
- return NULL;
- }
- ipmi_lock(lock);
- item = list->next;
- retry:
- if (item->cons_in_use < MAX_CONS_PER_FD) {
- int tslot = -1;
- /* Got an entry with a slot, just reuse it. */
- for (i=0; i<MAX_CONS_PER_FD; i++) {
- if (item->lan[i]) {
- /* Check for a matching IP address. Can't have two
- systems with the same address in the same fd entry. */
- unsigned int j, k;
- lan_data_t *l = item->lan[i];
- for (j=0; j<l->cparm.num_ip_addr; j++) {
- for (k=0; k<lan->cparm.num_ip_addr; k++) {
- if (lan_addr_same(&l->cparm.ip_addr[j],
- &lan->cparm.ip_addr[k]))
- {
- /* Found the same address in the same
- lan_data file. Try another one. */
- item = item->next;
- goto retry;
- }
- }
- }
- } else if (tslot < 0)
- tslot = i;
- }
- if (tslot < 0) {
- lan_fd_t *next = item->next;
- /* Can't happen, but log and fix it up. */
- ipmi_log(IPMI_LOG_SEVERE, "ipmi_lan.c: Internal error, count"
- " in lan fd list item incorrect, but we can recover.");
- item->cons_in_use = MAX_CONS_PER_FD;
- move_to_lan_list_end(item);
- item = next;
- goto retry;
- }
- item->cons_in_use++;
- item->lan[tslot] = lan;
- *slot = tslot;
- if (item->cons_in_use == MAX_CONS_PER_FD)
- /* Out of connections in this item, move it to the end of
- the list. */
- move_to_lan_list_end(item);
- } else {
- /* No free entries, create one */
- if (*free_list) {
- /* Pull them off the free list first. */
- item = *free_list;
- *free_list = item->next;
- } else {
- item = ipmi_mem_alloc(sizeof(*item));
- if (item) {
- memset(item, 0, sizeof(*item));
- rv = ipmi_create_global_lock(&item->con_lock);
- if (rv) {
- ipmi_mem_free(item);
- goto out_unlock;
- }
- item->lock = lock;
- item->free_list = free_list;
- item->list = list;
- }
- }
- if (!item)
- goto out_unlock;
- item->next = item;
- item->prev = item;
- item->fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
- if (item->fd == -1) {
- item->next = *free_list;
- *free_list = item;
- item = NULL;
- goto out_unlock;
- }
- /* Bind is not necessary, we don't care what port we are. */
- /* We want it to be non-blocking. */
- rv = fcntl(item->fd, F_SETFL, O_NONBLOCK);
- if (rv) {
- close(item->fd);
- item->next = *free_list;
- *free_list = item;
- item = NULL;
- goto out_unlock;
- }
- rv = lan_os_hnd->add_fd_to_wait_for(lan_os_hnd,
- item->fd,
- data_handler,
- item,
- NULL,
- &(item->fd_wait_id));
- if (rv) {
- close(item->fd);
- item->next = *free_list;
- *free_list = item;
- item = NULL;
- goto out_unlock;
- }
- item->cons_in_use++;
- item->lan[0] = lan;
- *slot = 0;
- /* This will have free items, put it at the head of the list. */
- move_to_lan_list_head(item);
- }
- out_unlock:
- ipmi_unlock(lock);
- return item;
- }
- static void
- release_lan_fd(lan_fd_t *item, int slot)
- {
- ipmi_lock(item->lock);
- item->lan[slot] = NULL;
- item->cons_in_use--;
- if (item->cons_in_use == 0) {
- lan_os_hnd->remove_fd_to_wait_for(lan_os_hnd, item->fd_wait_id);
- close(item->fd);
- item->next->prev = item->prev;
- item->prev->next = item->next;
- item->next = *(item->free_list);
- *(item->free_list) = item;
- } else {
- /* This has free connections, move it to the head of the
- list. */
- move_to_lan_list_head(item);
- }
- ipmi_unlock(item->lock);
- }
- /*
- * We keep two hash tables, one by IP address and one by connection
- * address.
- */
- #define LAN_HASH_SIZE 256
- #define LAN_HASH_SHIFT 6
- static ipmi_lock_t *lan_list_lock = NULL;
- static lan_link_t lan_list[LAN_HASH_SIZE];
- static lan_link_t lan_ip_list[LAN_HASH_SIZE];
- static unsigned int
- hash_lan(const ipmi_con_t *ipmi)
- {
- unsigned int idx;
- idx = (((unsigned long) ipmi)
- >> (sizeof(unsigned long) + LAN_HASH_SHIFT));
- idx %= LAN_HASH_SIZE;
- return idx;
- }
- static int
- hash_lan_addr(const struct sockaddr *addr)
- {
- int idx;
- switch (addr->sa_family)
- {
- case PF_INET:
- {
- struct sockaddr_in *iaddr = (struct sockaddr_in *) addr;
- idx = ntohl(iaddr->sin_addr.s_addr) % LAN_HASH_SIZE;
- break;
- }
- #ifdef PF_INET6
- case PF_INET6:
- {
- /* Use the lower 4 bytes of the IPV6 address. */
- struct sockaddr_in6 *iaddr = (struct sockaddr_in6 *) addr;
- idx = htonl(*((uint32_t *) &iaddr->sin6_addr.s6_addr[12]));
- idx %= LAN_HASH_SIZE;
- break;
- }
- #endif
- default:
- idx = 0;
- }
- idx %= LAN_HASH_SIZE;
- return idx;
- }
- static void
- lan_add_con(lan_data_t *lan)
- {
- unsigned int idx;
- lan_link_t *head;
- unsigned int i;
- ipmi_lock(lan_list_lock);
- idx = hash_lan(lan->ipmi);
- head = &lan_list[idx];
- lan->link.lan = lan;
- lan->link.next = head;
- lan->link.prev = head->prev;
- head->prev->next = &lan->link;
- head->prev = &lan->link;
- for (i=0; i<lan->cparm.num_ip_addr; i++) {
- struct sockaddr *addr = &lan->cparm.ip_addr[i].s_ipsock.s_addr;
- idx = hash_lan_addr(addr);
- head = &lan_ip_list[idx];
- lan->ip[i].ip_link.lan = lan;
- lan->ip[i].ip_link.next = head;
- lan->ip[i].ip_link.prev = head->prev;
- head->prev->next = &lan->ip[i].ip_link;
- head->prev = &lan->ip[i].ip_link;
- }
- ipmi_unlock(lan_list_lock);
- }
- /* Must be called with the lan list lock held. */
- static void
- lan_remove_con_nolock(lan_data_t *lan)
- {
- unsigned int i;
- if (!lan->link.lan)
- /* Hasn't been initialized. */
- return;
- lan->link.prev->next = lan->link.next;
- lan->link.next->prev = lan->link.prev;
- lan->link.lan = NULL;
- for (i=0; i<lan->cparm.num_ip_addr; i++) {
- lan->ip[i].ip_link.prev->next = lan->ip[i].ip_link.next;
- lan->ip[i].ip_link.next->prev = lan->ip[i].ip_link.prev;
- lan->ip[i].ip_link.lan = NULL;
- }
- }
- static lan_data_t *
- lan_find_con(ipmi_con_t *ipmi)
- {
- unsigned int idx;
- lan_link_t *l;
- ipmi_lock(lan_list_lock);
- idx = hash_lan(ipmi);
- l = lan_list[idx].next;
- while (l->lan) {
- if (l->lan->ipmi == ipmi)
- break;
- l = l->next;
- }
- if (l->lan)
- l->lan->refcount++;
- ipmi_unlock(lan_list_lock);
- return l->lan;
- }
- static inline int
- cmp_timeval(struct timeval *tv1, struct timeval *tv2)
- {
- if (tv1->tv_sec < tv2->tv_sec)
- return -1;
-
- if (tv1->tv_sec > tv2->tv_sec)
- return 1;
- if (tv1->tv_usec < tv2->tv_usec)
- return -1;
-
- if (tv1->tv_usec > tv2->tv_usec)
- return 1;
- return 0;
- }
- typedef struct lan_add_stat_info_s
- {
- int statnum;
- int count;
- } lan_add_stat_info_t;
- int
- add_stat_cb(void *cb_data, void *item1, void *item2)
- {
- ipmi_ll_stat_info_t *info = item2;
- lan_stat_info_t *stat = item1;
- lan_add_stat_info_t *sinfo = cb_data;
- if (stat->stats[sinfo->statnum])
- ipmi_ll_con_stat_call_adder(info, stat->stats[sinfo->statnum],
- sinfo->count);
- return LOCKED_LIST_ITER_CONTINUE;
- }
- static inline void
- add_stat(ipmi_con_t *ipmi, int stat, int count)
- {
- lan_data_t *lan = ipmi->con_data;
- lan_add_stat_info_t sinfo;
- sinfo.statnum = stat;
- sinfo.count = count;
- locked_list_iterate(lan->lan_stat_list, add_stat_cb, &sinfo);
- }
- static inline void
- diff_timeval(struct timeval *dest,
- struct timeval *left,
- struct timeval *right)
- {
- if ( (left->tv_sec < right->tv_sec)
- || ( (left->tv_sec == right->tv_sec)
- && (left->tv_usec < right->tv_usec)))
- {
- /* If left < right, just force to zero, don't allow negative
- numbers. */
- dest->tv_sec = 0;
- dest->tv_usec = 0;
- return;
- }
- dest->tv_sec = left->tv_sec - right->tv_sec;
- dest->tv_usec = left->tv_usec - right->tv_usec;
- while (dest->tv_usec < 0) {
- dest->tv_usec += 1000000;
- dest->tv_sec--;
- }
- }
- /* Must be called with the ipmi read or write lock. */
- static int lan_valid_ipmi(ipmi_con_t *ipmi)
- {
- return (lan_find_con(ipmi) != NULL);
- }
- static void lan_cleanup(ipmi_con_t *ipmi);
- static void
- lan_put(ipmi_con_t *ipmi)
- {
- lan_data_t *lan = ipmi->con_data;
- int done;
- ipmi_lock(lan_list_lock);
- lan->refcount--;
- done = lan->refcount == 0;
- /* If done, remove it before we release the lock. */
- if (done)
- lan_remove_con_nolock(lan);
- ipmi_unlock(lan_list_lock);
- if (done)
- lan_cleanup(ipmi);
- }
- static int
- auth_gen(lan_data_t *lan,
- unsigned char *out,
- uint8_t *ses_id,
- uint8_t *seq,
- unsigned char *data,
- unsigned int data_len,
- int addr_num)
- {
- int rv;
- ipmi_auth_sg_t l[] =
- { { ses_id, 4 },
- { data, data_len },
- { seq, 4 },
- { NULL, 0 }};
- rv = ipmi_auths[lan->ip[addr_num].working_authtype]
- .authcode_gen(lan->authdata, l, out);
- return rv;
- }
- static int
- auth_check(lan_data_t *lan,
- uint8_t *ses_id,
- uint8_t *seq,
- unsigned char *data,
- unsigned int data_len,
- unsigned char *code,
- int addr_num)
- {
- int rv;
- ipmi_auth_sg_t l[] =
- { { ses_id, 4 },
- { data, data_len },
- { seq, 4 },
- { NULL, 0 }};
- rv = ipmi_auths[lan->ip[addr_num].working_authtype]
- .authcode_check(lan->authdata, l, code);
- return rv;
- }
- #define IPMI_MAX_LAN_LEN (IPMI_MAX_MSG_LENGTH + 128)
- #define IPMI_LAN_MAX_HEADER 128
- static int
- rmcpp_format_msg(lan_data_t *lan, int addr_num,
- unsigned int payload_type, int in_session,
- unsigned char **msgdata, unsigned int *data_len,
- unsigned int max_data_len, unsigned int header_len,
- unsigned char *oem_iana, unsigned int oem_payload_id,
- const ipmi_con_option_t *options)
- {
- unsigned char *tmsg;
- int rv;
- unsigned int header_used;
- unsigned char *data;
- unsigned int payload_len;
- uint32_t *seqp;
- int do_auth = 1;
- int do_conf = 1;
- if (options) {
- while (options->option != IPMI_CON_OPTION_LIST_END) {
- switch (options->option) {
- case IPMI_CON_MSG_OPTION_AUTH:
- do_auth = options->ival;
- break;
- case IPMI_CON_MSG_OPTION_CONF:
- do_conf = options->ival;
- break;
- default:
- /* Ignore unknown options. */
- break;
- }
- options++;
- }
- }
- do_conf = (do_conf && in_session
- && (lan->ip[addr_num].working_conf
- != IPMI_LANP_CONFIDENTIALITY_ALGORITHM_NONE));
- do_auth = (do_auth && in_session
- && (lan->ip[addr_num].working_integ
- != IPMI_LANP_INTEGRITY_ALGORITHM_NONE));
- if (do_conf) {
- #if 0
- if (! lan->ip[addr_num].working)
- return EAGAIN;
- #endif
- /* Note: This may encrypt the data, the old data will be lost. */
- rv = lan->ip[addr_num].conf_info->conf_encrypt
- (lan->ipmi,
- lan->ip[addr_num].conf_data,
- msgdata,
- &header_len, data_len,
- &max_data_len);
- if (rv)
- return rv;
- }
- payload_len = *data_len;
- if (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OEM_EXPLICIT)
- header_used = 22;
- else
- header_used = 16;
- if (header_used > header_len)
- return E2BIG;
- data = *msgdata - header_used;
- *data_len += header_used;
- max_data_len += header_used;
- data[0] = 6; /* RMCP version 1.0. */
- data[1] = 0;
- data[2] = 0xff;
- data[3] = 0x07;
- data[4] = lan->ip[addr_num].working_authtype;
- data[5] = payload_type;
- tmsg = data+6;
- if (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OEM_EXPLICIT) {
- memcpy(tmsg, oem_iana, 3);
- tmsg += 3;
- *tmsg = 0;
- tmsg++;
- ipmi_set_uint16(tmsg, oem_payload_id);
- tmsg += 2;
- }
- if (in_session) {
- if (do_conf)
- data[5] |= 0x80;
- if (do_auth) {
- seqp = &(lan->ip[addr_num].outbound_seq_num);
- data[5] |= 0x40;
- } else {
- seqp = &(lan->ip[addr_num].unauth_out_seq_num);
- }
- ipmi_set_uint32(tmsg, lan->ip[addr_num].mgsys_session_id);
- tmsg += 4;
- ipmi_set_uint32(tmsg, *seqp);
- tmsg += 4;
- } else {
- ipmi_set_uint32(tmsg, 0); /* session id */
- tmsg += 4;
- ipmi_set_uint32(tmsg, 0); /* session sequence number */
- tmsg += 4;
- seqp = NULL;
- }
- /* Payload length doesn't include the padding. */
- ipmi_set_uint16(tmsg, payload_len);
- if (do_auth) {
- rv = lan->ip[addr_num].integ_info->integ_pad
- (lan->ipmi,
- lan->ip[addr_num].integ_data,
- data, data_len,
- max_data_len);
- if (rv)
- return rv;
- rv = lan->ip[addr_num].integ_info->integ_add
- (lan->ipmi,
- lan->ip[addr_num].integ_data,
- data, data_len,
- max_data_len);
- if (rv)
- return rv;
- }
- if (seqp) {
- (*seqp)++;
- if (*seqp == 0)
- *seqp = 1;
- }
- *msgdata = data;
- return 0;
- }
- static int
- lan15_format_msg(lan_data_t *lan, int addr_num,
- unsigned char **msgdata, unsigned int *data_len)
- {
- unsigned char *data;
- int rv;
- if (lan->ip[addr_num].working_authtype == IPMI_AUTHTYPE_NONE)
- data = *msgdata - 14;
- else
- data = *msgdata - 30;
- data[0] = 6; /* RMCP version 1.0. */
- data[1] = 0;
- data[2] = 0xff;
- data[3] = 0x07;
- data[4] = lan->ip[addr_num].working_authtype;
- ipmi_set_uint32(data+5, lan->ip[addr_num].outbound_seq_num);
- ipmi_set_uint32(data+9, lan->ip[addr_num].session_id);
- /* FIXME - need locks for the sequence numbers. */
- /* Increment the outbound number, but make sure it's not zero. If
- it's already zero, ignore it, we are in pre-setup. */
- if (lan->ip[addr_num].outbound_seq_num != 0) {
- (lan->ip[addr_num].outbound_seq_num)++;
- if (lan->ip[addr_num].outbound_seq_num == 0)
- (lan->ip[addr_num].outbound_seq_num)++;
- }
- if (lan->ip[addr_num].working_authtype == IPMI_AUTHTYPE_NONE) {
- /* No authentication, so no authcode. */
- data[13] = *data_len;
- *data_len += 14;
- } else {
- data[29] = *data_len;
- rv = auth_gen(lan, data+13, data+9, data+5, *msgdata, *data_len,
- addr_num);
- if (rv)
- return rv;
- *data_len += 30;
- }
- *msgdata = data;
- return 0;
- }
- static int
- lan_send_addr(lan_data_t *lan,
- const ipmi_addr_t *addr,
- int addr_len,
- const ipmi_msg_t *msg,
- uint8_t seq,
- int addr_num,
- const ipmi_con_option_t *options)
- {
- unsigned char data[IPMI_MAX_LAN_LEN+IPMI_LAN_MAX_HEADER];
- unsigned char *tmsg;
- unsigned int pos;
- int rv;
- unsigned int payload_type;
- int out_of_session = 0;
- ipmi_payload_t *payload = NULL;
- unsigned char oem_iana[3] = {0, 0, 0};
- unsigned int oem_payload_id = 0;
- if ((addr->addr_type >= IPMI_RMCPP_ADDR_START)
- && (addr->addr_type <= IPMI_RMCPP_ADDR_END))
- {
- /*
- * Let through the dodgy IPMI 1.5 Serial-over-LAN packets, but block
- * anything else that tries to send an RMCP+ packet to a non-RMCP+
- * host.
- */
- if ((addr->addr_type != IPMI_RMCPP_ADDR_SOL)
- && (lan->ip[addr_num].working_authtype != IPMI_AUTHTYPE_RMCP_PLUS))
- return EINVAL;
- payload_type = addr->addr_type - IPMI_RMCPP_ADDR_START;
- } else {
- switch (addr->addr_type) {
- case IPMI_SYSTEM_INTERFACE_ADDR_TYPE:
- case IPMI_IPMB_ADDR_TYPE:
- case IPMI_IPMB_BROADCAST_ADDR_TYPE:
- payload_type = IPMI_RMCPP_PAYLOAD_TYPE_IPMI;
- break;
- default:
- return EINVAL;
- }
- }
- if ((payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OEM_EXPLICIT)
- || ((payload_type >= 0x20) && (payload_type <= 0x27)))
- {
- ipmi_rmcpp_addr_t *addr = (ipmi_rmcpp_addr_t *) addr;
- payload_entry_t *e;
- if (payload_type == IPMI_RMCPP_PAYLOAD_TYPE_OEM_EXPLICIT) {
- memcpy(oem_iana, addr->oem_iana, 3);
- oem_payload_id = addr->oem_payload_id;
- } else {
- memcpy(oem_iana, lan->oem_iana, 3);
- oem_payload_id = 0;
- }
- /* No lock required, only payload additions are allowed. */
- e = oem_payload_list;
- while (e) {
- if ((e->payload_type == payload_type)
- && (memcmp(e->iana, oem_iana, 3) == 0)
- && (e->payload_id == oem_payload_id))
- {
- payload = e->payload;
- break;
- }
- e = e->next;
- }
- } else {
- payload = payloads[payload_type];
- }
- tmsg = data + IPMI_LAN_MAX_HEADER;
- if (!payload) {
- return ENOSYS;
- } else {
- pos = IPMI_MAX_LAN_LEN;
- rv = payload->format_for_xmit(lan->ipmi, addr, addr_len,
- msg, tmsg, &pos,
- &out_of_session, seq);
- if (rv)
- return rv;
- }
- if (lan->ip[addr_num].working_authtype == IPMI_AUTHTYPE_RMCP_PLUS) {
- rv = rmcpp_format_msg(lan, addr_num,
- payload_type, !out_of_session,
- &tmsg, &pos,
- IPMI_MAX_LAN_LEN, IPMI_LAN_MAX_HEADER,
- oem_iana, oem_payload_id, options);
- } else {
- rv = lan15_format_msg(lan, addr_num, &tmsg, &pos);
- if (addr->addr_type == IPMI_RMCPP_ADDR_SOL)
- /*
- * We're sending SoL over IPMI 1.5, which requires that we set
- * a "reserved" bit. This is dodgy.
- */
- tmsg[4] |= 0x80;
- }
- if (rv)
- return rv;
- if (DEBUG_RAWMSG) {
- char buf1[32], buf2[32];
- ipmi_log(IPMI_LOG_DEBUG_START, "%soutgoing seq %d\n addr =",
- IPMI_CONN_NAME(lan->ipmi), seq);
- dump_hex((unsigned char *) &(lan->cparm.ip_addr[addr_num]),
- sizeof(sockaddr_ip_t));
- ipmi_log(IPMI_LOG_DEBUG_CONT,
- "\n msg = netfn=%s cmd=%s data_len=%d.",
- ipmi_get_netfn_string(msg->netfn, buf1, 32),
- ipmi_get_command_string(msg->netfn, msg->cmd, buf2, 32),
- msg->data_len);
- if (pos) {
- ipmi_log(IPMI_LOG_DEBUG_CONT, "\n data =\n ");
- dump_hex(tmsg, pos);
- }
- ipmi_log(IPMI_LOG_DEBUG_END, " ");
- }
- add_stat(lan->ipmi, STAT_XMIT_PACKETS, 1);
- rv = sendto(lan->fd->fd, tmsg, pos, 0,
- (struct sockaddr *) &(lan->cparm.ip_addr[addr_num].s_ipsock),
- lan->cparm.ip_addr[addr_num].ip_addr_len);
- if (rv == -1)
- rv = errno;
- else
- rv = 0;
- return rv;
- }
- static int
- lan_send(lan_data_t *lan,
- const ipmi_addr_t *addr,
- int addr_len,
- const ipmi_msg_t *msg,
- uint8_t seq,
- int *send_ip_num,
- const ipmi_con_option_t *options)
- {
- int curr_ip_addr;
- ipmi_lock(lan->ip_lock);
- if (msg->netfn & 1) {
- /* For unacknowledged packets, don't switch addresses. They
- don't contribute to detecting that the link is down. */
- curr_ip_addr = lan->curr_ip_addr;
- } else if (lan->connected) {
- lan->num_sends++;
- /* We periodically switch between IP addresses, just to make sure
- they are all operational. */
- if ((lan->num_sends % SENDS_BETWEEN_IP_SWITCHES) == 0) {
- unsigned int addr_num = lan->curr_ip_addr + 1;
- if (addr_num >= lan->cparm.num_ip_addr)
- addr_num = 0;
- while (addr_num != lan->curr_ip_addr) {
- if (lan->ip[addr_num].working)
- break;
- addr_num++;
- if (addr_num >= lan->cparm.num_ip_addr)
- addr_num = 0;
- }
- lan->curr_ip_addr = addr_num;
- }
- } else {
- /* Just rotate between IP addresses if we are not yet connected */
- unsigned int addr_num = lan->curr_ip_addr + 1;
- if (addr_num >= lan->cparm.num_ip_addr)
- addr_num = 0;
- lan->curr_ip_addr = addr_num;
- }
- curr_ip_addr = lan->curr_ip_addr;
- ipmi_unlock(lan->ip_lock);
- *send_ip_num = curr_ip_addr;
- return lan_send_addr(lan, addr, addr_len, msg, seq, curr_ip_addr, options);
- }
- typedef struct call_ipmb_change_handler_s
- {
- lan_data_t *lan;
- int err;
- const unsigned char *ipmb_addr;
- unsigned int num_ipmb_addr;
- int active;
- unsigned int hacks;
- } call_ipmb_change_handler_t;
- static int
- call_ipmb_change_handler(void *cb_data, void *item1, void *item2)
- {
- call_ipmb_change_handler_t *info = cb_data;
- ipmi_ll_ipmb_addr_cb handler = item1;
- handler(info->lan->ipmi, info->err, info->ipmb_addr, info->num_ipmb_addr,
- info->active, info->hacks, item2);
- return LOCKED_LIST_ITER_CONTINUE;
- }
- static void
- call_ipmb_change_handlers(lan_data_t *lan, int err,
- const unsigned char ipmb_addr[],
- unsigned int num_ipmb_addr,
- int active, unsigned int hacks)
- {
- call_ipmb_change_handler_t info;
- info.lan = lan;
- info.err = err;
- info.ipmb_addr = ipmb_addr;
- info.num_ipmb_addr = num_ipmb_addr;
- info.active = active;
- info.hacks = hacks;
- locked_list_iterate(lan->ipmb_change_handlers, call_ipmb_change_handler,
- &info);
- }
- static int
- lan_add_ipmb_addr_handler(ipmi_con_t *ipmi,
- ipmi_ll_ipmb_addr_cb handler,
- void *cb_data)
- {
- lan_data_t *lan = (lan_data_t *) ipmi->con_data;
- …
Large files files are truncated, but you can click here to view the full file