/**************************************************************** **************************************************************** ** ** ** (C)Copyright 2005-2006, American Megatrends Inc. ** ** ** ** All Rights Reserved. ** ** ** ** 6145-F, Northbelt Parkway, Norcross, ** ** ** ** Georgia - 30071, USA. Phone-(770)-246-8600. ** ** ** **************************************************************** ****************************************************************/ /***************************************************************** * * LANIfc.c * LAN Interface Handler * * Author: Govind Kothandapani * : Bakka Ravinder Reddy * *****************************************************************/ #include #include #include #include #include #include #include #include "com_IPMI_LANIfc.h" #include "com_IPMI_RMCP.h" #include "RMCP.h" #include "LOOPBACK_ifc.h" #include "com_IPMIDefs.h" #include "RMCP.h" #include "MD.h" #include /* getaddrinfo(3) et al. */ #include /* sockaddr_in & sockaddr_in6 definition. */ #include #include #include "main.h" #include "Session.h" #define NO_OF_RETRY 3 #define MAX_POSSIBLE_IPMI_DATA_SIZE 1000 #define MAX_LAN_BUFFER_SIZE 1024 #define LAN_TIMER_INTERVAL 10 #define RMCP_CLASS_MSG_OFFSET 3 #define IPMI_MSG_AUTH_TYPE_OFFSET 4 #define RMCP_ASF_PING_MESSAGE_LENGTH 12 #define IPMI_MSG_LEN_OFFSET 13 #define IPMI20_MSG_LEN_OFFSET 14 #define RMCP_CLASS_MSG_ASF 0x06 #define RMCP_CLASS_MSG_IPMI 0x07 //static void* LANTimer (void*); static void* RecvLANPkt (void*); static int SendLANPkt (MsgPkt_T *pRes ); static void ProcessLANReq ( MsgPkt_T* pReq); static void ProcessBridgeMsg ( MsgPkt_T* pReq ); static int InitUDPSocket(void); static int SetIPv4Header(int socketID); int gSocket_lo = -1; int gFd_LoIfcQ, gFd_LoResQ; /** * @brief LAN Interface Task. **/ void *LoIfcTask (void *param) { MsgPkt_T Req; int i,BMC,Buffer = 0; uint8_t ethindex=0; prctl(PR_SET_NAME,__FUNCTION__,0,0,0); int curThreadIndex = 0; /* Init LAN SMB */ printf("LoIfc Task Started... \n"); //create LAN_IFC_Q if(-1 != access(LO_IFC_Q, F_OK)) { remove(LO_IFC_Q); } if(0 != mkfifo (LO_IFC_Q, 0777)) { printf("%s: Create %s fifo failed! %s\n", __FUNCTION__, LO_IFC_Q, strerror(errno)); return (void*)-1; } gFd_LoIfcQ = open (LO_IFC_Q, O_RDWR); if(-1 == gFd_LoIfcQ) { printf("%s: Open %s fifo failed! %s\n", __FUNCTION__, LO_IFC_Q, strerror(errno)); return (void*)-1; } //create LAN_RES_Q if(-1 != access(LO_RES_Q, F_OK)) { remove(LO_RES_Q); } if(0 != mkfifo (LO_RES_Q, 0777)) { printf("%s: Create %s fifo failed! %s\n", __FUNCTION__, LO_RES_Q, strerror(errno)); return (void*)-1; } gFd_LoResQ = open (LO_RES_Q, O_RDWR); if(-1 == gFd_LoResQ) { printf("%s: Open %s fifo failed! %s\n", __FUNCTION__, LO_RES_Q, strerror(errno)); return (void*)-1; } /* Create LAN socket */ if(0 != Lo_InitUDPSocket()) { printf("%s: Create UDP socket failed! %s\n", __FUNCTION__, strerror(errno)); return (void *)-1; } /*Create a thread to recv UDS Pkt */ gThreadIndex++; if(0 != pthread_create(&gThreadIDs[gThreadIndex],NULL,RecvLoPkt,NULL)) { printf("%s: Create RecvLANPkt thread failed! %s\n", __FUNCTION__, strerror(errno)); return (void *)-1; } while (1) { /* Wait for a message in LANIfc interface Queue */ if (0 != GetMsg (gFd_LoIfcQ, &Req, WAIT_INFINITE)) { printf("LANIfc.c : Error fetching message from hLANIfc_Q\n"); continue; } switch (Req.Param) { case LAN_SMB_REQUEST : ProcessLANReq (&Req); break; case BRIDGING_REQUEST : ProcessBridgeMsg (&Req ); break; default : printf ("LOOPBACK_Ifc.c : Invalid request\n"); break; } } } /** * @fn InitUnixDomainSocket * @brief This function is used to create the Socket for each BMC * @param BMCInst **/ static int Lo_InitUDPSocket(void) { struct sockaddr_in local; char UDPIfcName [MAX_STR_LENGTH]; int reuseaddr = 1; memset(UDPIfcName,0,sizeof(UDPIfcName)); if(gSocket_Lo != -1) { close(gSocket_Lo); gSocket_Lo = -1; } memset(&local, 0, sizeof(struct sockaddr_in)); local.sin_family = AF_INET; local.sin_port = htons(623); local.sin_addr.s_addr = htonl(INADDR_ANY); gSocket_LAN = socket(AF_INET,SOCK_DGRAM,0); if(-1 == gSocket_LAN) { printf("LANIfc.c : Unable to create the UDP Socket\n"); return -1; } //printf("UDP Socket %d\n", gSocket_LAN); strcpy(UDPIfcName,"eth0"); if (0 != setsockopt (gSocket_LAN, SOL_SOCKET,SO_BINDTODEVICE, UDPIfcName, sizeof (UDPIfcName)+1)) { printf("LANIfc.c: SetSockOpt(SO_BINDTODEVICE) Failed for UDP Socket\n"); return -1; } if (0 != setsockopt(gSocket_LAN, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int))) { printf("LANIfc.c: Setsockopt(SO_REUSEADDR) Failed for UDP socket\n"); } SetIPv4Header(gSocket_LAN); /* Bind */ if (-1 == bind(gSocket_LAN,(struct sockaddr *)&local,sizeof(local))) { printf("LANIfc.c : Error binding UDP Socket, %d, %s\n", errno, strerror(errno)); return -1; } //printf("Create UDP socket successfully, socket %d, port: %d\n", gSocket_LAN, local.sin_port); return 0; } /** * @fn ReadData * @brief This function receives the IPMI LAN request packets * * @param pMsgPkt - pointer to message packet * @param Socket - Socket handle **/ static int ReadData (MsgPkt_T *pMsgPkt, int Socket ) { unsigned int SourceLen = 0,Index,SocktIndex=0,addrlen=0; int Channel = 0; uint8_t *pData = pMsgPkt->Data; int16_t Len = 0; uint16_t RecvdLen = 0; uint16_t IPMIMsgLen = 0; uint16_t IPMIMsgOffset = 0; struct sockaddr_in Sourcev4; struct sockaddr_in server_v4addr; void *Source = NULL ; void *server_addr = NULL ; uint8_t WaitCount; int i; Source = &Sourcev4; SourceLen = sizeof (Sourcev4); //printf("ReadData:\n"); //SourceLen = sizeof (Source); /* Read minimum bytes to find class of message */ while (RecvdLen < RMCP_CLASS_MSG_OFFSET) { Len = recvfrom (Socket, &pData[RecvdLen], MAX_LAN_BUFFER_SIZE, 0, (struct sockaddr *)Source, &SourceLen); // printf("Recv1 %d: ", Len); // for(i=0;i= -1) && (Len <= 0)) { return -1; } RecvdLen += (uint16_t)Len; } /* if RMCP Presence Ping Requested */ if (RMCP_CLASS_MSG_ASF == pData[RMCP_CLASS_MSG_OFFSET]) { /* Read remaining RMCP ASF ping message */ while (RecvdLen < RMCP_ASF_PING_MESSAGE_LENGTH) { Len = recvfrom (Socket, &pData[RecvdLen], MAX_LAN_BUFFER_SIZE, 0, (struct sockaddr *)Source, &SourceLen); // printf("Recv2 %d: ", Len); // for(i=0;i= -1) && (Len <= 0)) { return -1; } RecvdLen += (uint16_t)Len; } } /*else if IPMI RMCP request */ else if (RMCP_CLASS_MSG_IPMI == pData[RMCP_CLASS_MSG_OFFSET]) { /* Read minimum no of bytes for IPMI Auth type offset*/ while (RecvdLen < IPMI_MSG_AUTH_TYPE_OFFSET) { Len = recvfrom (Socket, &pData[RecvdLen], MAX_LAN_BUFFER_SIZE, 0,(struct sockaddr *)Source, &SourceLen); // printf("Recv3 %d: ", Len); // for(i=0;i= -1) && (Len <= 0)) { return -1; } RecvdLen += (uint16_t)Len; } /* Get the IPMI message length offset based on format/authentication type */ if (pData [IPMI_MSG_AUTH_TYPE_OFFSET] == RMCP_PLUS_FORMAT) { IPMIMsgOffset = IPMI20_MSG_LEN_OFFSET + 1; } else if (pData [IPMI_MSG_AUTH_TYPE_OFFSET] == AUTH_TYPE_NONE) { IPMIMsgOffset = IPMI_MSG_LEN_OFFSET; } else { IPMIMsgOffset = IPMI_MSG_LEN_OFFSET + AUTH_CODE_LEN; } /* Read minimum no of bytes for IPMI message length offset*/ while (RecvdLen < IPMIMsgOffset) { Len = recvfrom (Socket, &pData[RecvdLen], MAX_LAN_BUFFER_SIZE, 0,(struct sockaddr *)Source, &SourceLen); // printf("Recv4 %d: ", Len); // for(i=0;i= -1) && (Len <= 0)) { return -1; } RecvdLen += (uint16_t)Len; } /* Get the IPMI message length based on RMCP format type */ if (pData [IPMI_MSG_AUTH_TYPE_OFFSET] == RMCP_PLUS_FORMAT) { IPMIMsgLen = *((uint16_t*)&pData [IPMI20_MSG_LEN_OFFSET]); } else { IPMIMsgLen = pData [IPMIMsgOffset]; } /* We are assuming that we cannot get more than 17 K data in IPMI Msg */ /* This work around for fix the malformed IPMI Msg length */ if(IPMIMsgOffset > MAX_POSSIBLE_IPMI_DATA_SIZE ) { return -1; } /* Read the remaining IPMI message packets */ WaitCount = 3; while (RecvdLen < IPMIMsgLen) { Len = recvfrom (Socket, &pData[RecvdLen], MAX_LAN_BUFFER_SIZE, 0,(struct sockaddr *)Source, &SourceLen); // printf("Recv5 %d: ", Len); // for(i=0;i= -1) && (Len <= 0)) { if(Len == -1) { if(errno == EAGAIN) { WaitCount--; } else return -1; } else return -1; } if(WaitCount == 0) { return -1; } RecvdLen += (uint16_t)Len; } }/* else other RMCP class are not supported. */ else { printf ("Unknown RMCP class\n"); } pMsgPkt->Size = RecvdLen; pMsgPkt->UDPPort = ((struct sockaddr_in *)Source)->sin_port; pMsgPkt->Socket = Socket; pMsgPkt->Channel = LAN_RMCP_CHANNEL; // printf("\nLan received %d: ",RecvdLen); // for(i=0;iIPAddr, &((struct sockaddr_in *)Source)->sin_addr.s_addr, sizeof (struct in_addr)); } pMsgPkt->Param = LAN_SMB_REQUEST; return 0; } void *RecvLANPkt(void *pArg) { MsgPkt_T MsgPkt; struct timeval Timeout; struct sockaddr_in local; int RetVal,max,Index = 0; unsigned int locallen; prctl(PR_SET_NAME,__FUNCTION__,0,0,0); fd_set fds; memset(&local,0,sizeof(local)); locallen=sizeof(local); printf("RecvLANPkt start...\n"); while(1) { Timeout.tv_sec = SESSION_TIMEOUT; Timeout.tv_usec = 0; FD_ZERO(&fds); if(gSocket_LAN != -1) FD_SET(gSocket_LAN,&fds); max = gSocket_LAN+1; /*Waits for an event to occur on socket*/ RetVal = select (max, &fds, NULL, NULL, &Timeout); if (-1 == RetVal) { continue; } if (0 == RetVal) { /* Its due to timeout - continue */ continue; } /*Accepting Connection*/ if(FD_ISSET(gSocket_LAN,&fds)) { if(0 == ReadData( &MsgPkt,gSocket_LAN)) { /* Post the request packet to LAN Interface Queue */ if (0 != PostMsg (gFd_LanIfcQ, &MsgPkt)) { printf ("Warning: LANIfc.c Error posting message to LANIfc Q\n"); } } else { close(gSocket_LAN); gSocket_LAN = -1; } } } } /** * @fn SendLANPkt * @brief This function sends the IPMI LAN Response to the requester * @param pRes - Response message. **/ int SendLANPkt (MsgPkt_T *pRes ) { struct sockaddr_in Dest; //struct stat Stat; int ret = 0; /* Set the destination UDP port and IP Address */ Dest.sin_family = AF_INET; Dest.sin_port = pRes->UDPPort; memcpy (&Dest.sin_addr.s_addr, pRes->IPAddr, sizeof (struct in_addr)); /* Send the LAN response packet */ //int i; //printf("\nLan send socket: %d, byte: %d: ", pRes->Socket, pRes->Size); // for (i = 0; i < pRes->Size; ++i) // { // printf("%#x ", pRes->Data[i]); // } //printf("\n"); //Check the socket before send a message on a socket //if (fstat(pRes->Socket, &Stat) != -1) { ret = sendto (pRes->Socket, pRes->Data, pRes->Size, 0, (struct sockaddr*)&Dest, sizeof (Dest)); if (ret == -1) { printf ("Warning: LANIfc.c Error sending response packets to LAN, %s\n",strerror(errno)); } // else // { // printf ("LANIfc.c : LAN packet sent successfully\n"); // } } return 1; } /** * @brief Process SMB Request. * @param pReq - Request message. **/ static void ProcessLANReq ( MsgPkt_T* pReq ) { MsgPkt_T Res; SessionInfo_T* pSessionInfo; SessionHdr_T* pSessionHdr; SessionHdr2_T* pSessionHdr2; uint32_t SessionID =0; /* Copy the request to response */ Res = *pReq; /* Save the LAN header inofmation */ pSessionHdr = (SessionHdr_T*) (((RMCPHdr_T*)pReq->Data) + 1); pSessionHdr2 = (SessionHdr2_T*)(((RMCPHdr_T*)pReq->Data) + 1); if (RMCP_PLUS_FORMAT == pSessionHdr->AuthType) { SessionID = pSessionHdr2->SessionID; pSessionInfo = getSessionInfo (SESSION_ID_INFO, &SessionID); } else { SessionID = pSessionHdr->SessionID; pSessionInfo = getSessionInfo (SESSION_ID_INFO, &SessionID ); } if (NULL != pSessionInfo) { pSessionInfo->LANRMCPPkt.UDPHdr.SrcPort = Res.UDPPort; pSessionInfo->hSocket = Res.Socket; //SocktIndex=GetSocketInfoIndex(pSessionInfo->hSocket ); memcpy (pSessionInfo->LANRMCPPkt.IPHdr.Srcv4Addr, Res.IPAddr, sizeof (struct in_addr)); memcpy (&pSessionInfo->LANRMCPPkt.RMCPHdr, Res.Data, sizeof (RMCPHdr_T)); } /* Process the RMCP Request */ Res.Size = ProcessRMCPReq ((RMCPHdr_T*)pReq->Data, (RMCPHdr_T*)Res.Data); /* ResLen is 0, don't send the packet */ if (0 == Res.Size ) { printf ("Note: LANIfc.c LAN request packet dropped, not processed\n"); return; } /* Sent the response packet */ SendLANPkt (&Res); return; } /*-------------------------------------------- * ProcessBridgeMsg *--------------------------------------------*/ static void ProcessBridgeMsg ( MsgPkt_T* pReq ) { MsgPkt_T ResPkt; uint16_t PayLoadLen = 0; uint8_t PayLoadType = 0; SessionInfo_T *pSessionInfo = getSessionInfo (SESSION_HANDLE_INFO, pReq->Data); //printf ("LANIfc: Bridge Request\n"); if (NULL == pSessionInfo) { printf ("Warning: LANIfc ProcessBridgeMsg - No Session with the LAN\n"); return; } /* Copy Lan RMCP headers from Session Record */ ResPkt.UDPPort = pSessionInfo->LANRMCPPkt.UDPHdr.SrcPort; ResPkt.Socket = pSessionInfo->hSocket; memcpy (ResPkt.IPAddr, pSessionInfo->LANRMCPPkt.IPHdr.Srcv4Addr, sizeof (struct in_addr)); memcpy (ResPkt.Data, &pSessionInfo->LANRMCPPkt.RMCPHdr, sizeof (RMCPHdr_T)); // #if IPMI20_SUPPORT == 1 // if (RMCP_PLUS_FORMAT == pSessionInfo->AuthType) // { // /* Fill Session Header */ // pSessionInfo->OutboundSeq++; // PayLoadLen = pReq->Size - 1; // PayLoadType = pReq->Cmd; // PayLoadType |= (pSessionInfo->SessPyldInfo[PayLoadType].AuxConfig[0] & 0xC0); // PayLoadLen = Frame20Payload (PayLoadType, ( RMCPHdr_T*)&ResPkt.Data [0], // &pReq->Data[1], PayLoadLen, pSessionInfo ); // } // else // #endif /*IPMI20_SUPPORT == 1*/ { /* Fill Session Header */ SessionHdr_T* pSessionHdr = ( SessionHdr_T*)(&ResPkt.Data [sizeof(RMCPHdr_T)]); uint8_t* pPayLoad = ( uint8_t*)(pSessionHdr + 1); pSessionHdr->AuthType = pSessionInfo->AuthType; pSessionHdr->SessionSeqNum = pSessionInfo->OutboundSeq++; pSessionHdr->SessionID = pSessionInfo->SessionID; /* If AuthType is not 0 - Compute AuthCode */ if (0 != pSessionInfo->AuthType) { PayLoadLen = AUTH_CODE_LEN; pPayLoad [PayLoadLen++] = pReq->Size - 1; memcpy (&pPayLoad [PayLoadLen], (pReq->Data + 1), (pReq->Size - 1)); PayLoadLen += pReq->Size; PayLoadLen--; PayLoadLen += sizeof (SessionHdr_T) + sizeof (RMCPHdr_T); ComputeAuthCode (pSessionInfo->Password, pSessionHdr, ( IPMIMsgHdr_T*) &pPayLoad [AUTH_CODE_LEN+1], pPayLoad, MULTI_SESSION_CHANNEL); } else { pPayLoad [PayLoadLen++] = pReq->Size - 1; /* Fill the ipmi message */ memcpy (&pPayLoad [PayLoadLen], (pReq->Data + 1), (pReq->Size - 1)); PayLoadLen += pReq->Size; PayLoadLen--; PayLoadLen += sizeof (SessionHdr_T) + sizeof (RMCPHdr_T); } } ResPkt.Size = PayLoadLen; if(pSessionInfo->Activated) { /* Sent the response packet */ SendLANPkt (&ResPkt); } return; } // /** // * @fn LANTimer // * @brief This function handles the time out for lan connections. // * @param None // **/ // static // void* LANTimer (void *pArg) // { // int *inst = (int*)pArg; // int BMCInst= *inst; // prctl(PR_SET_NAME,__FUNCTION__,0,0,0); // while (1) // { // UpdateTimeout (BMCInst); // sleep (LAN_TIMER_INTERVAL); // } // return 0; // } static int SetIPv4Header(int socketID) { uint8_t flag = 0; uint8_t TimeToLive = 64; //uint8_t TypeOfService = 0; if (setsockopt(socketID, IPPROTO_IP, IP_TTL, &TimeToLive, sizeof(uint8_t)) == -1) { printf("LANIfc.c: Setsockopt(IP_TTL) Failed for UDP socket:"); return -1; } flag = 0; /* Never send DF frames. */ if (setsockopt(socketID, IPPROTO_IP, IP_MTU_DISCOVER, &(flag), sizeof(uint8_t)) == -1) { printf("LANIfc.c: Setsockopt(IP_MTU_DISCOVER) Failed for UDP socket\n"); return -1; } // if (setsockopt(socketID, IPPROTO_IP, IP_TOS, // &(pBMCInfo->LANCfs[ethIndex].Ipv4HdrParam.TypeOfService), sizeof(INT8U)) == -1) // { // printf("LANIfc.c: Setsockopt(IP_TOS) Failed for UDP socket\n"); // return -1; // } return 0; }