Add common ctrl_iface files
[mech_eap.git] / src / common / ctrl_iface_common.c
1 /*
2  * Common hostapd/wpa_supplicant ctrl iface code.
3  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4  * Copyright (c) 2015, Qualcomm Atheros, Inc.
5  *
6  * This software may be distributed under the terms of the BSD license.
7  * See README for more details.
8  */
9
10 #include "utils/includes.h"
11 #include <netdb.h>
12 #include <sys/un.h>
13
14 #include "utils/common.h"
15 #include "ctrl_iface_common.h"
16
17 static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
18                             struct sockaddr_storage *b, socklen_t b_len)
19 {
20         struct sockaddr_in *in_a, *in_b;
21         struct sockaddr_in6 *in6_a, *in6_b;
22         struct sockaddr_un *u_a, *u_b;
23
24         if (a->ss_family != b->ss_family)
25                 return 1;
26
27         switch (a->ss_family) {
28         case AF_INET:
29                 in_a = (struct sockaddr_in *) a;
30                 in_b = (struct sockaddr_in *) b;
31
32                 if (in_a->sin_port != in_b->sin_port)
33                         return 1;
34                 if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
35                         return 1;
36                 break;
37         case AF_INET6:
38                 in6_a = (struct sockaddr_in6 *) a;
39                 in6_b = (struct sockaddr_in6 *) b;
40
41                 if (in6_a->sin6_port != in6_b->sin6_port)
42                         return 1;
43                 if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
44                               sizeof(in6_a->sin6_addr)) != 0)
45                         return 1;
46                 break;
47         case AF_UNIX:
48                 u_a = (struct sockaddr_un *) a;
49                 u_b = (struct sockaddr_un *) b;
50
51                 if (a_len != b_len ||
52                     os_memcmp(u_a->sun_path, u_b->sun_path,
53                               a_len - offsetof(struct sockaddr_un, sun_path))
54                     != 0)
55                         return 1;
56                 break;
57         default:
58                 return 1;
59         }
60
61         return 0;
62 }
63
64
65 void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
66                     socklen_t socklen)
67 {
68         char host[NI_MAXHOST] = { 0 };
69         char service[NI_MAXSERV] = { 0 };
70         char addr_txt[200];
71
72         switch (sock->ss_family) {
73         case AF_INET:
74         case AF_INET6:
75                 getnameinfo((struct sockaddr *) sock, socklen,
76                             host, sizeof(host),
77                             service, sizeof(service),
78                             NI_NUMERICHOST);
79
80                 wpa_printf(level, "%s %s:%s", msg, host, service);
81                 break;
82         case AF_UNIX:
83                 printf_encode(addr_txt, sizeof(addr_txt),
84                               (u8 *) ((struct sockaddr_un *) sock)->sun_path,
85                               socklen - offsetof(struct sockaddr_un, sun_path));
86                 wpa_printf(level, "%s %s", msg, addr_txt);
87                 break;
88         default:
89                 wpa_printf(level, "%s", msg);
90                 break;
91         }
92 }
93
94
95 int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_un *from,
96                       socklen_t fromlen)
97 {
98         struct wpa_ctrl_dst *dst;
99
100         dst = os_zalloc(sizeof(*dst));
101         if (dst == NULL)
102                 return -1;
103         os_memcpy(&dst->addr, from, fromlen);
104         dst->addrlen = fromlen;
105         dst->debug_level = MSG_INFO;
106         dl_list_add(ctrl_dst, &dst->list);
107
108         sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached",
109                        (struct sockaddr_storage *) from, fromlen);
110         return 0;
111 }
112
113
114 int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_un *from,
115                       socklen_t fromlen)
116 {
117         struct wpa_ctrl_dst *dst;
118
119         dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
120                 if (!sockaddr_compare((struct sockaddr_storage *) from,
121                                       fromlen,
122                                       (struct sockaddr_storage *) &dst->addr,
123                                       dst->addrlen)) {
124                         sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
125                                        (struct sockaddr_storage *) from,
126                                        fromlen);
127                         dl_list_del(&dst->list);
128                         os_free(dst);
129                         return 0;
130                 }
131         }
132
133         return -1;
134 }
135
136
137 int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_un *from,
138                      socklen_t fromlen, const char *level)
139 {
140         struct wpa_ctrl_dst *dst;
141
142         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
143
144         dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
145                 if (!sockaddr_compare((struct sockaddr_storage *) from,
146                                       fromlen,
147                                       (struct sockaddr_storage *) &dst->addr,
148                                       dst->addrlen)) {
149                         sockaddr_print(MSG_DEBUG,
150                                        "CTRL_IFACE changed monitor level",
151                                        (struct sockaddr_storage *) from,
152                                        fromlen);
153                         dst->debug_level = atoi(level);
154                         return 0;
155                 }
156         }
157
158         return -1;
159 }