]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/wpa_ctrl.c
This commit was generated by cvs2svn to compensate for changes in r154184,
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / wpa_ctrl.c
1 /*
2  * WPA Supplicant - wpa_supplicant control interface library
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  *
14  * $FreeBSD$
15  */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #ifndef CONFIG_NATIVE_WINDOWS
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #endif /* CONFIG_NATIVE_WINDOWS */
27
28 #include "wpa_ctrl.h"
29 #ifdef CONFIG_NATIVE_WINDOWS
30 #include "common.h"
31 #endif /* CONFIG_NATIVE_WINDOWS */
32
33
34 struct wpa_ctrl {
35         int s;
36 #ifdef CONFIG_CTRL_IFACE_UDP
37         struct sockaddr_in local;
38         struct sockaddr_in dest;
39 #else /* CONFIG_CTRL_IFACE_UDP */
40         struct sockaddr_un local;
41         struct sockaddr_un dest;
42 #endif /* CONFIG_CTRL_IFACE_UDP */
43 };
44
45
46 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
47 {
48         struct wpa_ctrl *ctrl;
49 #ifndef CONFIG_CTRL_IFACE_UDP
50         static int counter = 0;
51 #endif /* CONFIG_CTRL_IFACE_UDP */
52
53         ctrl = malloc(sizeof(*ctrl));
54         if (ctrl == NULL)
55                 return NULL;
56         memset(ctrl, 0, sizeof(*ctrl));
57
58 #ifdef CONFIG_CTRL_IFACE_UDP
59         ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
60         if (ctrl->s < 0) {
61                 perror("socket");
62                 free(ctrl);
63                 return NULL;
64         }
65
66         ctrl->local.sin_family = AF_INET;
67         ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
68         if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
69                  sizeof(ctrl->local)) < 0) {
70                 close(ctrl->s);
71                 free(ctrl);
72                 return NULL;
73         }
74
75         ctrl->dest.sin_family = AF_INET;
76         ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
77         ctrl->dest.sin_port = htons(9877);
78         if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
79                     sizeof(ctrl->dest)) < 0) {
80                 perror("connect");
81                 close(ctrl->s);
82                 free(ctrl);
83                 return NULL;
84         }
85 #else /* CONFIG_CTRL_IFACE_UDP */
86         ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
87         if (ctrl->s < 0) {
88                 free(ctrl);
89                 return NULL;
90         }
91
92         ctrl->local.sun_family = AF_UNIX;
93         snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path) - 1,
94                  "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
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
102         ctrl->dest.sun_family = AF_UNIX;
103         strncpy(ctrl->dest.sun_path, ctrl_path, sizeof(ctrl->dest.sun_path) - 1);
104         if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
105                     sizeof(ctrl->dest)) < 0) {
106                 close(ctrl->s);
107                 unlink(ctrl->local.sun_path);
108                 free(ctrl);
109                 return NULL;
110         }
111 #endif /* CONFIG_CTRL_IFACE_UDP */
112
113         return ctrl;
114 }
115
116
117 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
118 {
119 #ifndef CONFIG_CTRL_IFACE_UDP
120         unlink(ctrl->local.sun_path);
121 #endif /* CONFIG_CTRL_IFACE_UDP */
122         close(ctrl->s);
123         free(ctrl);
124 }
125
126
127 int wpa_ctrl_request(struct wpa_ctrl *ctrl, char *cmd, size_t cmd_len,
128                      char *reply, size_t *reply_len,
129                      void (*msg_cb)(char *msg, size_t len))
130 {
131         struct timeval tv;
132         int res;
133         fd_set rfds;
134
135         if (send(ctrl->s, cmd, cmd_len, 0) < 0)
136                 return -1;
137
138         for (;;) {
139                 tv.tv_sec = 2;
140                 tv.tv_usec = 0;
141                 FD_ZERO(&rfds);
142                 FD_SET(ctrl->s, &rfds);
143                 res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
144                 if (FD_ISSET(ctrl->s, &rfds)) {
145                         res = recv(ctrl->s, reply, *reply_len, 0);
146                         if (res < 0)
147                                 return res;
148                         if (res > 0 && reply[0] == '<') {
149                                 /* This is an unsolicited message from
150                                  * wpa_supplicant, not the reply to the
151                                  * request. Use msg_cb to report this to the
152                                  * caller. */
153                                 if (msg_cb) {
154                                         /* Make sure the message is nul
155                                          * terminated. */
156                                         if (res == *reply_len)
157                                                 res = (*reply_len) - 1;
158                                         reply[res] = '\0';
159                                         msg_cb(reply, res);
160                                 }
161                                 continue;
162                         }
163                         *reply_len = res;
164                         break;
165                 } else {
166                         return -2;
167                 }
168         }
169         return 0;
170 }
171
172
173 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
174 {
175         char buf[10];
176         int ret;
177         size_t len = 10;
178
179         ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
180                                buf, &len, NULL);
181         if (ret < 0)
182                 return ret;
183         if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
184                 return 0;
185         return -1;
186 }
187
188
189 int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
190 {
191         return wpa_ctrl_attach_helper(ctrl, 1);
192 }
193
194
195 int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
196 {
197         return wpa_ctrl_attach_helper(ctrl, 0);
198 }
199
200
201 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
202 {
203         int res;
204
205         res = recv(ctrl->s, reply, *reply_len, 0);
206         if (res < 0)
207                 return res;
208         *reply_len = res;
209         return 0;
210 }
211
212
213 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
214 {
215         struct timeval tv;
216         int res;
217         fd_set rfds;
218         tv.tv_sec = 0;
219         tv.tv_usec = 0;
220         FD_ZERO(&rfds);
221         FD_SET(ctrl->s, &rfds);
222         res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
223         return FD_ISSET(ctrl->s, &rfds);
224 }
225
226
227 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
228 {
229         return ctrl->s;
230 }