#include <errno.h> #include <netlink/genl/genl.h> #include <netlink/genl/family.h> #include <netlink/genl/ctrl.h> #include <netlink/msg.h> #include <netlink/attr.h> #include "nl80211.h" #include "iw.h" static int iw_conn(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; unsigned char bssid[6]; int freq; if (argc < 1) return 1; /* SSID */ NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); argv++; argc--; /* freq */ if (argc) { freq = strtoul(argv[0], &end, 10); if (*end == '\0') { NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); argv++; argc--; } } /* bssid */ if (argc) { if (mac_addr_a2n(bssid, argv[0]) == 0) { NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); argv++; argc--; } } if (!argc) return 0; if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) return 1; argv++; argc--; return parse_keys(msg, argv, argc); nla_put_failure: return -ENOSPC; } static int disconnect(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { return 0; } TOPLEVEL(disconnect, NULL, NL80211_CMD_DISCONNECT, 0, CIB_NETDEV, disconnect, "Disconnect from the current network."); static int iw_connect(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char **conn_argv, *dev = argv[0]; static const __u32 cmds[] = { NL80211_CMD_CONNECT, }; struct print_event_args printargs = { }; int conn_argc, err; bool wait = false; int i; /* strip "wlan0 connect" */ argc -= 2; argv += 2; /* check -w */ if (argc && strcmp(argv[0], "-w") == 0) { wait = true; argc--; argv++; } err = __prepare_listen_events(state); if (err) return err; conn_argc = 3 + argc; conn_argv = calloc(conn_argc, sizeof(*conn_argv)); if (!conn_argv) return -ENOMEM; conn_argv[0] = dev; conn_argv[1] = "connect"; conn_argv[2] = "establish"; for (i = 0; i < argc; i++) conn_argv[i + 3] = argv[i]; err = handle_cmd(state, id, conn_argc, conn_argv); free(conn_argv); if (err) return err; if (!wait) return 0; /* * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION * * This code has a bug: * * It is possible for a connect result message from another * connect attempt to be processed here first, because we * start listening to the multicast group before starting * our own connect request, which may succeed but we get a * fail message from a previous attempt that raced with us, * or similar. * * The only proper way to fix this would be to listen to events * before sending the command, and for the kernel to send the * connect request or a cookie along with the event, so that you * can match up whether the connect _you_ requested was finished * or aborted. * * Alas, the kernel doesn't do that (yet). */ __do_listen_events(state, ARRAY_SIZE(cmds), cmds, &printargs); return 0; } TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465]", 0, 0, CIB_NETDEV, iw_connect, "Join the network with the given SSID (and frequency, BSSID).\n" "With -w, wait for the connect to finish or fail."); HIDDEN(connect, establish, "", NL80211_CMD_CONNECT, 0, CIB_NETDEV, iw_conn); static int iw_auth(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { char *end; unsigned char bssid[6]; int freq; bool need_key = false; if (argc < 4) return 1; /* SSID */ NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); argv++; argc--; /* bssid */ if (mac_addr_a2n(bssid, argv[0]) == 0) { NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); argv++; argc--; } else { return 1; } /* FIXME */ if (strcmp(argv[0], "open") == 0) { NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_OPEN_SYSTEM); } else if (strcmp(argv[0], "shared") == 0) { NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_SHARED_KEY); need_key = true; } else { return 1; } argv++; argc--; freq = strtoul(argv[0], &end, 10); if (*end == '\0') { NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); argv++; argc--; } else { return 1; } if (!argc && need_key) return 1; if (argc && !need_key) return 1; if (!argc) return 0; if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) return 1; argv++; argc--; return parse_keys(msg, argv, argc); nla_put_failure: return -ENOSPC; } TOPLEVEL(auth, "<SSID> <bssid> <type:open|shared> <freq in MHz> [key 0:abcde d:1:6162636465]", NL80211_CMD_AUTHENTICATE, 0, CIB_NETDEV, iw_auth, "Authenticate with the given network.\n");