diff options
-rw-r--r-- | include/linux/nl80211.h | 8 | ||||
-rw-r--r-- | include/net/cfg80211.h | 38 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 39 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 13 | ||||
-rw-r--r-- | net/mac80211/iface.c | 14 | ||||
-rw-r--r-- | net/mac80211/main.c | 3 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 26 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 25 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 15 | ||||
-rw-r--r-- | net/wireless/core.h | 13 | ||||
-rw-r--r-- | net/wireless/mesh.c | 140 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 137 | ||||
-rw-r--r-- | net/wireless/util.c | 1 |
14 files changed, 359 insertions, 115 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9e541452d80..410a06ea551 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -394,6 +394,11 @@ | |||
394 | * | 394 | * |
395 | * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. | 395 | * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. |
396 | * | 396 | * |
397 | * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial | ||
398 | * mesh config parameters may be given. | ||
399 | * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the | ||
400 | * network is determined by the network interface. | ||
401 | * | ||
397 | * @NL80211_CMD_MAX: highest used command number | 402 | * @NL80211_CMD_MAX: highest used command number |
398 | * @__NL80211_CMD_AFTER_LAST: internal use | 403 | * @__NL80211_CMD_AFTER_LAST: internal use |
399 | */ | 404 | */ |
@@ -500,6 +505,9 @@ enum nl80211_commands { | |||
500 | 505 | ||
501 | NL80211_CMD_FRAME_WAIT_CANCEL, | 506 | NL80211_CMD_FRAME_WAIT_CANCEL, |
502 | 507 | ||
508 | NL80211_CMD_JOIN_MESH, | ||
509 | NL80211_CMD_LEAVE_MESH, | ||
510 | |||
503 | /* add new commands above here */ | 511 | /* add new commands above here */ |
504 | 512 | ||
505 | /* used to define NL80211_CMD_MAX below */ | 513 | /* used to define NL80211_CMD_MAX below */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 902895dfbd4..788c3989a9e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -258,13 +258,9 @@ struct ieee80211_supported_band { | |||
258 | 258 | ||
259 | /** | 259 | /** |
260 | * struct vif_params - describes virtual interface parameters | 260 | * struct vif_params - describes virtual interface parameters |
261 | * @mesh_id: mesh ID to use | ||
262 | * @mesh_id_len: length of the mesh ID | ||
263 | * @use_4addr: use 4-address frames | 261 | * @use_4addr: use 4-address frames |
264 | */ | 262 | */ |
265 | struct vif_params { | 263 | struct vif_params { |
266 | u8 *mesh_id; | ||
267 | int mesh_id_len; | ||
268 | int use_4addr; | 264 | int use_4addr; |
269 | }; | 265 | }; |
270 | 266 | ||
@@ -615,6 +611,11 @@ struct bss_parameters { | |||
615 | int ap_isolate; | 611 | int ap_isolate; |
616 | }; | 612 | }; |
617 | 613 | ||
614 | /* | ||
615 | * struct mesh_config - 802.11s mesh configuration | ||
616 | * | ||
617 | * These parameters can be changed while the mesh is active. | ||
618 | */ | ||
618 | struct mesh_config { | 619 | struct mesh_config { |
619 | /* Timeouts in ms */ | 620 | /* Timeouts in ms */ |
620 | /* Mesh plink management parameters */ | 621 | /* Mesh plink management parameters */ |
@@ -638,6 +639,18 @@ struct mesh_config { | |||
638 | }; | 639 | }; |
639 | 640 | ||
640 | /** | 641 | /** |
642 | * struct mesh_setup - 802.11s mesh setup configuration | ||
643 | * @mesh_id: the mesh ID | ||
644 | * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes | ||
645 | * | ||
646 | * These parameters are fixed when the mesh is created. | ||
647 | */ | ||
648 | struct mesh_setup { | ||
649 | const u8 *mesh_id; | ||
650 | u8 mesh_id_len; | ||
651 | }; | ||
652 | |||
653 | /** | ||
641 | * struct ieee80211_txq_params - TX queue parameters | 654 | * struct ieee80211_txq_params - TX queue parameters |
642 | * @queue: TX queue identifier (NL80211_TXQ_Q_*) | 655 | * @queue: TX queue identifier (NL80211_TXQ_Q_*) |
643 | * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled | 656 | * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled |
@@ -1078,7 +1091,7 @@ struct cfg80211_pmksa { | |||
1078 | * | 1091 | * |
1079 | * @get_mesh_params: Put the current mesh parameters into *params | 1092 | * @get_mesh_params: Put the current mesh parameters into *params |
1080 | * | 1093 | * |
1081 | * @set_mesh_params: Set mesh parameters. | 1094 | * @update_mesh_params: Update mesh parameters on a running mesh. |
1082 | * The mask is a bitfield which tells us which parameters to | 1095 | * The mask is a bitfield which tells us which parameters to |
1083 | * set, and which to leave alone. | 1096 | * set, and which to leave alone. |
1084 | * | 1097 | * |
@@ -1229,9 +1242,14 @@ struct cfg80211_ops { | |||
1229 | int (*get_mesh_params)(struct wiphy *wiphy, | 1242 | int (*get_mesh_params)(struct wiphy *wiphy, |
1230 | struct net_device *dev, | 1243 | struct net_device *dev, |
1231 | struct mesh_config *conf); | 1244 | struct mesh_config *conf); |
1232 | int (*set_mesh_params)(struct wiphy *wiphy, | 1245 | int (*update_mesh_params)(struct wiphy *wiphy, |
1233 | struct net_device *dev, | 1246 | struct net_device *dev, u32 mask, |
1234 | const struct mesh_config *nconf, u32 mask); | 1247 | const struct mesh_config *nconf); |
1248 | int (*join_mesh)(struct wiphy *wiphy, struct net_device *dev, | ||
1249 | const struct mesh_config *conf, | ||
1250 | const struct mesh_setup *setup); | ||
1251 | int (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev); | ||
1252 | |||
1235 | int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, | 1253 | int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, |
1236 | struct bss_parameters *params); | 1254 | struct bss_parameters *params); |
1237 | 1255 | ||
@@ -1647,6 +1665,8 @@ struct cfg80211_cached_keys; | |||
1647 | * @bssid: (private) Used by the internal configuration code | 1665 | * @bssid: (private) Used by the internal configuration code |
1648 | * @ssid: (private) Used by the internal configuration code | 1666 | * @ssid: (private) Used by the internal configuration code |
1649 | * @ssid_len: (private) Used by the internal configuration code | 1667 | * @ssid_len: (private) Used by the internal configuration code |
1668 | * @mesh_id_len: (private) Used by the internal configuration code | ||
1669 | * @mesh_id_up_len: (private) Used by the internal configuration code | ||
1650 | * @wext: (private) Used by the internal wireless extensions compat code | 1670 | * @wext: (private) Used by the internal wireless extensions compat code |
1651 | * @use_4addr: indicates 4addr mode is used on this interface, must be | 1671 | * @use_4addr: indicates 4addr mode is used on this interface, must be |
1652 | * set by driver (if supported) on add_interface BEFORE registering the | 1672 | * set by driver (if supported) on add_interface BEFORE registering the |
@@ -1676,7 +1696,7 @@ struct wireless_dev { | |||
1676 | 1696 | ||
1677 | /* currently used for IBSS and SME - might be rearranged later */ | 1697 | /* currently used for IBSS and SME - might be rearranged later */ |
1678 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 1698 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
1679 | u8 ssid_len; | 1699 | u8 ssid_len, mesh_id_len, mesh_id_up_len; |
1680 | enum { | 1700 | enum { |
1681 | CFG80211_SME_IDLE, | 1701 | CFG80211_SME_IDLE, |
1682 | CFG80211_SME_CONNECTING, | 1702 | CFG80211_SME_CONNECTING, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d34c7c3dd76..68329d713c0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -60,11 +60,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
60 | if (ret) | 60 | if (ret) |
61 | return ret; | 61 | return ret; |
62 | 62 | ||
63 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | ||
64 | ieee80211_sdata_set_mesh_id(sdata, | ||
65 | params->mesh_id_len, | ||
66 | params->mesh_id); | ||
67 | |||
68 | if (type == NL80211_IFTYPE_AP_VLAN && | 63 | if (type == NL80211_IFTYPE_AP_VLAN && |
69 | params && params->use_4addr == 0) | 64 | params && params->use_4addr == 0) |
70 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | 65 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); |
@@ -1003,9 +998,9 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) | |||
1003 | return (mask >> (parm-1)) & 0x1; | 998 | return (mask >> (parm-1)) & 0x1; |
1004 | } | 999 | } |
1005 | 1000 | ||
1006 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, | 1001 | static int ieee80211_update_mesh_params(struct wiphy *wiphy, |
1007 | struct net_device *dev, | 1002 | struct net_device *dev, u32 mask, |
1008 | const struct mesh_config *nconf, u32 mask) | 1003 | const struct mesh_config *nconf) |
1009 | { | 1004 | { |
1010 | struct mesh_config *conf; | 1005 | struct mesh_config *conf; |
1011 | struct ieee80211_sub_if_data *sdata; | 1006 | struct ieee80211_sub_if_data *sdata; |
@@ -1056,6 +1051,30 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1056 | return 0; | 1051 | return 0; |
1057 | } | 1052 | } |
1058 | 1053 | ||
1054 | static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | ||
1055 | const struct mesh_config *conf, | ||
1056 | const struct mesh_setup *setup) | ||
1057 | { | ||
1058 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1059 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
1060 | |||
1061 | memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config)); | ||
1062 | ifmsh->mesh_id_len = setup->mesh_id_len; | ||
1063 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | ||
1064 | |||
1065 | ieee80211_start_mesh(sdata); | ||
1066 | |||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | ||
1071 | { | ||
1072 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1073 | |||
1074 | ieee80211_stop_mesh(sdata); | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1059 | #endif | 1078 | #endif |
1060 | 1079 | ||
1061 | static int ieee80211_change_bss(struct wiphy *wiphy, | 1080 | static int ieee80211_change_bss(struct wiphy *wiphy, |
@@ -1760,8 +1779,10 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1760 | .change_mpath = ieee80211_change_mpath, | 1779 | .change_mpath = ieee80211_change_mpath, |
1761 | .get_mpath = ieee80211_get_mpath, | 1780 | .get_mpath = ieee80211_get_mpath, |
1762 | .dump_mpath = ieee80211_dump_mpath, | 1781 | .dump_mpath = ieee80211_dump_mpath, |
1763 | .set_mesh_params = ieee80211_set_mesh_params, | 1782 | .update_mesh_params = ieee80211_update_mesh_params, |
1764 | .get_mesh_params = ieee80211_get_mesh_params, | 1783 | .get_mesh_params = ieee80211_get_mesh_params, |
1784 | .join_mesh = ieee80211_join_mesh, | ||
1785 | .leave_mesh = ieee80211_leave_mesh, | ||
1765 | #endif | 1786 | #endif |
1766 | .change_bss = ieee80211_change_bss, | 1787 | .change_bss = ieee80211_change_bss, |
1767 | .set_txq_params = ieee80211_set_txq_params, | 1788 | .set_txq_params = ieee80211_set_txq_params, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e7c88072563..72499fe5fc3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -609,19 +609,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) | |||
609 | return container_of(p, struct ieee80211_sub_if_data, vif); | 609 | return container_of(p, struct ieee80211_sub_if_data, vif); |
610 | } | 610 | } |
611 | 611 | ||
612 | static inline void | ||
613 | ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata, | ||
614 | u8 mesh_id_len, u8 *mesh_id) | ||
615 | { | ||
616 | #ifdef CONFIG_MAC80211_MESH | ||
617 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
618 | ifmsh->mesh_id_len = mesh_id_len; | ||
619 | memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len); | ||
620 | #else | ||
621 | WARN_ON(1); | ||
622 | #endif | ||
623 | } | ||
624 | |||
625 | enum sdata_queue_type { | 612 | enum sdata_queue_type { |
626 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 613 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
627 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 614 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 96e27f1e79f..f0f11bb794a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -268,9 +268,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
268 | goto err_stop; | 268 | goto err_stop; |
269 | } | 269 | } |
270 | 270 | ||
271 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 271 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
272 | ieee80211_start_mesh(sdata); | ||
273 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
274 | local->fif_pspoll++; | 272 | local->fif_pspoll++; |
275 | local->fif_probe_req++; | 273 | local->fif_probe_req++; |
276 | 274 | ||
@@ -495,10 +493,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
495 | ieee80211_adjust_monitor_flags(sdata, -1); | 493 | ieee80211_adjust_monitor_flags(sdata, -1); |
496 | ieee80211_configure_filter(local); | 494 | ieee80211_configure_filter(local); |
497 | break; | 495 | break; |
498 | case NL80211_IFTYPE_MESH_POINT: | ||
499 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
500 | ieee80211_stop_mesh(sdata); | ||
501 | /* fall through */ | ||
502 | default: | 496 | default: |
503 | flush_work(&sdata->work); | 497 | flush_work(&sdata->work); |
504 | /* | 498 | /* |
@@ -1188,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1188 | if (ret) | 1182 | if (ret) |
1189 | goto fail; | 1183 | goto fail; |
1190 | 1184 | ||
1191 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
1192 | params && params->mesh_id_len) | ||
1193 | ieee80211_sdata_set_mesh_id(sdata, | ||
1194 | params->mesh_id_len, | ||
1195 | params->mesh_id); | ||
1196 | |||
1197 | mutex_lock(&local->iflist_mtx); | 1185 | mutex_lock(&local->iflist_mtx); |
1198 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 1186 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
1199 | mutex_unlock(&local->iflist_mtx); | 1187 | mutex_unlock(&local->iflist_mtx); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 107a0cbe52a..2de69766c6a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -246,7 +246,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
246 | !!sdata->u.ibss.presp; | 246 | !!sdata->u.ibss.presp; |
247 | break; | 247 | break; |
248 | case NL80211_IFTYPE_MESH_POINT: | 248 | case NL80211_IFTYPE_MESH_POINT: |
249 | sdata->vif.bss_conf.enable_beacon = true; | 249 | sdata->vif.bss_conf.enable_beacon = |
250 | !!sdata->u.mesh.mesh_id_len; | ||
250 | break; | 251 | break; |
251 | default: | 252 | default: |
252 | /* not reached */ | 253 | /* not reached */ |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 0d3234875ac..63e1188d506 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -530,6 +530,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
530 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 530 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
531 | { | 531 | { |
532 | struct ieee80211_local *local = sdata->local; | 532 | struct ieee80211_local *local = sdata->local; |
533 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
534 | |||
535 | ifmsh->mesh_id_len = 0; | ||
536 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | ||
537 | sta_info_flush(local, NULL); | ||
533 | 538 | ||
534 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 539 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
535 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 540 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
@@ -674,27 +679,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
674 | ieee80211_mesh_housekeeping_timer, | 679 | ieee80211_mesh_housekeeping_timer, |
675 | (unsigned long) sdata); | 680 | (unsigned long) sdata); |
676 | 681 | ||
677 | ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; | ||
678 | ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | ||
679 | ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | ||
680 | ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | ||
681 | ifmsh->mshcfg.dot11MeshTTL = MESH_TTL; | ||
682 | ifmsh->mshcfg.element_ttl = MESH_DEFAULT_ELEMENT_TTL; | ||
683 | ifmsh->mshcfg.auto_open_plinks = true; | ||
684 | ifmsh->mshcfg.dot11MeshMaxPeerLinks = | ||
685 | MESH_MAX_ESTAB_PLINKS; | ||
686 | ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout = | ||
687 | MESH_PATH_TIMEOUT; | ||
688 | ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval = | ||
689 | MESH_PREQ_MIN_INT; | ||
690 | ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = | ||
691 | MESH_DIAM_TRAVERSAL_TIME; | ||
692 | ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries = | ||
693 | MESH_MAX_PREQ_RETRIES; | ||
694 | ifmsh->mshcfg.path_refresh_time = | ||
695 | MESH_PATH_REFRESH_TIME; | ||
696 | ifmsh->mshcfg.min_discovery_timeout = | ||
697 | MESH_MIN_DISCOVERY_TIMEOUT; | ||
698 | ifmsh->accepting_plinks = true; | 682 | ifmsh->accepting_plinks = true; |
699 | ifmsh->preq_id = 0; | 683 | ifmsh->preq_id = 0; |
700 | ifmsh->sn = 0; | 684 | ifmsh->sn = 0; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 182942eeac4..039d7fa0af7 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -175,33 +175,10 @@ struct mesh_rmc { | |||
175 | */ | 175 | */ |
176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) | 176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) |
177 | 177 | ||
178 | /* Default values, timeouts in ms */ | ||
179 | #define MESH_TTL 31 | ||
180 | #define MESH_MAX_RETR 3 | ||
181 | #define MESH_RET_T 100 | ||
182 | #define MESH_CONF_T 100 | ||
183 | #define MESH_HOLD_T 100 | ||
184 | |||
185 | #define MESH_PATH_TIMEOUT 5000 | ||
186 | /* Minimum interval between two consecutive PREQs originated by the same | ||
187 | * interface | ||
188 | */ | ||
189 | #define MESH_PREQ_MIN_INT 10 | ||
190 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
191 | /* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before | ||
192 | * timing out. This way it will remain ACTIVE and no data frames will be | ||
193 | * unnecesarily held in the pending queue. | ||
194 | */ | ||
195 | #define MESH_PATH_REFRESH_TIME 1000 | ||
196 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
197 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ | 178 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ |
198 | 179 | ||
199 | #define MESH_MAX_PREQ_RETRIES 4 | ||
200 | #define MESH_PATH_EXPIRE (600 * HZ) | 180 | #define MESH_PATH_EXPIRE (600 * HZ) |
201 | 181 | ||
202 | /* Default maximum number of established plinks per interface */ | ||
203 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
204 | |||
205 | /* Default maximum number of plinks per interface */ | 182 | /* Default maximum number of plinks per interface */ |
206 | #define MESH_MAX_PLINKS 256 | 183 | #define MESH_MAX_PLINKS 256 |
207 | 184 | ||
@@ -216,8 +193,6 @@ struct mesh_rmc { | |||
216 | #define PERR_RCODE_NO_ROUTE 12 | 193 | #define PERR_RCODE_NO_ROUTE 12 |
217 | #define PERR_RCODE_DEST_UNREACH 13 | 194 | #define PERR_RCODE_DEST_UNREACH 13 |
218 | 195 | ||
219 | #define MESH_DEFAULT_ELEMENT_TTL 31 | ||
220 | |||
221 | /* Public interfaces */ | 196 | /* Public interfaces */ |
222 | /* Various */ | 197 | /* Various */ |
223 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | 198 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index e77e508126f..55a28ab21db 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 630bcf0a2f0..79772fcc37b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -332,6 +332,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
332 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); | 332 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); |
333 | WARN_ON(ops->add_station && !ops->del_station); | 333 | WARN_ON(ops->add_station && !ops->del_station); |
334 | WARN_ON(ops->add_mpath && !ops->del_mpath); | 334 | WARN_ON(ops->add_mpath && !ops->del_mpath); |
335 | WARN_ON(ops->join_mesh && !ops->leave_mesh); | ||
335 | 336 | ||
336 | alloc_size = sizeof(*rdev) + sizeof_priv; | 337 | alloc_size = sizeof(*rdev) + sizeof_priv; |
337 | 338 | ||
@@ -752,6 +753,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
752 | cfg80211_mlme_down(rdev, dev); | 753 | cfg80211_mlme_down(rdev, dev); |
753 | wdev_unlock(wdev); | 754 | wdev_unlock(wdev); |
754 | break; | 755 | break; |
756 | case NL80211_IFTYPE_MESH_POINT: | ||
757 | cfg80211_leave_mesh(rdev, dev); | ||
758 | break; | ||
755 | default: | 759 | default: |
756 | break; | 760 | break; |
757 | } | 761 | } |
@@ -775,20 +779,27 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
775 | } | 779 | } |
776 | cfg80211_lock_rdev(rdev); | 780 | cfg80211_lock_rdev(rdev); |
777 | mutex_lock(&rdev->devlist_mtx); | 781 | mutex_lock(&rdev->devlist_mtx); |
778 | #ifdef CONFIG_CFG80211_WEXT | ||
779 | wdev_lock(wdev); | 782 | wdev_lock(wdev); |
780 | switch (wdev->iftype) { | 783 | switch (wdev->iftype) { |
784 | #ifdef CONFIG_CFG80211_WEXT | ||
781 | case NL80211_IFTYPE_ADHOC: | 785 | case NL80211_IFTYPE_ADHOC: |
782 | cfg80211_ibss_wext_join(rdev, wdev); | 786 | cfg80211_ibss_wext_join(rdev, wdev); |
783 | break; | 787 | break; |
784 | case NL80211_IFTYPE_STATION: | 788 | case NL80211_IFTYPE_STATION: |
785 | cfg80211_mgd_wext_connect(rdev, wdev); | 789 | cfg80211_mgd_wext_connect(rdev, wdev); |
786 | break; | 790 | break; |
791 | #endif | ||
792 | case NL80211_IFTYPE_MESH_POINT: | ||
793 | /* backward compat code ... */ | ||
794 | if (wdev->mesh_id_up_len) | ||
795 | __cfg80211_join_mesh(rdev, dev, wdev->ssid, | ||
796 | wdev->mesh_id_up_len, | ||
797 | &default_mesh_config); | ||
798 | break; | ||
787 | default: | 799 | default: |
788 | break; | 800 | break; |
789 | } | 801 | } |
790 | wdev_unlock(wdev); | 802 | wdev_unlock(wdev); |
791 | #endif | ||
792 | rdev->opencount++; | 803 | rdev->opencount++; |
793 | mutex_unlock(&rdev->devlist_mtx); | 804 | mutex_unlock(&rdev->devlist_mtx); |
794 | cfg80211_unlock_rdev(rdev); | 805 | cfg80211_unlock_rdev(rdev); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index ee80ad8dc65..743203bb61a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -285,6 +285,19 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | |||
285 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 285 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
286 | struct wireless_dev *wdev); | 286 | struct wireless_dev *wdev); |
287 | 287 | ||
288 | /* mesh */ | ||
289 | extern const struct mesh_config default_mesh_config; | ||
290 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
291 | struct net_device *dev, | ||
292 | const u8 *mesh_id, u8 mesh_id_len, | ||
293 | const struct mesh_config *conf); | ||
294 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
295 | struct net_device *dev, | ||
296 | const u8 *mesh_id, u8 mesh_id_len, | ||
297 | const struct mesh_config *conf); | ||
298 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
299 | struct net_device *dev); | ||
300 | |||
288 | /* MLME */ | 301 | /* MLME */ |
289 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 302 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
290 | struct net_device *dev, | 303 | struct net_device *dev, |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c new file mode 100644 index 00000000000..e0b9747fe50 --- /dev/null +++ b/net/wireless/mesh.c | |||
@@ -0,0 +1,140 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <net/cfg80211.h> | ||
3 | #include "core.h" | ||
4 | |||
5 | /* Default values, timeouts in ms */ | ||
6 | #define MESH_TTL 31 | ||
7 | #define MESH_DEFAULT_ELEMENT_TTL 31 | ||
8 | #define MESH_MAX_RETR 3 | ||
9 | #define MESH_RET_T 100 | ||
10 | #define MESH_CONF_T 100 | ||
11 | #define MESH_HOLD_T 100 | ||
12 | |||
13 | #define MESH_PATH_TIMEOUT 5000 | ||
14 | |||
15 | /* | ||
16 | * Minimum interval between two consecutive PREQs originated by the same | ||
17 | * interface | ||
18 | */ | ||
19 | #define MESH_PREQ_MIN_INT 10 | ||
20 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
21 | |||
22 | /* | ||
23 | * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds | ||
24 | * before timing out. This way it will remain ACTIVE and no data frames | ||
25 | * will be unnecessarily held in the pending queue. | ||
26 | */ | ||
27 | #define MESH_PATH_REFRESH_TIME 1000 | ||
28 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
29 | |||
30 | /* Default maximum number of established plinks per interface */ | ||
31 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
32 | |||
33 | #define MESH_MAX_PREQ_RETRIES 4 | ||
34 | |||
35 | |||
36 | const struct mesh_config default_mesh_config = { | ||
37 | .dot11MeshRetryTimeout = MESH_RET_T, | ||
38 | .dot11MeshConfirmTimeout = MESH_CONF_T, | ||
39 | .dot11MeshHoldingTimeout = MESH_HOLD_T, | ||
40 | .dot11MeshMaxRetries = MESH_MAX_RETR, | ||
41 | .dot11MeshTTL = MESH_TTL, | ||
42 | .element_ttl = MESH_DEFAULT_ELEMENT_TTL, | ||
43 | .auto_open_plinks = true, | ||
44 | .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, | ||
45 | .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, | ||
46 | .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, | ||
47 | .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, | ||
48 | .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, | ||
49 | .path_refresh_time = MESH_PATH_REFRESH_TIME, | ||
50 | .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, | ||
51 | }; | ||
52 | |||
53 | |||
54 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
55 | struct net_device *dev, | ||
56 | const u8 *mesh_id, u8 mesh_id_len, | ||
57 | const struct mesh_config *conf) | ||
58 | { | ||
59 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
60 | struct mesh_setup setup = { | ||
61 | .mesh_id = mesh_id, | ||
62 | .mesh_id_len = mesh_id_len, | ||
63 | }; | ||
64 | int err; | ||
65 | |||
66 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); | ||
67 | |||
68 | ASSERT_WDEV_LOCK(wdev); | ||
69 | |||
70 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
71 | return -EOPNOTSUPP; | ||
72 | |||
73 | if (wdev->mesh_id_len) | ||
74 | return -EALREADY; | ||
75 | |||
76 | if (!mesh_id_len) | ||
77 | return -EINVAL; | ||
78 | |||
79 | if (!rdev->ops->join_mesh) | ||
80 | return -EOPNOTSUPP; | ||
81 | |||
82 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, &setup); | ||
83 | if (!err) { | ||
84 | memcpy(wdev->ssid, mesh_id, mesh_id_len); | ||
85 | wdev->mesh_id_len = mesh_id_len; | ||
86 | } | ||
87 | |||
88 | return err; | ||
89 | } | ||
90 | |||
91 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
92 | struct net_device *dev, | ||
93 | const u8 *mesh_id, u8 mesh_id_len, | ||
94 | const struct mesh_config *conf) | ||
95 | { | ||
96 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
97 | int err; | ||
98 | |||
99 | wdev_lock(wdev); | ||
100 | err = __cfg80211_join_mesh(rdev, dev, mesh_id, mesh_id_len, conf); | ||
101 | wdev_unlock(wdev); | ||
102 | |||
103 | return err; | ||
104 | } | ||
105 | |||
106 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
107 | struct net_device *dev) | ||
108 | { | ||
109 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
110 | int err; | ||
111 | |||
112 | ASSERT_WDEV_LOCK(wdev); | ||
113 | |||
114 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
115 | return -EOPNOTSUPP; | ||
116 | |||
117 | if (!rdev->ops->leave_mesh) | ||
118 | return -EOPNOTSUPP; | ||
119 | |||
120 | if (!wdev->mesh_id_len) | ||
121 | return -ENOTCONN; | ||
122 | |||
123 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | ||
124 | if (!err) | ||
125 | wdev->mesh_id_len = 0; | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
130 | struct net_device *dev) | ||
131 | { | ||
132 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
133 | int err; | ||
134 | |||
135 | wdev_lock(wdev); | ||
136 | err = __cfg80211_leave_mesh(rdev, dev); | ||
137 | wdev_unlock(wdev); | ||
138 | |||
139 | return err; | ||
140 | } | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c8d4d53fc45..56508d40c74 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -661,13 +661,14 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
661 | CMD(add_beacon, NEW_BEACON); | 661 | CMD(add_beacon, NEW_BEACON); |
662 | CMD(add_station, NEW_STATION); | 662 | CMD(add_station, NEW_STATION); |
663 | CMD(add_mpath, NEW_MPATH); | 663 | CMD(add_mpath, NEW_MPATH); |
664 | CMD(set_mesh_params, SET_MESH_PARAMS); | 664 | CMD(update_mesh_params, SET_MESH_PARAMS); |
665 | CMD(change_bss, SET_BSS); | 665 | CMD(change_bss, SET_BSS); |
666 | CMD(auth, AUTHENTICATE); | 666 | CMD(auth, AUTHENTICATE); |
667 | CMD(assoc, ASSOCIATE); | 667 | CMD(assoc, ASSOCIATE); |
668 | CMD(deauth, DEAUTHENTICATE); | 668 | CMD(deauth, DEAUTHENTICATE); |
669 | CMD(disassoc, DISASSOCIATE); | 669 | CMD(disassoc, DISASSOCIATE); |
670 | CMD(join_ibss, JOIN_IBSS); | 670 | CMD(join_ibss, JOIN_IBSS); |
671 | CMD(join_mesh, JOIN_MESH); | ||
671 | CMD(set_pmksa, SET_PMKSA); | 672 | CMD(set_pmksa, SET_PMKSA); |
672 | CMD(del_pmksa, DEL_PMKSA); | 673 | CMD(del_pmksa, DEL_PMKSA); |
673 | CMD(flush_pmksa, FLUSH_PMKSA); | 674 | CMD(flush_pmksa, FLUSH_PMKSA); |
@@ -1324,11 +1325,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1324 | } | 1325 | } |
1325 | 1326 | ||
1326 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1327 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1328 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1329 | |||
1327 | if (ntype != NL80211_IFTYPE_MESH_POINT) | 1330 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1328 | return -EINVAL; | 1331 | return -EINVAL; |
1329 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1332 | if (netif_running(dev)) |
1330 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1333 | return -EBUSY; |
1331 | change = true; | 1334 | |
1335 | wdev_lock(wdev); | ||
1336 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | ||
1337 | IEEE80211_MAX_MESH_ID_LEN); | ||
1338 | wdev->mesh_id_up_len = | ||
1339 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1340 | memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
1341 | wdev->mesh_id_up_len); | ||
1342 | wdev_unlock(wdev); | ||
1332 | } | 1343 | } |
1333 | 1344 | ||
1334 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1345 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
@@ -1388,12 +1399,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1388 | !(rdev->wiphy.interface_modes & (1 << type))) | 1399 | !(rdev->wiphy.interface_modes & (1 << type))) |
1389 | return -EOPNOTSUPP; | 1400 | return -EOPNOTSUPP; |
1390 | 1401 | ||
1391 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
1392 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
1393 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1394 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1395 | } | ||
1396 | |||
1397 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1402 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
1398 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1403 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1399 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1404 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
@@ -1410,6 +1415,20 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1410 | if (IS_ERR(dev)) | 1415 | if (IS_ERR(dev)) |
1411 | return PTR_ERR(dev); | 1416 | return PTR_ERR(dev); |
1412 | 1417 | ||
1418 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
1419 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
1420 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1421 | |||
1422 | wdev_lock(wdev); | ||
1423 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | ||
1424 | IEEE80211_MAX_MESH_ID_LEN); | ||
1425 | wdev->mesh_id_up_len = | ||
1426 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1427 | memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
1428 | wdev->mesh_id_up_len); | ||
1429 | wdev_unlock(wdev); | ||
1430 | } | ||
1431 | |||
1413 | return 0; | 1432 | return 0; |
1414 | } | 1433 | } |
1415 | 1434 | ||
@@ -2543,21 +2562,32 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2543 | } | 2562 | } |
2544 | 2563 | ||
2545 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2564 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2546 | struct genl_info *info) | 2565 | struct genl_info *info) |
2547 | { | 2566 | { |
2548 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2567 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2549 | struct mesh_config cur_params; | ||
2550 | int err; | ||
2551 | struct net_device *dev = info->user_ptr[1]; | 2568 | struct net_device *dev = info->user_ptr[1]; |
2569 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2570 | struct mesh_config cur_params; | ||
2571 | int err = 0; | ||
2552 | void *hdr; | 2572 | void *hdr; |
2553 | struct nlattr *pinfoattr; | 2573 | struct nlattr *pinfoattr; |
2554 | struct sk_buff *msg; | 2574 | struct sk_buff *msg; |
2555 | 2575 | ||
2576 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | ||
2577 | return -EOPNOTSUPP; | ||
2578 | |||
2556 | if (!rdev->ops->get_mesh_params) | 2579 | if (!rdev->ops->get_mesh_params) |
2557 | return -EOPNOTSUPP; | 2580 | return -EOPNOTSUPP; |
2558 | 2581 | ||
2559 | /* Get the mesh params */ | 2582 | wdev_lock(wdev); |
2560 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2583 | /* If not connected, get default parameters */ |
2584 | if (!wdev->mesh_id_len) | ||
2585 | memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); | ||
2586 | else | ||
2587 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, | ||
2588 | &cur_params); | ||
2589 | wdev_unlock(wdev); | ||
2590 | |||
2561 | if (err) | 2591 | if (err) |
2562 | return err; | 2592 | return err; |
2563 | 2593 | ||
@@ -2705,23 +2735,37 @@ do {\ | |||
2705 | #undef FILL_IN_MESH_PARAM_IF_SET | 2735 | #undef FILL_IN_MESH_PARAM_IF_SET |
2706 | } | 2736 | } |
2707 | 2737 | ||
2708 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2738 | static int nl80211_update_mesh_params(struct sk_buff *skb, |
2739 | struct genl_info *info) | ||
2709 | { | 2740 | { |
2710 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2741 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2711 | struct net_device *dev = info->user_ptr[1]; | 2742 | struct net_device *dev = info->user_ptr[1]; |
2743 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2712 | struct mesh_config cfg; | 2744 | struct mesh_config cfg; |
2713 | u32 mask; | 2745 | u32 mask; |
2714 | int err; | 2746 | int err; |
2715 | 2747 | ||
2716 | if (!rdev->ops->set_mesh_params) | 2748 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) |
2749 | return -EOPNOTSUPP; | ||
2750 | |||
2751 | if (!rdev->ops->update_mesh_params) | ||
2717 | return -EOPNOTSUPP; | 2752 | return -EOPNOTSUPP; |
2718 | 2753 | ||
2719 | err = nl80211_parse_mesh_params(info, &cfg, &mask); | 2754 | err = nl80211_parse_mesh_params(info, &cfg, &mask); |
2720 | if (err) | 2755 | if (err) |
2721 | return err; | 2756 | return err; |
2722 | 2757 | ||
2723 | /* Apply changes */ | 2758 | wdev_lock(wdev); |
2724 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2759 | if (!wdev->mesh_id_len) |
2760 | err = -ENOLINK; | ||
2761 | |||
2762 | if (!err) | ||
2763 | err = rdev->ops->update_mesh_params(&rdev->wiphy, dev, | ||
2764 | mask, &cfg); | ||
2765 | |||
2766 | wdev_unlock(wdev); | ||
2767 | |||
2768 | return err; | ||
2725 | } | 2769 | } |
2726 | 2770 | ||
2727 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 2771 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) |
@@ -4505,6 +4549,41 @@ out: | |||
4505 | return err; | 4549 | return err; |
4506 | } | 4550 | } |
4507 | 4551 | ||
4552 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | ||
4553 | { | ||
4554 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4555 | struct net_device *dev = info->user_ptr[1]; | ||
4556 | struct mesh_config cfg; | ||
4557 | int err; | ||
4558 | |||
4559 | /* start with default */ | ||
4560 | memcpy(&cfg, &default_mesh_config, sizeof(cfg)); | ||
4561 | |||
4562 | if (info->attrs[NL80211_ATTR_MESH_PARAMS]) { | ||
4563 | /* and parse parameters if given */ | ||
4564 | err = nl80211_parse_mesh_params(info, &cfg, NULL); | ||
4565 | if (err) | ||
4566 | return err; | ||
4567 | } | ||
4568 | |||
4569 | if (!info->attrs[NL80211_ATTR_MESH_ID] || | ||
4570 | !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) | ||
4571 | return -EINVAL; | ||
4572 | |||
4573 | return cfg80211_join_mesh(rdev, dev, | ||
4574 | nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
4575 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]), | ||
4576 | &cfg); | ||
4577 | } | ||
4578 | |||
4579 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | ||
4580 | { | ||
4581 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4582 | struct net_device *dev = info->user_ptr[1]; | ||
4583 | |||
4584 | return cfg80211_leave_mesh(rdev, dev); | ||
4585 | } | ||
4586 | |||
4508 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 4587 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
4509 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 4588 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
4510 | #define NL80211_FLAG_NEED_RTNL 0x04 | 4589 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -4769,10 +4848,10 @@ static struct genl_ops nl80211_ops[] = { | |||
4769 | }, | 4848 | }, |
4770 | { | 4849 | { |
4771 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4850 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
4772 | .doit = nl80211_set_mesh_params, | 4851 | .doit = nl80211_update_mesh_params, |
4773 | .policy = nl80211_policy, | 4852 | .policy = nl80211_policy, |
4774 | .flags = GENL_ADMIN_PERM, | 4853 | .flags = GENL_ADMIN_PERM, |
4775 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 4854 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
4776 | NL80211_FLAG_NEED_RTNL, | 4855 | NL80211_FLAG_NEED_RTNL, |
4777 | }, | 4856 | }, |
4778 | { | 4857 | { |
@@ -4987,6 +5066,22 @@ static struct genl_ops nl80211_ops[] = { | |||
4987 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 5066 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
4988 | NL80211_FLAG_NEED_RTNL, | 5067 | NL80211_FLAG_NEED_RTNL, |
4989 | }, | 5068 | }, |
5069 | { | ||
5070 | .cmd = NL80211_CMD_JOIN_MESH, | ||
5071 | .doit = nl80211_join_mesh, | ||
5072 | .policy = nl80211_policy, | ||
5073 | .flags = GENL_ADMIN_PERM, | ||
5074 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5075 | NL80211_FLAG_NEED_RTNL, | ||
5076 | }, | ||
5077 | { | ||
5078 | .cmd = NL80211_CMD_LEAVE_MESH, | ||
5079 | .doit = nl80211_leave_mesh, | ||
5080 | .policy = nl80211_policy, | ||
5081 | .flags = GENL_ADMIN_PERM, | ||
5082 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5083 | NL80211_FLAG_NEED_RTNL, | ||
5084 | }, | ||
4990 | }; | 5085 | }; |
4991 | 5086 | ||
4992 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5087 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/util.c b/net/wireless/util.c index fee020b15a4..4de624ca4c6 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -792,6 +792,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
792 | 792 | ||
793 | if (ntype != otype) { | 793 | if (ntype != otype) { |
794 | dev->ieee80211_ptr->use_4addr = false; | 794 | dev->ieee80211_ptr->use_4addr = false; |
795 | dev->ieee80211_ptr->mesh_id_up_len = 0; | ||
795 | 796 | ||
796 | switch (otype) { | 797 | switch (otype) { |
797 | case NL80211_IFTYPE_ADHOC: | 798 | case NL80211_IFTYPE_ADHOC: |