PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/OpenIPMI-2.0.18/sample/rmcp_ping.c

#
C | 324 lines | 269 code | 25 blank | 30 comment | 88 complexity | 3928268a416e252f28af1969ca1d280a MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. /*
  2. * rmcp_ping.c
  3. *
  4. * OpenIPMI RMCP pinger
  5. *
  6. * Author: Montavista Software
  7. * Corey Minyard <cminyard@mvista.com>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public License
  11. * as published by the Free Software Foundation; either version 2 of
  12. * the License, or (at your option) any later version.
  13. *
  14. *
  15. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  16. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  20. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  21. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  23. * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  24. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. * You should have received a copy of the GNU Lesser General Public
  27. * License along with this program; if not, write to the Free
  28. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <unistd.h>
  34. #include <fcntl.h>
  35. #include <sys/time.h>
  36. #include <sys/socket.h>
  37. #include <netinet/in.h>
  38. #include <arpa/inet.h>
  39. #include <sys/select.h>
  40. #include <netdb.h>
  41. unsigned char ping_msg[12] =
  42. {
  43. 0x06, /* RMCP version 1.0 */
  44. 0x00, /* reserved */
  45. 0xff, /* RMCP seq num, not used for IPMI */
  46. 0x06, /* ASF message */
  47. 0x00, 0x00, 0x11, 0xbe, /* ASF IANA */
  48. 0x80, /* Presence Ping */
  49. 0x00, /* Message tag */
  50. 0x00, /* Reserved */
  51. 0x00 /* Data Length */
  52. };
  53. static char *progname;
  54. static void
  55. usage(void)
  56. {
  57. fprintf(stderr,
  58. "Send an RMCP ping packet onces a second to the destination,\n");
  59. fprintf(stderr,
  60. "printing unique responses it receives\n");
  61. fprintf(stderr,
  62. "Usage:\n");
  63. fprintf(stderr,
  64. " %s [-p <port>] [-t <waittime>] [-s <starttag>]"
  65. " [-d] [destination]\n",
  66. progname);
  67. fprintf(stderr,
  68. " -p - Destination port, defaults to 623\n");
  69. fprintf(stderr,
  70. " -t - Sets the number of seconds to wait for responses"
  71. " (default 10)\n");
  72. fprintf(stderr,
  73. " -s - Sets the start tag to start sending at"
  74. " (0-254, default 0\n");
  75. fprintf(stderr,
  76. " -d - enable debugging\n");
  77. fprintf(stderr,
  78. " destination - the target address, default is the broadcast\n");
  79. fprintf(stderr,
  80. " address (default 255.255.255.255)\n");
  81. exit(1);
  82. }
  83. int port = 0x26f;
  84. int waittime = 10;
  85. int starttag = 0;
  86. int debug_packet = 0;
  87. struct socklist
  88. {
  89. struct in_addr addr;
  90. struct socklist *next;
  91. };
  92. struct socklist *socklist = NULL;
  93. static int
  94. add_host(struct sockaddr *addr)
  95. {
  96. struct socklist *curr = socklist;
  97. struct sockaddr_in *ip;
  98. if (addr->sa_family != AF_INET)
  99. return 0;
  100. ip = (struct sockaddr_in *) addr;
  101. while (curr) {
  102. if (ip->sin_addr.s_addr == curr->addr.s_addr)
  103. break;
  104. curr = curr->next;
  105. }
  106. if (curr)
  107. return 0;
  108. curr = malloc(sizeof(*curr));
  109. curr->addr = ip->sin_addr;
  110. curr->next = socklist;
  111. socklist = curr;
  112. return 1;
  113. }
  114. int
  115. main(int argc, char *argv[])
  116. {
  117. unsigned char rsp[28];
  118. int sock;
  119. int rv;
  120. struct sockaddr dest;
  121. size_t destlen;
  122. struct sockaddr src;
  123. int val;
  124. socklen_t fromlen;
  125. fd_set readfds;
  126. struct timeval currtime;
  127. struct timeval endtime;
  128. struct timeval twait;
  129. char host[200];
  130. char serv[200];
  131. char *addrname;
  132. int send_next;
  133. int i;
  134. char *end;
  135. progname = argv[0];
  136. for (i=1; i<argc; i++) {
  137. if (argv[i][0] != '-')
  138. break;
  139. if (argv[i][1] == '\0')
  140. usage();
  141. if (strcmp(argv[i], "--") == 0) {
  142. i++;
  143. break;
  144. } else if (strcmp(argv[i], "-p") == 0) {
  145. i++;
  146. if (i >= argc) {
  147. fprintf(stderr, "No parameter given for -p\n\n");
  148. usage();
  149. }
  150. port = strtoul(argv[i], &end, 0);
  151. if (port < 0 || port > 65535 || *end != '\0') {
  152. fprintf(stderr, "Wrong port specified for -p\n\n");
  153. usage();
  154. }
  155. } else if (strcmp(argv[i], "-t") == 0) {
  156. i++;
  157. if (i >= argc) {
  158. fprintf(stderr, "No parameter given for -t\n\n");
  159. usage();
  160. }
  161. waittime = strtoul(argv[i], &end, 0);
  162. if (waittime < 0 || *end != '\0') {
  163. fprintf(stderr, "Wrong waittime specified for -t\n\n");
  164. usage();
  165. }
  166. } else if (strcmp(argv[i], "-s") == 0) {
  167. i++;
  168. if (i >= argc) {
  169. fprintf(stderr, "No parameter given for -s\n\n");
  170. usage();
  171. }
  172. starttag = strtoul(argv[i], &end, 0);
  173. if (starttag < 0 || starttag > 254 || *end != '\0') {
  174. fprintf(stderr, "Invalid start tag for -s\n\n");
  175. usage();
  176. }
  177. } else if (strcmp(argv[i], "-d") == 0) {
  178. debug_packet++;
  179. }
  180. }
  181. if (i < argc) {
  182. struct addrinfo hints, *res0;
  183. char ports[16];
  184. snprintf(ports, sizeof(ports), "%d", port);
  185. memset(&hints, 0, sizeof(hints));
  186. hints.ai_family = PF_UNSPEC;
  187. hints.ai_socktype = SOCK_DGRAM;
  188. rv = getaddrinfo(argv[i], ports, &hints, &res0);
  189. if (rv != 0) {
  190. fprintf(stderr, "Unable to handle given address: %s\n\n",
  191. gai_strerror(rv));
  192. usage();
  193. }
  194. dest = *(res0->ai_addr);
  195. destlen = res0->ai_addrlen;
  196. freeaddrinfo(res0);
  197. } else {
  198. struct sockaddr_in *ip = (struct sockaddr_in *) &dest;
  199. ip->sin_family = AF_INET;
  200. ip->sin_port = htons(port);
  201. ip->sin_addr.s_addr = INADDR_BROADCAST;
  202. destlen = sizeof(*ip);
  203. }
  204. sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  205. if (sock == -1) {
  206. perror("socket");
  207. exit(1);
  208. }
  209. /* We want it to be non-blocking. */
  210. rv = fcntl(sock, F_SETFL, O_NONBLOCK);
  211. if (rv) {
  212. close(sock);
  213. perror("fcntl(sock, F_SETFL, O_NONBLOCK)");
  214. exit(1);
  215. }
  216. val = 1;
  217. rv = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val));
  218. if (rv) {
  219. close(sock);
  220. perror("setsockopt(sock, SO_BROADCAST)");
  221. exit(1);
  222. }
  223. gettimeofday(&currtime, NULL);
  224. endtime = currtime;
  225. endtime.tv_sec += waittime;
  226. send_next = 1;
  227. for (;;) {
  228. if ((endtime.tv_sec < currtime.tv_sec)
  229. || ((endtime.tv_sec == currtime.tv_sec)
  230. && (endtime.tv_usec < currtime.tv_usec)))
  231. break;
  232. if (send_next) {
  233. ping_msg[9] = starttag;
  234. starttag++;
  235. if (starttag > 254)
  236. starttag = 0;
  237. rv = sendto(sock, ping_msg, sizeof(ping_msg), 0, &dest, destlen);
  238. if (rv < 0) {
  239. close(sock);
  240. perror("sendto");
  241. exit(1);
  242. }
  243. send_next = 0;
  244. }
  245. twait.tv_usec = 0;
  246. twait.tv_sec = 1;
  247. FD_ZERO(&readfds);
  248. FD_SET(sock, &readfds);
  249. rv = select(sock+1, &readfds, NULL, NULL, &twait);
  250. if (rv < 0) {
  251. close(sock);
  252. perror("select");
  253. exit(1);
  254. }
  255. if (rv == 0) {
  256. send_next = 1;
  257. goto next;
  258. }
  259. fromlen = sizeof(src);
  260. rv = recvfrom(sock, rsp, sizeof(rsp), 0, &src, &fromlen);
  261. if (debug_packet && (rv > 0)) {
  262. int i;
  263. printf("Got packet:");
  264. for (i=0; i<rv; i++) {
  265. if ((i % 16) == 0)
  266. printf("\n ");
  267. printf(" %2.2x", rsp[i]);
  268. }
  269. printf("\n");
  270. }
  271. if (rv < 0) {
  272. perror("recvfrom");
  273. } else if (rv < 28) {
  274. fprintf(stderr, "Invalid receive length: %d, should be 28\n", rv);
  275. } else if ((rsp[0] != 6) || (rsp[3] != 6) || (rsp[4] != 0x00)
  276. || (rsp[5] != 0x00) || (rsp[6] != 0x11) || (rsp[7] != 0xbe)
  277. || (rsp[8] != 0x40) || (rsp[11] < 16))
  278. {
  279. fprintf(stderr, "Invalid ping response\n");
  280. } else {
  281. if (! add_host(&src))
  282. goto next;
  283. rv = getnameinfo(&src, fromlen, host, sizeof(host),
  284. serv, sizeof(serv), 0);
  285. if (rv) {
  286. struct sockaddr_in *ip = (struct sockaddr_in *) &src;
  287. addrname = inet_ntoa(ip->sin_addr);
  288. } else
  289. addrname = host;
  290. printf("%s", addrname);
  291. if ((rsp[20] & 0x80) && ((rsp[20] & 0xf) == 0x01))
  292. printf(" IPMI");
  293. printf("\n");
  294. }
  295. next:
  296. gettimeofday(&currtime, NULL);
  297. }
  298. return 0;
  299. }