You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wpa_ctrl.c 5.4 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Modifed version of src/common/wpa_ctrl.c from wpa_supplicant, discarding
  3. * all code paths except for CONFIG_CTRL_IFACE_UNIX. Define strlcpy inline,
  4. * it is not provided by GNU libc.
  5. * Copyright (c) 2008, Kel Modderman <kel@otaku42.de>
  6. *
  7. * wpa_supplicant/hostapd control interface library
  8. * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. *
  14. * Alternatively, this software may be distributed under the terms of BSD
  15. * license.
  16. */
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <stdarg.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <netinet/in.h>
  23. #include <sys/socket.h>
  24. #include <sys/time.h>
  25. #include <sys/types.h>
  26. #include <sys/un.h>
  27. #include "wpa_ctrl.h"
  28. /**
  29. * strlcpy - Copy a string with size bound and NUL-termination
  30. * @dest: Destination
  31. * @src: Source
  32. * @siz: Size of the target buffer
  33. * Returns: Total length of the target string (length of src) (not including
  34. * NUL-termination)
  35. *
  36. * This function matches in behavior with the strlcpy(3) function in OpenBSD.
  37. */
  38. size_t strlcpy(char *dest, const char *src, size_t siz)
  39. {
  40. const char *s = src;
  41. size_t left = siz;
  42. if (left) {
  43. /* Copy string up to the maximum size of the dest buffer */
  44. while (--left != 0) {
  45. if ((*dest++ = *s++) == '\0')
  46. break;
  47. }
  48. }
  49. if (left == 0) {
  50. /* Not enough room for the string; force NUL-termination */
  51. if (siz != 0)
  52. *dest = '\0';
  53. while (*s++)
  54. ; /* determine total src string length */
  55. }
  56. return s - src - 1;
  57. }
  58. /**
  59. * struct wpa_ctrl - Internal structure for control interface library
  60. *
  61. * This structure is used by the wpa_supplicant/hostapd control interface
  62. * library to store internal data. Programs using the library should not touch
  63. * this data directly. They can only use the pointer to the data structure as
  64. * an identifier for the control interface connection and use this as one of
  65. * the arguments for most of the control interface library functions.
  66. */
  67. struct wpa_ctrl {
  68. int s;
  69. struct sockaddr_un local;
  70. struct sockaddr_un dest;
  71. };
  72. struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
  73. {
  74. struct wpa_ctrl *ctrl;
  75. static int counter = 0;
  76. int ret;
  77. size_t res;
  78. ctrl = malloc(sizeof(*ctrl));
  79. if (ctrl == NULL)
  80. return NULL;
  81. memset(ctrl, 0, sizeof(*ctrl));
  82. ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
  83. if (ctrl->s < 0) {
  84. free(ctrl);
  85. return NULL;
  86. }
  87. ctrl->local.sun_family = AF_UNIX;
  88. ret = snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
  89. "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
  90. if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
  91. close(ctrl->s);
  92. free(ctrl);
  93. return NULL;
  94. }
  95. if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
  96. sizeof(ctrl->local)) < 0) {
  97. close(ctrl->s);
  98. free(ctrl);
  99. return NULL;
  100. }
  101. ctrl->dest.sun_family = AF_UNIX;
  102. res = strlcpy(ctrl->dest.sun_path, ctrl_path,
  103. sizeof(ctrl->dest.sun_path));
  104. if (res >= sizeof(ctrl->dest.sun_path)) {
  105. close(ctrl->s);
  106. free(ctrl);
  107. return NULL;
  108. }
  109. if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
  110. sizeof(ctrl->dest)) < 0) {
  111. close(ctrl->s);
  112. unlink(ctrl->local.sun_path);
  113. free(ctrl);
  114. return NULL;
  115. }
  116. return ctrl;
  117. }
  118. void wpa_ctrl_close(struct wpa_ctrl *ctrl)
  119. {
  120. unlink(ctrl->local.sun_path);
  121. close(ctrl->s);
  122. free(ctrl);
  123. }
  124. int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
  125. char *reply, size_t *reply_len,
  126. void (*msg_cb)(char *msg, size_t len))
  127. {
  128. struct timeval tv;
  129. int res;
  130. fd_set rfds;
  131. const char *_cmd;
  132. char *cmd_buf = NULL;
  133. size_t _cmd_len;
  134. {
  135. _cmd = cmd;
  136. _cmd_len = cmd_len;
  137. }
  138. if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
  139. free(cmd_buf);
  140. return -1;
  141. }
  142. free(cmd_buf);
  143. for (;;) {
  144. tv.tv_sec = 2;
  145. tv.tv_usec = 0;
  146. FD_ZERO(&rfds);
  147. FD_SET(ctrl->s, &rfds);
  148. res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
  149. if (FD_ISSET(ctrl->s, &rfds)) {
  150. res = recv(ctrl->s, reply, *reply_len, 0);
  151. if (res < 0)
  152. return res;
  153. if (res > 0 && reply[0] == '<') {
  154. /* This is an unsolicited message from
  155. * wpa_supplicant, not the reply to the
  156. * request. Use msg_cb to report this to the
  157. * caller. */
  158. if (msg_cb) {
  159. /* Make sure the message is nul
  160. * terminated. */
  161. if ((size_t) res == *reply_len)
  162. res = (*reply_len) - 1;
  163. reply[res] = '\0';
  164. msg_cb(reply, res);
  165. }
  166. continue;
  167. }
  168. *reply_len = res;
  169. break;
  170. } else {
  171. return -2;
  172. }
  173. }
  174. return 0;
  175. }
  176. static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
  177. {
  178. char buf[10];
  179. int ret;
  180. size_t len = 10;
  181. ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
  182. buf, &len, NULL);
  183. if (ret < 0)
  184. return ret;
  185. if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
  186. return 0;
  187. return -1;
  188. }
  189. int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
  190. {
  191. return wpa_ctrl_attach_helper(ctrl, 1);
  192. }
  193. int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
  194. {
  195. return wpa_ctrl_attach_helper(ctrl, 0);
  196. }
  197. int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
  198. {
  199. int res;
  200. res = recv(ctrl->s, reply, *reply_len, 0);
  201. if (res < 0)
  202. return res;
  203. *reply_len = res;
  204. return 0;
  205. }
  206. int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
  207. {
  208. struct timeval tv;
  209. fd_set rfds;
  210. tv.tv_sec = 0;
  211. tv.tv_usec = 0;
  212. FD_ZERO(&rfds);
  213. FD_SET(ctrl->s, &rfds);
  214. select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
  215. return FD_ISSET(ctrl->s, &rfds);
  216. }
  217. int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
  218. {
  219. return ctrl->s;
  220. }