1 #include <errno.h> 2 3 #include <netlink/genl/genl.h> 4 #include <netlink/genl/family.h> 5 #include <netlink/genl/ctrl.h> 6 #include <netlink/msg.h> 7 #include <netlink/attr.h> 8 9 #include "nl80211.h" 10 #include "iw.h" 11 12 static int iw_conn(struct nl80211_state *state, struct nl_cb *cb, 13 struct nl_msg *msg, int argc, char **argv, 14 enum id_input id) 15 { 16 char *end; 17 unsigned char bssid[6]; 18 int freq; 19 20 if (argc < 1) 21 return 1; 22 23 /* SSID */ 24 NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); 25 argv++; 26 argc--; 27 28 /* freq */ 29 if (argc) { 30 freq = strtoul(argv[0], &end, 10); 31 if (*end == '\0') { 32 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); 33 argv++; 34 argc--; 35 } 36 } 37 38 /* bssid */ 39 if (argc) { 40 if (mac_addr_a2n(bssid, argv[0]) == 0) { 41 NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); 42 argv++; 43 argc--; 44 } 45 } 46 47 if (!argc) 48 return 0; 49 50 if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) 51 return 1; 52 53 argv++; 54 argc--; 55 56 return parse_keys(msg, argv, argc); 57 nla_put_failure: 58 return -ENOSPC; 59 } 60 61 static int disconnect(struct nl80211_state *state, 62 struct nl_cb *cb, 63 struct nl_msg *msg, 64 int argc, char **argv, 65 enum id_input id) 66 { 67 return 0; 68 } 69 TOPLEVEL(disconnect, NULL, 70 NL80211_CMD_DISCONNECT, 0, CIB_NETDEV, disconnect, 71 "Disconnect from the current network."); 72 73 static int iw_connect(struct nl80211_state *state, struct nl_cb *cb, 74 struct nl_msg *msg, int argc, char **argv, 75 enum id_input id) 76 { 77 char **conn_argv, *dev = argv[0]; 78 static const __u32 cmds[] = { 79 NL80211_CMD_CONNECT, 80 }; 81 struct print_event_args printargs = { }; 82 int conn_argc, err; 83 bool wait = false; 84 int i; 85 86 /* strip "wlan0 connect" */ 87 argc -= 2; 88 argv += 2; 89 90 /* check -w */ 91 if (argc && strcmp(argv[0], "-w") == 0) { 92 wait = true; 93 argc--; 94 argv++; 95 } 96 97 err = __prepare_listen_events(state); 98 if (err) 99 return err; 100 101 conn_argc = 3 + argc; 102 conn_argv = calloc(conn_argc, sizeof(*conn_argv)); 103 if (!conn_argv) 104 return -ENOMEM; 105 106 conn_argv[0] = dev; 107 conn_argv[1] = "connect"; 108 conn_argv[2] = "establish"; 109 for (i = 0; i < argc; i++) 110 conn_argv[i + 3] = argv[i]; 111 err = handle_cmd(state, id, conn_argc, conn_argv); 112 free(conn_argv); 113 if (err) 114 return err; 115 116 if (!wait) 117 return 0; 118 119 /* 120 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION 121 * 122 * This code has a bug: 123 * 124 * It is possible for a connect result message from another 125 * connect attempt to be processed here first, because we 126 * start listening to the multicast group before starting 127 * our own connect request, which may succeed but we get a 128 * fail message from a previous attempt that raced with us, 129 * or similar. 130 * 131 * The only proper way to fix this would be to listen to events 132 * before sending the command, and for the kernel to send the 133 * connect request or a cookie along with the event, so that you 134 * can match up whether the connect _you_ requested was finished 135 * or aborted. 136 * 137 * Alas, the kernel doesn't do that (yet). 138 */ 139 140 __do_listen_events(state, ARRAY_SIZE(cmds), cmds, &printargs); 141 return 0; 142 } 143 TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465]", 144 0, 0, CIB_NETDEV, iw_connect, 145 "Join the network with the given SSID (and frequency, BSSID).\n" 146 "With -w, wait for the connect to finish or fail."); 147 HIDDEN(connect, establish, "", NL80211_CMD_CONNECT, 0, CIB_NETDEV, iw_conn); 148 149 static int iw_auth(struct nl80211_state *state, struct nl_cb *cb, 150 struct nl_msg *msg, int argc, char **argv, 151 enum id_input id) 152 { 153 char *end; 154 unsigned char bssid[6]; 155 int freq; 156 bool need_key = false; 157 158 if (argc < 4) 159 return 1; 160 161 /* SSID */ 162 NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); 163 argv++; 164 argc--; 165 166 /* bssid */ 167 if (mac_addr_a2n(bssid, argv[0]) == 0) { 168 NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); 169 argv++; 170 argc--; 171 } else { 172 return 1; 173 } 174 175 /* FIXME */ 176 if (strcmp(argv[0], "open") == 0) { 177 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, 178 NL80211_AUTHTYPE_OPEN_SYSTEM); 179 } else if (strcmp(argv[0], "shared") == 0) { 180 NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, 181 NL80211_AUTHTYPE_SHARED_KEY); 182 need_key = true; 183 } else { 184 return 1; 185 } 186 argv++; 187 argc--; 188 189 freq = strtoul(argv[0], &end, 10); 190 if (*end == '\0') { 191 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); 192 argv++; 193 argc--; 194 } else { 195 return 1; 196 } 197 198 if (!argc && need_key) 199 return 1; 200 if (argc && !need_key) 201 return 1; 202 if (!argc) 203 return 0; 204 205 if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) 206 return 1; 207 208 argv++; 209 argc--; 210 211 return parse_keys(msg, argv, argc); 212 nla_put_failure: 213 return -ENOSPC; 214 } 215 216 TOPLEVEL(auth, "<SSID> <bssid> <type:open|shared> <freq in MHz> [key 0:abcde d:1:6162636465]", 217 NL80211_CMD_AUTHENTICATE, 0, CIB_NETDEV, iw_auth, 218 "Authenticate with the given network.\n"); 219