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.
 
 
 
 

265 lines
5.5 KiB

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