📄 ipmi_con_lan.cpp
字号:
/* * * Copyright (c) 2003,2004 by FORCE Computers * * Note that this file is based on parts of OpenIPMI * written by Corey Minyard <minyard@mvista.com> * of MontaVista Software. Corey's code was helpful * and many thanks go to him. He gave the permission * to use this code in OpenHPI under BSD license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This * file and program are licensed under a BSD style license. See * the Copying file included with the OpenHPI distribution for * full licensing terms. * * Authors: * Thomas Kanngieser <thomas.kanngieser@fci.com> */#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <unistd.h>#include <assert.h>#include <poll.h>#include <sys/time.h>#include "ipmi_con_lan.h"#define dIpmiMaxLanLen (dIpmiMaxMsgLength + 42)cIpmiConLan::cIpmiConLan( unsigned int timeout, int log_level, struct in_addr addr, int port, tIpmiAuthType auth, tIpmiPrivilege priv, char *user, char *passwd ) : cIpmiCon( timeout, log_level ), m_port( port ), m_auth( auth ), m_priv( priv ), m_auth_method( 0 ), m_session_id( 0 ), m_working_auth( eIpmiAuthTypeNone ), m_ping_count( 0 ), m_outbound_seq_num( 0 ), m_inbound_seq_num( 0 ), m_recv_msg_map( 0 ){ assert( strlen( user ) < dIpmiUsernameMax ); assert( strlen( passwd ) < dIpmiPasswordMax ); m_ip_addr.sin_family = AF_INET; m_ip_addr.sin_port = htons( port ); m_ip_addr.sin_addr = addr; m_port = port; memset( m_username, 0, dIpmiUsernameMax ); strcpy( m_username, user ); memset( m_passwd, 0, dIpmiPasswordMax ); strcpy( m_passwd, passwd );}cIpmiConLan::~cIpmiConLan(){ if ( IsOpen() ) Close(); if ( m_auth_method ) delete m_auth_method;}intcIpmiConLan::AuthGen( unsigned char *out, uint8_t *ses_id, uint8_t *seq, unsigned char *data, unsigned int data_len ){ assert( m_auth == m_working_auth ); assert( m_auth_method ); int rv; cIpmiAuthSg l[] = { { ses_id, 4 }, { data, data_len }, { seq, 4 }, { NULL, 0 } }; rv = m_auth_method->Gen( l, out ); return rv;}intcIpmiConLan::AuthCheck( uint8_t *ses_id, uint8_t *seq, unsigned char *data, unsigned int data_len, unsigned char *code ){ assert( m_auth == m_working_auth ); assert( m_auth_method ); int rv; cIpmiAuthSg l[] = { { ses_id, 4 }, { data, data_len }, { seq, 4 }, { NULL, 0 } }; rv = m_auth_method->Check( l, code ); return rv;}intcIpmiConLan::OpenLanFd(){ int fd; struct sockaddr_in addr; int curr_port; int rv; fd = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ); if ( fd == -1 ) return fd; curr_port = 7000; do { curr_port++; addr.sin_family = AF_INET; addr.sin_port = htons( curr_port ); addr.sin_addr.s_addr = INADDR_ANY; rv = bind( fd, (struct sockaddr *)&addr, sizeof( addr ) ); } while( curr_port < 7100 && rv == -1 ); if ( rv == -1 ) { int tmp_errno = errno; close( fd ); errno = tmp_errno; return -1; } stdlog << "using port " << curr_port << ".\n"; return fd;}unsigned charcIpmiConLan::Checksum( unsigned char *data, int size ){ unsigned char csum = 0; for( ; size > 0; size--, data++ ) csum += *data; return -csum;}intcIpmiConLan::SendPing(){ unsigned char data[dIpmiMaxLanLen]; data[0] = 6; // RMCP version 1.0. data[1] = 0; data[2] = 0xff; // no RMCP ACK data[3] = 0x06; // ASF IpmiSetUint32( data + 4, dAsfIana ); data[8] = 0x80; // presence ping data[9] = 0xff; // ???? data[10] = 0x00; data[11] = 0x00; stdlog << "sending RMCP ping.\n"; int rv = sendto( m_fd, data, 12, 0, (struct sockaddr *)&m_ip_addr, sizeof( struct sockaddr_in ) ); if ( rv == -1 ) return errno; m_ping_count++; return 0;}boolcIpmiConLan::WaitForPong( unsigned int timeout_ms ){ struct pollfd pfd; pfd.fd = m_fd; pfd.events = POLLIN; tResponseType ret; // loop do { int rv = poll( &pfd, 1, timeout_ms ); // timeout if ( !rv ) return false; if ( rv == -1 ) { assert( 0 ); return false; } assert( rv == 1 ); int seq; cIpmiAddr addr; cIpmiMsg msg; ret = ReadResponse( seq, addr, msg ); if ( ret == eResponseTypeMessage ) { stdlog << "reading unexpected message while waiting for pong:\n"; IpmiLogDataMsg( addr, msg ); } } while( ret != eResponseTypePong ); return true;}cIpmiConLan::tResponseTypecIpmiConLan::WaitForResponse( unsigned int timeout_ms, int &seq, cIpmiAddr &addr, cIpmiMsg &msg ){ struct timeval tv; struct timeval timeout; struct timeval t0; // create absolute timeout gettimeofday( &timeout, 0 ); timeout.tv_sec += timeout_ms / 1000; timeout.tv_usec += (timeout_ms % 1000) * 1000; while( timeout.tv_usec > 1000000 ) { timeout.tv_sec++; timeout.tv_usec -= 1000000; } tResponseType ret; // loop do { struct pollfd pfd; pfd.fd = m_fd; pfd.events = POLLIN; // relative timeout gettimeofday( &t0, 0 ); timersub( &timeout, &t0, &tv ); if ( tv.tv_sec < 0 || tv.tv_usec < 0 ) { tv.tv_sec = 0; tv.tv_usec = 0; } timeout_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; int rv = poll( &pfd, 1, timeout_ms ); // timeout if ( !rv ) return eResponseTypeTimeout; if ( rv == -1 ) { assert( 0 ); return eResponseTypeError; } assert( rv == 1 ); ret = ReadResponse( seq, addr, msg ); } while( ret != eResponseTypeMessage ); return eResponseTypeMessage;}SaErrorTcIpmiConLan::SendMsgAndWaitForResponse( const cIpmiAddr &addr, const cIpmiMsg &msg, cIpmiAddr &rsp_addr, cIpmiMsg &rsp_msg ){ cIpmiRequest *r = new cIpmiRequest( addr, msg ); r->m_retries_left = dIpmiDefaultRetries; int seq; while( r->m_retries_left > 0 ) { SaErrorT rv = SendCmd( r ); if ( rv != SA_OK ) continue; tResponseType rt; do { rt = WaitForResponse( m_timeout, seq, rsp_addr, rsp_msg ); } while( rt == eResponseTypeEvent || rt == eResponseTypePong ); RemOutstanding( r->m_seq ); if ( rt == eResponseTypeMessage ) { // check seq if ( seq == r->m_seq ) { delete r; return SA_OK; } } // resend message stdlog << "resending RMCP msg.\n"; } return SA_ERR_HPI_TIMEOUT;}SaErrorTcIpmiConLan::AuthCap(){ SaErrorT rv; cIpmiAddr addr( eIpmiAddrTypeSystemInterface ); cIpmiMsg msg( eIpmiNetfnApp, eIpmiCmdGetChannelAuthCapabilities ); cIpmiAddr rsp_addr; cIpmiMsg rsp_msg; msg.m_data[0] = 0xe; msg.m_data[1] = m_priv; msg.m_data_len = 2; // dbg( "RMCP: sending GetChannelAuthCapabilitiesCmd" ); rv = SendMsgAndWaitForResponse( addr, msg, rsp_addr, rsp_msg ); if ( rv != SA_OK ) return rv; if ( (rsp_msg.m_data[0] != 0 ) || (rsp_msg.m_data_len < 9 ) ) { stdlog << "auth response = " << rsp_msg.m_data[0] << " !\n"; return SA_ERR_HPI_INVALID_DATA; } if ( !( rsp_msg.m_data[2] & (1 << m_auth ) ) ) { stdlog << "Requested authentication not supported !\n"; char str[256] = ""; if ( rsp_msg.m_data[2] & ( 1 << eIpmiAuthTypeNone ) ) strcat( str, " none" ); if ( rsp_msg.m_data[2] & ( 1 << eIpmiAuthTypeMd2 ) ) strcat( str, " md2" ); if ( rsp_msg.m_data[2] & ( 1 << eIpmiAuthTypeMd5 ) ) strcat( str, " md5" ); if ( rsp_msg.m_data[2] & ( 1 << eIpmiAuthTypeStraight ) ) strcat( str, " straight" ); if ( rsp_msg.m_data[2] & ( 1 << eIpmiAuthTypeOem ) ) strcat( str, " oem" ); stdlog << "supported authentication types: " << str << ".\n"; return SA_ERR_HPI_INVALID_DATA; } return SA_OK;}SaErrorTcIpmiConLan::SetSessionPriv(){ SaErrorT rv; cIpmiAddr addr( eIpmiAddrTypeSystemInterface ); cIpmiMsg msg( eIpmiNetfnApp, eIpmiCmdSetSessionPrivilege ); cIpmiAddr rsp_addr; cIpmiMsg rsp_msg; msg.m_data[0] = m_priv; msg.m_data_len = 1; // dbg( "RMCP: sending SetSessionPrivilegeCmd" ); rv = SendMsgAndWaitForResponse( addr, msg, rsp_addr, rsp_msg ); if ( rv != SA_OK ) return rv; if ( rsp_msg.m_data[0] != 0 ) { stdlog << "set session priv: " << rsp_msg.m_data[0] << " !\n"; return SA_ERR_HPI_INVALID_DATA; } if ( rsp_msg.m_data_len < 2 ) { stdlog << "set session priv: msg to small: " << rsp_msg.m_data_len << " !\n"; return SA_ERR_HPI_DATA_LEN_INVALID; } if ( (unsigned char)m_priv != (rsp_msg.m_data[1] & 0xf)) { // Requested privilege level did not match. stdlog << "set session priv: Requested privilege level did not match: " << m_priv << ", " << (rsp_msg.m_data[1] & 0xf ) << " !\n"; return SA_ERR_HPI_INVALID_DATA; } return SA_OK;}SaErrorTcIpmiConLan::ActiveSession(){ SaErrorT rv; cIpmiAddr addr( eIpmiAddrTypeSystemInterface ); cIpmiMsg msg( eIpmiNetfnApp, eIpmiCmdActivateSession ); cIpmiAddr rsp_addr; cIpmiMsg rsp_msg; msg.m_data[0] = m_auth; msg.m_data[1] = m_priv; memcpy( msg.m_data + 2, m_challenge_string, 16 ); IpmiSetUint32( msg.m_data + 18, m_inbound_seq_num ); msg.m_data_len = 22; // dbg( "RMCP: sending ActivateSessionCmd" ); rv = SendMsgAndWaitForResponse( addr, msg, rsp_addr, rsp_msg ); if ( rv != SA_OK ) return rv; if ( rsp_msg.m_data[0] != 0 ) { stdlog << "active session: " << rsp_msg.m_data[0] << " !\n"; return SA_ERR_HPI_INVALID_DATA; } if ( rsp_msg.m_data_len < 11 ) { stdlog << "active session: msg to small: " << rsp_msg.m_data_len << " !\n"; return SA_ERR_HPI_DATA_LEN_INVALID; } m_working_auth = (tIpmiAuthType)(rsp_msg.m_data[1] & 0xf); if ( m_working_auth != 0 && m_working_auth != m_auth ) { // Eh? It didn't return a valid authtype. stdlog << "active session: wrong auth: " << m_working_auth << " !\n"; return SA_ERR_HPI_INVALID_DATA; } m_session_id = IpmiGetUint32( rsp_msg.m_data + 2 ); m_outbound_seq_num = IpmiGetUint32( rsp_msg.m_data + 6 ); // dbg( "reading: sid = 0x%x, seq = 0x%x", // m_session_id, m_outbound_seq_num ); return SA_OK;}SaErrorTcIpmiConLan::Challange(){ SaErrorT rv; cIpmiAddr addr( eIpmiAddrTypeSystemInterface ); cIpmiMsg msg( eIpmiNetfnApp, eIpmiCmdGetSessionChallenge ); cIpmiAddr rsp_addr; cIpmiMsg rsp_msg; msg.m_data[0] = m_auth; msg.m_data_len = 1; memcpy( msg.m_data + 1, m_username, dIpmiUsernameMax ); msg.m_data_len += dIpmiUsernameMax; // dbg( "RMCP: sending GetSessionChallengeCmd" ); rv = SendMsgAndWaitForResponse( addr, msg, rsp_addr, rsp_msg ); if ( rv != SA_OK ) return rv; if ( rsp_msg.m_data[0] != 0 ) { stdlog << "Challange returns: " << rsp_msg.m_data[0] << " !\n"; return SA_ERR_HPI_INVALID_DATA; } if ( rsp_msg.m_data_len < 21 ) { stdlog << "Challange response to small !\n"; return SA_ERR_HPI_DATA_LEN_INVALID; } // Get the temporary session id. m_session_id = IpmiGetUint32( rsp_msg.m_data + 1 ); m_outbound_seq_num = 0; m_working_auth = m_auth; memcpy( m_challenge_string, rsp_msg.m_data + 5, 16 ); // Get a random number of the other end to start sending me sequence // numbers at, but don't let it be zero. while( m_inbound_seq_num == 0 ) m_inbound_seq_num = random(); return SA_OK;}intcIpmiConLan::IfGetMaxSeq(){ return 64;}intcIpmiConLan::IfOpen(){ m_auth_method = IpmiAuthFactory( m_auth ); if ( m_auth_method == 0 ) { stdlog << "unknown authentication method " << m_auth << " !\n"; return -1; } m_auth_method->Init( (unsigned char *)m_passwd ); m_fd = OpenLanFd(); if ( m_fd < 0 ) return -1; SaErrorT rv = CreateSession(); if ( rv != SA_OK ) { close( m_fd ); m_fd = -1; } return m_fd;}SaErrorTcIpmiConLan::CreateSession(){ m_ping_count = 0; m_outbound_seq_num = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -