/*
 * pins - Print iLO Network Settings
 *
 * This utility program queries HP Proliant server's iLO processor nework settings,
 * and prints them in an XML stream on standard output.
 *
 * (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as 
 * published by the Free Software Foundation.
 *
 * 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

 /*
 * Dependencies : pins requires presence of the "hpilo" driver in host system.
 *
 * Arguments : <none>
 *
 * Release history
 * - 1.0a, 11-Nov-2011, created.
 */

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

#define SLEEP nanosleep(&st, NULL);

int main()
{
	int fd, status, len;
	struct timespec st;
	int step, eof;
	char *c1, *c2;
	int trace;
  
/* xml commands */
	unsigned char h1[8]  = {0x0,0x0,0x0,0x0,0x02,0x0,0x0,0x0};
	unsigned char h2[12] = {0x0,0x0,0x0,0x0,0x50,0x0,0x0,0x0,0x04,0x0,0x0,0x0};
	unsigned char h3[12] = {0x0,0x0,0x0,0x0,0x50,0x0,0x0,0x0,0x05,0x0,0x0,0x0};
	unsigned char h4[12] = {0x0,0x0,0x0,0x0,0x50,0x0,0x0,0x0,0x06,0x0,0x0,0x0};
	unsigned char h5[8]  = {0x0,0x0,0x0,0x0,0x67,0x0,0x0,0x0};
	unsigned char h6[8]  = {0x0,0x0,0x0,0x0,0x43,0x0,0x0,0x0};
	unsigned char h7[8]  = {0x0,0x0,0x01,0x0,0x43,0x0,0x0,0x0};
	unsigned char h8[8]  = {0x0,0x0,0x02,0x0,0x43,0x0,0x0,0x0};
	unsigned char h9[8]  = {0x0,0x0,0x03,0x0,0x43,0x0,0x0,0x0};
	char xml6[] = "<?xml version=\"1.0\"?>\r\n";
	char xml7[] = "<LOCFG VERSION=\"2.24\">";
	char xml8[] = "<RIBCL VERSION=\"2.0\"><LOGIN USER_LOGIN=\"anyBody\" PASSWORD=\"anyThing\"><RIB_INFO MODE=\"read\"><GET_NETWORK_SETTINGS/></RIB_INFO></LOGIN></RIBCL>\r\n";

 	struct {
  		unsigned char header[8];	/* header[0:1] = iLO command length , header included */
  		char xml[4088];
  	} wBuf;
	struct {
  		unsigned char header[12];	/* header[0:1] = iLO response length , header included */
  		char xml[4084];
 	} rBuf;
  
  	char xmlOutput[8192];
	char *xml;

	/* initialize */
	
	trace = 0;
	
	st.tv_sec = 0;
	st.tv_nsec = 1000000;
 	
	bzero(&xmlOutput, sizeof(xmlOutput));
	xml = &xmlOutput[0];
	
	/* open iLO channel */
	fd = open("/dev/hpilo/d0ccb0", O_RDWR|O_EXCL);
	if (fd < 0) {
		perror("iLO device open failed");
		exit(1);
	}
	SLEEP

	/* T1 - no xml */
	step = 10;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h1, &wBuf.header, sizeof(h1));
	len = sizeof(h1);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
	if ((len = read(fd, &rBuf, 72))< 0) goto read_error;
	if(trace) printf("%s%d%s\n","t1: ", len," bytes read");
	SLEEP

	/* T2 - no xml, but 4 extra-header bytes */
	step = 20;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h2, &wBuf.header, sizeof(h2));
	len = sizeof(h2);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
	if ((len = read(fd, &rBuf, 189))< 0) goto read_error;
	if(trace) printf("%s%d%s\n","t2: ", len," bytes read");
	SLEEP	

	/* T3 - no xml, but 4 extra-header bytes */
	step = 30;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h3, &wBuf.header, sizeof(h3));
	len = sizeof(h3);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
	if ((len = read(fd, &rBuf, 189))< 0) goto read_error;
	if(trace) printf("%s%d%s\n","t3: ", len," bytes read");
	SLEEP		

	/* T4 - no xml, but 4 extra-header bytes */
	step = 40;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h4, &wBuf.header, sizeof(h4));
	len = sizeof(h4);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
	if ((len = read(fd, &rBuf, 189))< 0) goto read_error;
	if(trace) printf("%s%d%s\n","t4: ", len," bytes read");
	SLEEP		

	/* T5 - no xml */
	step = 50;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h5, &wBuf.header, sizeof(h5));
	len = sizeof(h5);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
	if ((len = read(fd, &rBuf, 104))< 0) goto read_error;
	if(trace) printf("%s%d%s\n","t5: ", len," bytes read");
	SLEEP			

	/* T6- xml */
	step = 60;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h6, &wBuf.header, sizeof(h6));
	bcopy(&xml6, &wBuf.xml, sizeof(xml6)-1);
	len = sizeof(wBuf.header) + (sizeof(xml6)-1);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
  	bzero(&wBuf, sizeof(wBuf));
  	do {
		step++;
		if ((len = read(fd, &rBuf, 2176))< 0) goto read_error;
		if(trace) printf("%s%d%s%d%s\n","t",step,": ", len," bytes read");
		SLEEP
		eof = *(unsigned int *)&rBuf.header[8];
		/* if(eof == 0) printf("%s\n",&rBuf.xml); */
	} while(eof == 0);

	/* T7 - xml */
	step = 70;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h7, &wBuf.header, sizeof(h7));
	bcopy(&xml7, &wBuf.xml, sizeof(xml7)-1);
	len = sizeof(wBuf.header) + (sizeof(xml7)-1);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
  	bzero(&wBuf, sizeof(wBuf));
  	do {
  		step++;
		if ((len = read(fd, &rBuf, 2176))< 0) goto read_error;
		if(trace) printf("%s%d%s%d%s\n","t",step,": ", len," bytes read");
		SLEEP
		eof = *(unsigned int *)&rBuf.header[8];
		/* if(eof == 0) printf("%s\n",&rBuf.xml); */
	} while(eof == 0);	

	/* T8 - xml */
	step = 80;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h8, &wBuf.header, sizeof(h8));
	bcopy(&xml8, &wBuf.xml, sizeof(xml8)-1);
	len = sizeof(wBuf.header) + (sizeof(xml8)-1);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
  	bzero(&wBuf, sizeof(wBuf));
  	do {
  		step++;
		if ((len = read(fd, &rBuf, 2176))< 0) goto read_error;
		if (trace) printf("%s%d%s%d%s\n","t",step,": ", len," bytes read");
		SLEEP
		eof = *(unsigned int *)&rBuf.header[8];
		if(eof == 0) xml += sprintf(xml,"%s",&rBuf.xml);
	} while(eof == 0);
	
	c1 = strstr(xmlOutput, "<GET_NETWORK_SETTINGS>");
	c2 = strstr(xmlOutput, "</GET_NETWORK_SETTINGS>");
	*(c2+sizeof("</GET_NETWORK_SETTINGS>")+1) = 0;
	printf("%s\n", c1);

	/* T9 - no xml - last command to iLO, no response expected) */
	step = 9;
  	bzero(&wBuf, sizeof(wBuf));
	bcopy(&h9, &wBuf.header, sizeof(h9));
	len = sizeof(h9);
	*(unsigned short *)&wBuf.header[0] = (unsigned short) len;
	if ((status = write(fd, &wBuf, len))!= len) goto write_error;
	SLEEP
	goto finish;

write_error : 
	printf("%s%d\n", "iLO channel write failed in step", step);
	goto finish;
read_error : 
	printf("%s%d\n", "iLO channel read failed in step", step);
	goto finish;
finish :
	close(fd);
	printf("%s\n","finished.");
}
