mesh.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, 2009 open80211s Ltd.
00003  * Authors:    Luis Carlos Cobo <luisca@cozybit.com>
00004  *             Javier Cardona <javier@cozybit.com>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License version 2 as
00008  * published by the Free Software Foundation.
00009  */
00010 
00011 #include <linux/slab.h>
00012 #include <asm/unaligned.h>
00013 #include "ieee80211_i.h"
00014 #include "mesh.h"
00015 
00016 #define TMR_RUNNING_HK  0
00017 #define TMR_RUNNING_MP  1
00018 #define TMR_RUNNING_MPR 2
00019 
00020 int mesh_allocated;
00021 static struct kmem_cache *rm_cache;
00022 
00023 #ifdef CONFIG_MAC80211_MESH
00024 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
00025 {
00026         return (mgmt->u.action.u.mesh_action.action_code ==
00027                         WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
00028 }
00029 #else
00030 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
00031 { return false; }
00032 #endif
00033 
00034 void ieee80211s_init(void)
00035 {
00036         mesh_pathtbl_init();
00037         mesh_allocated = 1;
00038         rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
00039                                      0, 0, NULL);
00040 }
00041 
00042 void ieee80211s_stop(void)
00043 {
00044         mesh_pathtbl_unregister();
00045         kmem_cache_destroy(rm_cache);
00046 }
00047 
00048 static void ieee80211_mesh_housekeeping_timer(unsigned long data)
00049 {
00050         struct ieee80211_sub_if_data *sdata = (void *) data;
00051         struct ieee80211_local *local = sdata->local;
00052         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00053 
00054         set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
00055 
00056         if (local->quiescing) {
00057                 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
00058                 return;
00059         }
00060 
00061         ieee80211_queue_work(&local->hw, &sdata->work);
00062 }
00063 
00073 bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
00074                         struct ieee802_11_elems *ie)
00075 {
00076         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00077         struct ieee80211_local *local = sdata->local;
00078         u32 basic_rates = 0;
00079         enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT;
00080 
00081         /*
00082          * As support for each feature is added, check for matching
00083          * - On mesh config capabilities
00084          *   - Power Save Support En
00085          *   - Sync support enabled
00086          *   - Sync support active
00087          *   - Sync support required from peer
00088          *   - MDA enabled
00089          * - Power management control on fc
00090          */
00091         if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
00092              memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
00093              (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
00094              (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
00095              (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
00096              (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
00097              (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
00098                 goto mismatch;
00099 
00100         ieee80211_sta_get_rates(local, ie, local->oper_channel->band,
00101                                 &basic_rates);
00102 
00103         if (sdata->vif.bss_conf.basic_rates != basic_rates)
00104                 goto mismatch;
00105 
00106         if (ie->ht_operation)
00107                 sta_channel_type =
00108                         ieee80211_ht_oper_to_channel_type(ie->ht_operation);
00109 
00110         /* Disallow HT40+/- mismatch */
00111         if (ie->ht_operation &&
00112             (local->_oper_channel_type == NL80211_CHAN_HT40MINUS ||
00113             local->_oper_channel_type == NL80211_CHAN_HT40PLUS) &&
00114             (sta_channel_type == NL80211_CHAN_HT40MINUS ||
00115              sta_channel_type == NL80211_CHAN_HT40PLUS) &&
00116             local->_oper_channel_type != sta_channel_type)
00117                 goto mismatch;
00118 
00119         return true;
00120 mismatch:
00121         return false;
00122 }
00123 
00129 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
00130 {
00131         return (ie->mesh_config->meshconf_cap &
00132             MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
00133 }
00134 
00140 void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
00141 {
00142         bool free_plinks;
00143 
00144         /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
00145          * the mesh interface might be able to establish plinks with peers that
00146          * are already on the table but are not on PLINK_ESTAB state. However,
00147          * in general the mesh interface is not accepting peer link requests
00148          * from new peers, and that must be reflected in the beacon
00149          */
00150         free_plinks = mesh_plink_availables(sdata);
00151 
00152         if (free_plinks != sdata->u.mesh.accepting_plinks)
00153                 ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
00154 }
00155 
00156 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
00157 {
00158         int i;
00159 
00160         sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
00161         if (!sdata->u.mesh.rmc)
00162                 return -ENOMEM;
00163         sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
00164         for (i = 0; i < RMC_BUCKETS; i++)
00165                 INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list);
00166         return 0;
00167 }
00168 
00169 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
00170 {
00171         struct mesh_rmc *rmc = sdata->u.mesh.rmc;
00172         struct rmc_entry *p, *n;
00173         int i;
00174 
00175         if (!sdata->u.mesh.rmc)
00176                 return;
00177 
00178         for (i = 0; i < RMC_BUCKETS; i++)
00179                 list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
00180                         list_del(&p->list);
00181                         kmem_cache_free(rm_cache, p);
00182                 }
00183 
00184         kfree(rmc);
00185         sdata->u.mesh.rmc = NULL;
00186 }
00187 
00200 int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
00201                    struct ieee80211_sub_if_data *sdata)
00202 {
00203         struct mesh_rmc *rmc = sdata->u.mesh.rmc;
00204         u32 seqnum = 0;
00205         int entries = 0;
00206         u8 idx;
00207         struct rmc_entry *p, *n;
00208 
00209         /* Don't care about endianness since only match matters */
00210         memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
00211         idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
00212         list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
00213                 ++entries;
00214                 if (time_after(jiffies, p->exp_time) ||
00215                                 (entries == RMC_QUEUE_MAX_LEN)) {
00216                         list_del(&p->list);
00217                         kmem_cache_free(rm_cache, p);
00218                         --entries;
00219                 } else if ((seqnum == p->seqnum) &&
00220                            (ether_addr_equal(sa, p->sa)))
00221                         return -1;
00222         }
00223 
00224         p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
00225         if (!p)
00226                 return 0;
00227 
00228         p->seqnum = seqnum;
00229         p->exp_time = jiffies + RMC_TIMEOUT;
00230         memcpy(p->sa, sa, ETH_ALEN);
00231         list_add(&p->list, &rmc->bucket[idx].list);
00232         return 0;
00233 }
00234 
00235 int
00236 mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
00237 {
00238         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00239         u8 *pos, neighbors;
00240         u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
00241 
00242         if (skb_tailroom(skb) < 2 + meshconf_len)
00243                 return -ENOMEM;
00244 
00245         pos = skb_put(skb, 2 + meshconf_len);
00246         *pos++ = WLAN_EID_MESH_CONFIG;
00247         *pos++ = meshconf_len;
00248 
00249         /* Active path selection protocol ID */
00250         *pos++ = ifmsh->mesh_pp_id;
00251         /* Active path selection metric ID   */
00252         *pos++ = ifmsh->mesh_pm_id;
00253         /* Congestion control mode identifier */
00254         *pos++ = ifmsh->mesh_cc_id;
00255         /* Synchronization protocol identifier */
00256         *pos++ = ifmsh->mesh_sp_id;
00257         /* Authentication Protocol identifier */
00258         *pos++ = ifmsh->mesh_auth_id;
00259         /* Mesh Formation Info - number of neighbors */
00260         neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
00261         /* Number of neighbor mesh STAs or 15 whichever is smaller */
00262         neighbors = (neighbors > 15) ? 15 : neighbors;
00263         *pos++ = neighbors << 1;
00264         /* Mesh capability */
00265         ifmsh->accepting_plinks = mesh_plink_availables(sdata);
00266         *pos = MESHCONF_CAPAB_FORWARDING;
00267         *pos |= ifmsh->accepting_plinks ?
00268             MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
00269         *pos++ |= ifmsh->adjusting_tbtt ?
00270             MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
00271         *pos++ = 0x00;
00272 
00273         return 0;
00274 }
00275 
00276 int
00277 mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
00278 {
00279         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00280         u8 *pos;
00281 
00282         if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
00283                 return -ENOMEM;
00284 
00285         pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
00286         *pos++ = WLAN_EID_MESH_ID;
00287         *pos++ = ifmsh->mesh_id_len;
00288         if (ifmsh->mesh_id_len)
00289                 memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
00290 
00291         return 0;
00292 }
00293 
00294 int
00295 mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
00296 {
00297         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00298         u8 offset, len;
00299         const u8 *data;
00300 
00301         if (!ifmsh->ie || !ifmsh->ie_len)
00302                 return 0;
00303 
00304         /* fast-forward to vendor IEs */
00305         offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
00306 
00307         if (offset) {
00308                 len = ifmsh->ie_len - offset;
00309                 data = ifmsh->ie + offset;
00310                 if (skb_tailroom(skb) < len)
00311                         return -ENOMEM;
00312                 memcpy(skb_put(skb, len), data, len);
00313         }
00314 
00315         return 0;
00316 }
00317 
00318 int
00319 mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
00320 {
00321         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00322         u8 len = 0;
00323         const u8 *data;
00324 
00325         if (!ifmsh->ie || !ifmsh->ie_len)
00326                 return 0;
00327 
00328         /* find RSN IE */
00329         data = ifmsh->ie;
00330         while (data < ifmsh->ie + ifmsh->ie_len) {
00331                 if (*data == WLAN_EID_RSN) {
00332                         len = data[1] + 2;
00333                         break;
00334                 }
00335                 data++;
00336         }
00337 
00338         if (len) {
00339                 if (skb_tailroom(skb) < len)
00340                         return -ENOMEM;
00341                 memcpy(skb_put(skb, len), data, len);
00342         }
00343 
00344         return 0;
00345 }
00346 
00347 int mesh_add_ds_params_ie(struct sk_buff *skb,
00348                           struct ieee80211_sub_if_data *sdata)
00349 {
00350         struct ieee80211_local *local = sdata->local;
00351         struct ieee80211_supported_band *sband;
00352         u8 *pos;
00353 
00354         if (skb_tailroom(skb) < 3)
00355                 return -ENOMEM;
00356 
00357         sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
00358         if (sband->band == IEEE80211_BAND_2GHZ) {
00359                 pos = skb_put(skb, 2 + 1);
00360                 *pos++ = WLAN_EID_DS_PARAMS;
00361                 *pos++ = 1;
00362                 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
00363         }
00364 
00365         return 0;
00366 }
00367 
00368 int mesh_add_ht_cap_ie(struct sk_buff *skb,
00369                        struct ieee80211_sub_if_data *sdata)
00370 {
00371         struct ieee80211_local *local = sdata->local;
00372         struct ieee80211_supported_band *sband;
00373         u8 *pos;
00374 
00375         sband = local->hw.wiphy->bands[local->oper_channel->band];
00376         if (!sband->ht_cap.ht_supported ||
00377             local->_oper_channel_type == NL80211_CHAN_NO_HT)
00378                 return 0;
00379 
00380         if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
00381                 return -ENOMEM;
00382 
00383         pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
00384         ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap);
00385 
00386         return 0;
00387 }
00388 
00389 int mesh_add_ht_oper_ie(struct sk_buff *skb,
00390                         struct ieee80211_sub_if_data *sdata)
00391 {
00392         struct ieee80211_local *local = sdata->local;
00393         struct ieee80211_channel *channel = local->oper_channel;
00394         enum nl80211_channel_type channel_type = local->_oper_channel_type;
00395         struct ieee80211_supported_band *sband =
00396                                 local->hw.wiphy->bands[channel->band];
00397         struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
00398         u8 *pos;
00399 
00400         if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
00401                 return 0;
00402 
00403         if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
00404                 return -ENOMEM;
00405 
00406         pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
00407         ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type,
00408                                    sdata->vif.bss_conf.ht_operation_mode);
00409 
00410         return 0;
00411 }
00412 static void ieee80211_mesh_path_timer(unsigned long data)
00413 {
00414         struct ieee80211_sub_if_data *sdata =
00415                 (struct ieee80211_sub_if_data *) data;
00416         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00417         struct ieee80211_local *local = sdata->local;
00418 
00419         if (local->quiescing) {
00420                 set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
00421                 return;
00422         }
00423 
00424         ieee80211_queue_work(&local->hw, &sdata->work);
00425 }
00426 
00427 static void ieee80211_mesh_path_root_timer(unsigned long data)
00428 {
00429         struct ieee80211_sub_if_data *sdata =
00430                 (struct ieee80211_sub_if_data *) data;
00431         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00432         struct ieee80211_local *local = sdata->local;
00433 
00434         set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
00435 
00436         if (local->quiescing) {
00437                 set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
00438                 return;
00439         }
00440 
00441         ieee80211_queue_work(&local->hw, &sdata->work);
00442 }
00443 
00444 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
00445 {
00446         if (ifmsh->mshcfg.dot11MeshHWMPRootMode)
00447                 set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
00448         else {
00449                 clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
00450                 /* stop running timer */
00451                 del_timer_sync(&ifmsh->mesh_path_root_timer);
00452         }
00453 }
00454 
00465 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
00466                                   const u8 *meshda, const u8 *meshsa)
00467 {
00468         if (is_multicast_ether_addr(meshda)) {
00469                 *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
00470                 /* DA TA SA */
00471                 memcpy(hdr->addr1, meshda, ETH_ALEN);
00472                 memcpy(hdr->addr2, meshsa, ETH_ALEN);
00473                 memcpy(hdr->addr3, meshsa, ETH_ALEN);
00474                 return 24;
00475         } else {
00476                 *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
00477                 /* RA TA DA SA */
00478                 memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
00479                 memcpy(hdr->addr2, meshsa, ETH_ALEN);
00480                 memcpy(hdr->addr3, meshda, ETH_ALEN);
00481                 memcpy(hdr->addr4, meshsa, ETH_ALEN);
00482                 return 30;
00483         }
00484 }
00485 
00498 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
00499                 struct ieee80211_sub_if_data *sdata, char *addr4or5,
00500                 char *addr6)
00501 {
00502         int aelen = 0;
00503         BUG_ON(!addr4or5 && addr6);
00504         memset(meshhdr, 0, sizeof(*meshhdr));
00505         meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
00506         put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
00507         sdata->u.mesh.mesh_seqnum++;
00508         if (addr4or5 && !addr6) {
00509                 meshhdr->flags |= MESH_FLAGS_AE_A4;
00510                 aelen += ETH_ALEN;
00511                 memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
00512         } else if (addr4or5 && addr6) {
00513                 meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
00514                 aelen += 2 * ETH_ALEN;
00515                 memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN);
00516                 memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
00517         }
00518         return 6 + aelen;
00519 }
00520 
00521 static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
00522                            struct ieee80211_if_mesh *ifmsh)
00523 {
00524         bool free_plinks;
00525 
00526 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
00527         printk(KERN_DEBUG "%s: running mesh housekeeping\n",
00528                sdata->name);
00529 #endif
00530 
00531         ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
00532         mesh_path_expire(sdata);
00533 
00534         free_plinks = mesh_plink_availables(sdata);
00535         if (free_plinks != sdata->u.mesh.accepting_plinks)
00536                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00537 
00538         mod_timer(&ifmsh->housekeeping_timer,
00539                   round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
00540 }
00541 
00542 static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
00543 {
00544         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00545 
00546         mesh_path_tx_root_frame(sdata);
00547         mod_timer(&ifmsh->mesh_path_root_timer,
00548                   round_jiffies(TU_TO_EXP_TIME(
00549                                   ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
00550 }
00551 
00552 #ifdef CONFIG_PM
00553 void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
00554 {
00555         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00556 
00557         /* use atomic bitops in case all timers fire at the same time */
00558 
00559         if (del_timer_sync(&ifmsh->housekeeping_timer))
00560                 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
00561         if (del_timer_sync(&ifmsh->mesh_path_timer))
00562                 set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
00563         if (del_timer_sync(&ifmsh->mesh_path_root_timer))
00564                 set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
00565 }
00566 
00567 void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
00568 {
00569         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00570 
00571         if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
00572                 add_timer(&ifmsh->housekeeping_timer);
00573         if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
00574                 add_timer(&ifmsh->mesh_path_timer);
00575         if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running))
00576                 add_timer(&ifmsh->mesh_path_root_timer);
00577         ieee80211_mesh_root_setup(ifmsh);
00578 }
00579 #endif
00580 
00581 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
00582 {
00583         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00584         struct ieee80211_local *local = sdata->local;
00585 
00586         local->fif_other_bss++;
00587         /* mesh ifaces must set allmulti to forward mcast traffic */
00588         atomic_inc(&local->iff_allmultis);
00589         ieee80211_configure_filter(local);
00590 
00591         ifmsh->mesh_cc_id = 0;  /* Disabled */
00592         ifmsh->mesh_auth_id = 0;        /* Disabled */
00593         /* register sync ops from extensible synchronization framework */
00594         ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id);
00595         ifmsh->adjusting_tbtt = false;
00596         ifmsh->sync_offset_clockdrift_max = 0;
00597         set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
00598         ieee80211_mesh_root_setup(ifmsh);
00599         ieee80211_queue_work(&local->hw, &sdata->work);
00600         sdata->vif.bss_conf.ht_operation_mode =
00601                                 ifmsh->mshcfg.ht_opmode;
00602         sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
00603         sdata->vif.bss_conf.basic_rates =
00604                 ieee80211_mandatory_rates(sdata->local,
00605                                           sdata->local->hw.conf.channel->band);
00606         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
00607                                                 BSS_CHANGED_BEACON_ENABLED |
00608                                                 BSS_CHANGED_HT |
00609                                                 BSS_CHANGED_BASIC_RATES |
00610                                                 BSS_CHANGED_BEACON_INT);
00611 }
00612 
00613 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
00614 {
00615         struct ieee80211_local *local = sdata->local;
00616         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00617 
00618         ifmsh->mesh_id_len = 0;
00619         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
00620         sta_info_flush(local, NULL);
00621 
00622         del_timer_sync(&sdata->u.mesh.housekeeping_timer);
00623         del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
00624         del_timer_sync(&sdata->u.mesh.mesh_path_timer);
00625         /*
00626          * If the timer fired while we waited for it, it will have
00627          * requeued the work. Now the work will be running again
00628          * but will not rearm the timer again because it checks
00629          * whether the interface is running, which, at this point,
00630          * it no longer is.
00631          */
00632         cancel_work_sync(&sdata->work);
00633 
00634         local->fif_other_bss--;
00635         atomic_dec(&local->iff_allmultis);
00636         ieee80211_configure_filter(local);
00637 }
00638 
00639 static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
00640                                         u16 stype,
00641                                         struct ieee80211_mgmt *mgmt,
00642                                         size_t len,
00643                                         struct ieee80211_rx_status *rx_status)
00644 {
00645         struct ieee80211_local *local = sdata->local;
00646         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00647         struct ieee802_11_elems elems;
00648         struct ieee80211_channel *channel;
00649         size_t baselen;
00650         int freq;
00651         enum ieee80211_band band = rx_status->band;
00652 
00653         /* ignore ProbeResp to foreign address */
00654         if (stype == IEEE80211_STYPE_PROBE_RESP &&
00655             !ether_addr_equal(mgmt->da, sdata->vif.addr))
00656                 return;
00657 
00658         baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
00659         if (baselen > len)
00660                 return;
00661 
00662         ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
00663                                &elems);
00664 
00665         /* ignore beacons from secure mesh peers if our security is off */
00666         if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE)
00667                 return;
00668 
00669         if (elems.ds_params && elems.ds_params_len == 1)
00670                 freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
00671         else
00672                 freq = rx_status->freq;
00673 
00674         channel = ieee80211_get_channel(local->hw.wiphy, freq);
00675 
00676         if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
00677                 return;
00678 
00679         if (elems.mesh_id && elems.mesh_config &&
00680             mesh_matches_local(sdata, &elems))
00681                 mesh_neighbour_update(sdata, mgmt->sa, &elems);
00682 
00683         if (ifmsh->sync_ops)
00684                 ifmsh->sync_ops->rx_bcn_presp(sdata,
00685                         stype, mgmt, &elems, rx_status);
00686 }
00687 
00688 static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
00689                                           struct ieee80211_mgmt *mgmt,
00690                                           size_t len,
00691                                           struct ieee80211_rx_status *rx_status)
00692 {
00693         switch (mgmt->u.action.category) {
00694         case WLAN_CATEGORY_SELF_PROTECTED:
00695                 switch (mgmt->u.action.u.self_prot.action_code) {
00696                 case WLAN_SP_MESH_PEERING_OPEN:
00697                 case WLAN_SP_MESH_PEERING_CLOSE:
00698                 case WLAN_SP_MESH_PEERING_CONFIRM:
00699                         mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
00700                         break;
00701                 }
00702                 break;
00703         case WLAN_CATEGORY_MESH_ACTION:
00704                 if (mesh_action_is_path_sel(mgmt))
00705                         mesh_rx_path_sel_frame(sdata, mgmt, len);
00706                 break;
00707         }
00708 }
00709 
00710 void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
00711                                    struct sk_buff *skb)
00712 {
00713         struct ieee80211_rx_status *rx_status;
00714         struct ieee80211_mgmt *mgmt;
00715         u16 stype;
00716 
00717         rx_status = IEEE80211_SKB_RXCB(skb);
00718         mgmt = (struct ieee80211_mgmt *) skb->data;
00719         stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
00720 
00721         switch (stype) {
00722         case IEEE80211_STYPE_PROBE_RESP:
00723         case IEEE80211_STYPE_BEACON:
00724                 ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
00725                                             rx_status);
00726                 break;
00727         case IEEE80211_STYPE_ACTION:
00728                 ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
00729                 break;
00730         }
00731 }
00732 
00733 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
00734 {
00735         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00736 
00737         if (ifmsh->preq_queue_len &&
00738             time_after(jiffies,
00739                        ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
00740                 mesh_path_start_discovery(sdata);
00741 
00742         if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
00743                 mesh_mpath_table_grow();
00744 
00745         if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
00746                 mesh_mpp_table_grow();
00747 
00748         if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
00749                 ieee80211_mesh_housekeeping(sdata, ifmsh);
00750 
00751         if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags))
00752                 ieee80211_mesh_rootpath(sdata);
00753 
00754         if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
00755                 mesh_sync_adjust_tbtt(sdata);
00756 }
00757 
00758 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
00759 {
00760         struct ieee80211_sub_if_data *sdata;
00761 
00762         rcu_read_lock();
00763         list_for_each_entry_rcu(sdata, &local->interfaces, list)
00764                 if (ieee80211_vif_is_mesh(&sdata->vif))
00765                         ieee80211_queue_work(&local->hw, &sdata->work);
00766         rcu_read_unlock();
00767 }
00768 
00769 void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
00770 {
00771         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00772 
00773         setup_timer(&ifmsh->housekeeping_timer,
00774                     ieee80211_mesh_housekeeping_timer,
00775                     (unsigned long) sdata);
00776 
00777         ifmsh->accepting_plinks = true;
00778         ifmsh->preq_id = 0;
00779         ifmsh->sn = 0;
00780         ifmsh->num_gates = 0;
00781         atomic_set(&ifmsh->mpaths, 0);
00782         mesh_rmc_init(sdata);
00783         ifmsh->last_preq = jiffies;
00784         ifmsh->next_perr = jiffies;
00785         /* Allocate all mesh structures when creating the first mesh interface. */
00786         if (!mesh_allocated)
00787                 ieee80211s_init();
00788         setup_timer(&ifmsh->mesh_path_timer,
00789                     ieee80211_mesh_path_timer,
00790                     (unsigned long) sdata);
00791         setup_timer(&ifmsh->mesh_path_root_timer,
00792                     ieee80211_mesh_path_root_timer,
00793                     (unsigned long) sdata);
00794         INIT_LIST_HEAD(&ifmsh->preq_queue.list);
00795         spin_lock_init(&ifmsh->mesh_preq_queue_lock);
00796         spin_lock_init(&ifmsh->sync_offset_lock);
00797 }


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Fri Jan 3 2014 12:07:55