Johannes Berg | 2ef1be6 | 2008-04-02 17:40:11 +0200 | [diff] [blame^] | 1 | #include <linux/nl80211.h> |
| 2 | #include <net/if.h> |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 3 | #include <errno.h> |
Johannes Berg | 2ef1be6 | 2008-04-02 17:40:11 +0200 | [diff] [blame^] | 4 | |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 5 | #include <netlink/genl/genl.h> |
| 6 | #include <netlink/genl/family.h> |
| 7 | #include <netlink/genl/ctrl.h> |
| 8 | #include <netlink/msg.h> |
| 9 | #include <netlink/attr.h> |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 10 | |
| 11 | #include "iw.h" |
| 12 | |
| 13 | /* return 0 if not found, 1 if ok, -1 on error */ |
| 14 | static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type) |
| 15 | { |
| 16 | char *tpstr; |
| 17 | |
| 18 | if (*argc < 2) |
| 19 | return 0; |
| 20 | |
| 21 | if (strcmp((*argv)[0], "type")) |
| 22 | return 0; |
| 23 | |
| 24 | tpstr = (*argv)[1]; |
| 25 | *argc -= 2; |
| 26 | *argv += 2; |
| 27 | |
| 28 | if (strcmp(tpstr, "adhoc") == 0 || |
| 29 | strcmp(tpstr, "ibss") == 0) { |
| 30 | *type = NL80211_IFTYPE_ADHOC; |
| 31 | return 1; |
| 32 | } else if (strcmp(tpstr, "monitor") == 0) { |
| 33 | *type = NL80211_IFTYPE_MONITOR; |
| 34 | return 1; |
Mike Kershaw | 1cdd901 | 2007-09-29 19:17:20 -0400 | [diff] [blame] | 35 | } else if (strcmp(tpstr, "ap") == 0 || strcmp(tpstr, "master") == 0) { |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 36 | *type = NL80211_IFTYPE_AP; |
| 37 | return 1; |
| 38 | } else if (strcmp(tpstr, "ap_vlan") == 0) { |
| 39 | *type = NL80211_IFTYPE_AP_VLAN; |
| 40 | return 1; |
| 41 | } else if (strcmp(tpstr, "wds") == 0) { |
| 42 | *type = NL80211_IFTYPE_WDS; |
| 43 | return 1; |
| 44 | } else if (strcmp(tpstr, "station") == 0) { |
| 45 | *type = NL80211_IFTYPE_STATION; |
| 46 | return 1; |
Luis Carlos Cobo | 3d1e870 | 2008-04-01 12:03:41 -0700 | [diff] [blame] | 47 | } else if (strcmp(tpstr, "mp") == 0 || |
| 48 | strcmp(tpstr, "mesh") == 0) { |
| 49 | *type = NL80211_IFTYPE_MESH_POINT; |
| 50 | return 1; |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | |
| 54 | fprintf(stderr, "invalid interface type %s\n", tpstr); |
| 55 | return -1; |
| 56 | } |
| 57 | |
| 58 | static int handle_interface_add(struct nl80211_state *state, |
| 59 | char *phy, char *dev, int argc, char **argv) |
| 60 | { |
Andrew Lutomirski | 2dfd6bf | 2007-12-20 18:50:07 +0100 | [diff] [blame] | 61 | char *name; |
Luis Carlos Cobo | 3d1e870 | 2008-04-01 12:03:41 -0700 | [diff] [blame] | 62 | char *mesh_id = NULL; |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 63 | enum nl80211_iftype type; |
| 64 | int tpset, err; |
| 65 | struct nl_msg *msg; |
| 66 | |
| 67 | if (argc < 1) { |
| 68 | fprintf(stderr, "not enough arguments\n"); |
| 69 | return -1; |
| 70 | } |
| 71 | |
Andrew Lutomirski | 2dfd6bf | 2007-12-20 18:50:07 +0100 | [diff] [blame] | 72 | name = argv[0]; |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 73 | argc--; |
| 74 | argv++; |
| 75 | |
Andrew Lutomirski | 2dfd6bf | 2007-12-20 18:50:07 +0100 | [diff] [blame] | 76 | tpset = get_if_type(&argc, &argv, &type); |
| 77 | if (tpset == 0) |
| 78 | fprintf(stderr, "you must specify an interface type\n"); |
| 79 | if (tpset <= 0) |
| 80 | return -1; |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 81 | |
| 82 | if (argc) { |
Luis Carlos Cobo | 3d1e870 | 2008-04-01 12:03:41 -0700 | [diff] [blame] | 83 | if (strcmp(argv[0], "mesh_id") != 0) { |
| 84 | fprintf(stderr, "option %s not supported\n", argv[0]); |
| 85 | return -1; |
| 86 | } |
| 87 | argc--; |
| 88 | argv++; |
| 89 | |
| 90 | if (!argc) { |
| 91 | fprintf(stderr, "not enough arguments\n"); |
| 92 | return -1; |
| 93 | } |
| 94 | mesh_id = argv[0]; |
| 95 | argc--; |
| 96 | argv++; |
| 97 | } |
| 98 | |
| 99 | if (argc) { |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 100 | fprintf(stderr, "too many arguments\n"); |
| 101 | return -1; |
| 102 | } |
| 103 | |
Mike Kershaw | 1cdd901 | 2007-09-29 19:17:20 -0400 | [diff] [blame] | 104 | msg = nlmsg_alloc(); |
| 105 | if (!msg) { |
| 106 | fprintf(stderr, "failed to allocate netlink msg\n"); |
| 107 | return -1; |
| 108 | } |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 109 | |
| 110 | genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, |
| 111 | 0, NL80211_CMD_NEW_INTERFACE, 0); |
| 112 | if (dev) |
| 113 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev)); |
| 114 | if (phy) |
| 115 | return -1; /* XXX TODO */ |
| 116 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name); |
| 117 | if (tpset) |
| 118 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); |
Luis Carlos Cobo | 3d1e870 | 2008-04-01 12:03:41 -0700 | [diff] [blame] | 119 | if (mesh_id) |
| 120 | NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 121 | |
| 122 | if ((err = nl_send_auto_complete(state->nl_handle, msg)) < 0 || |
| 123 | (err = nl_wait_for_ack(state->nl_handle)) < 0) { |
| 124 | nla_put_failure: |
| 125 | fprintf(stderr, "failed to create interface: %d\n", err); |
| 126 | nlmsg_free(msg); |
| 127 | return -1; |
| 128 | } |
| 129 | |
| 130 | nlmsg_free(msg); |
| 131 | |
| 132 | return 0; |
| 133 | } |
| 134 | |
Johannes Berg | 3fcfe40 | 2007-09-28 23:50:25 +0200 | [diff] [blame] | 135 | static int handle_interface_del(struct nl80211_state *state, |
| 136 | char *phy, char *dev, int argc, char **argv) |
| 137 | { |
| 138 | int err; |
| 139 | struct nl_msg *msg; |
| 140 | |
| 141 | if (argc) { |
| 142 | fprintf(stderr, "too many arguments\n"); |
| 143 | return -1; |
| 144 | } |
| 145 | |
| 146 | msg = nlmsg_alloc(); |
| 147 | if (!msg) |
| 148 | return -1; |
| 149 | |
| 150 | genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0, |
| 151 | 0, NL80211_CMD_DEL_INTERFACE, 0); |
| 152 | if (!dev) { |
| 153 | fprintf(stderr, "need device\n"); |
| 154 | nlmsg_free(msg); |
| 155 | return -1; |
| 156 | } |
| 157 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(dev)); |
| 158 | |
| 159 | if ((err = nl_send_auto_complete(state->nl_handle, msg)) < 0 || |
| 160 | (err = nl_wait_for_ack(state->nl_handle)) < 0) { |
| 161 | nla_put_failure: |
| 162 | fprintf(stderr, "failed to remove interface: %d\n", err); |
| 163 | nlmsg_free(msg); |
| 164 | return -1; |
| 165 | } |
| 166 | |
| 167 | nlmsg_free(msg); |
| 168 | |
| 169 | return 0; |
| 170 | } |
| 171 | |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 172 | int handle_interface(struct nl80211_state *state, |
| 173 | char *phy, char *dev, int argc, char **argv) |
| 174 | { |
| 175 | char *cmd = argv[0]; |
| 176 | |
Andrew Lutomirski | 2dfd6bf | 2007-12-20 18:50:07 +0100 | [diff] [blame] | 177 | if (argc < 1) { |
| 178 | fprintf(stderr, "you must specify an interface command\n"); |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 179 | return -1; |
Andrew Lutomirski | 2dfd6bf | 2007-12-20 18:50:07 +0100 | [diff] [blame] | 180 | } |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 181 | |
| 182 | argc--; |
| 183 | argv++; |
| 184 | |
| 185 | if (strcmp(cmd, "add") == 0) |
| 186 | return handle_interface_add(state, phy, dev, argc, argv); |
Johannes Berg | 3fcfe40 | 2007-09-28 23:50:25 +0200 | [diff] [blame] | 187 | else if (strcmp(cmd, "del") == 0) |
| 188 | return handle_interface_del(state, phy, dev, argc, argv); |
Johannes Berg | 45c7212 | 2007-09-28 23:47:38 +0200 | [diff] [blame] | 189 | |
| 190 | printf("invalid interface command %s\n", cmd); |
| 191 | return -1; |
| 192 | } |