mesh_hwmp.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, 2009 open80211s Ltd.
00003  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  */
00009 
00010 #include <linux/slab.h>
00011 #include <linux/etherdevice.h>
00012 #include <asm/unaligned.h>
00013 #include "wme.h"
00014 #include "mesh.h"
00015 
00016 #ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
00017 #define mhwmp_dbg(fmt, args...) \
00018         printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
00019 #else
00020 #define mhwmp_dbg(fmt, args...)   do { (void)(0); } while (0)
00021 #endif
00022 
00023 #define TEST_FRAME_LEN  8192
00024 #define MAX_METRIC      0xffffffff
00025 #define ARITH_SHIFT     8
00026 
00027 /* Number of frames buffered per destination for unresolved destinations */
00028 #define MESH_FRAME_QUEUE_LEN    10
00029 #define MAX_PREQ_QUEUE_LEN      64
00030 
00031 /* Destination only */
00032 #define MP_F_DO 0x1
00033 /* Reply and forward */
00034 #define MP_F_RF 0x2
00035 /* Unknown Sequence Number */
00036 #define MP_F_USN    0x01
00037 /* Reason code Present */
00038 #define MP_F_RCODE  0x02
00039 
00040 static void mesh_queue_preq(struct mesh_path *, u8);
00041 
00042 static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
00043 {
00044         if (ae)
00045                 offset += 6;
00046         return get_unaligned_le32(preq_elem + offset);
00047 }
00048 
00049 static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae)
00050 {
00051         if (ae)
00052                 offset += 6;
00053         return get_unaligned_le16(preq_elem + offset);
00054 }
00055 
00056 /* HWMP IE processing macros */
00057 #define AE_F                    (1<<6)
00058 #define AE_F_SET(x)             (*x & AE_F)
00059 #define PREQ_IE_FLAGS(x)        (*(x))
00060 #define PREQ_IE_HOPCOUNT(x)     (*(x + 1))
00061 #define PREQ_IE_TTL(x)          (*(x + 2))
00062 #define PREQ_IE_PREQ_ID(x)      u32_field_get(x, 3, 0)
00063 #define PREQ_IE_ORIG_ADDR(x)    (x + 7)
00064 #define PREQ_IE_ORIG_SN(x)      u32_field_get(x, 13, 0)
00065 #define PREQ_IE_LIFETIME(x)     u32_field_get(x, 17, AE_F_SET(x))
00066 #define PREQ_IE_METRIC(x)       u32_field_get(x, 21, AE_F_SET(x))
00067 #define PREQ_IE_TARGET_F(x)     (*(AE_F_SET(x) ? x + 32 : x + 26))
00068 #define PREQ_IE_TARGET_ADDR(x)  (AE_F_SET(x) ? x + 33 : x + 27)
00069 #define PREQ_IE_TARGET_SN(x)    u32_field_get(x, 33, AE_F_SET(x))
00070 
00071 
00072 #define PREP_IE_FLAGS(x)        PREQ_IE_FLAGS(x)
00073 #define PREP_IE_HOPCOUNT(x)     PREQ_IE_HOPCOUNT(x)
00074 #define PREP_IE_TTL(x)          PREQ_IE_TTL(x)
00075 #define PREP_IE_ORIG_ADDR(x)    (AE_F_SET(x) ? x + 27 : x + 21)
00076 #define PREP_IE_ORIG_SN(x)      u32_field_get(x, 27, AE_F_SET(x))
00077 #define PREP_IE_LIFETIME(x)     u32_field_get(x, 13, AE_F_SET(x))
00078 #define PREP_IE_METRIC(x)       u32_field_get(x, 17, AE_F_SET(x))
00079 #define PREP_IE_TARGET_ADDR(x)  (x + 3)
00080 #define PREP_IE_TARGET_SN(x)    u32_field_get(x, 9, 0)
00081 
00082 #define PERR_IE_TTL(x)          (*(x))
00083 #define PERR_IE_TARGET_FLAGS(x) (*(x + 2))
00084 #define PERR_IE_TARGET_ADDR(x)  (x + 3)
00085 #define PERR_IE_TARGET_SN(x)    u32_field_get(x, 9, 0)
00086 #define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0)
00087 
00088 #define MSEC_TO_TU(x) (x*1000/1024)
00089 #define SN_GT(x, y) ((s32)(y - x) < 0)
00090 #define SN_LT(x, y) ((s32)(x - y) < 0)
00091 
00092 #define net_traversal_jiffies(s) \
00093         msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
00094 #define default_lifetime(s) \
00095         MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout)
00096 #define min_preq_int_jiff(s) \
00097         (msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval))
00098 #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries)
00099 #define disc_timeout_jiff(s) \
00100         msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout)
00101 
00102 enum mpath_frame_type {
00103         MPATH_PREQ = 0,
00104         MPATH_PREP,
00105         MPATH_PERR,
00106         MPATH_RANN
00107 };
00108 
00109 static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
00110 
00111 static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
00112                 u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
00113                 __le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
00114                 __le32 lifetime, __le32 metric, __le32 preq_id,
00115                 struct ieee80211_sub_if_data *sdata)
00116 {
00117         struct ieee80211_local *local = sdata->local;
00118         struct sk_buff *skb;
00119         struct ieee80211_mgmt *mgmt;
00120         u8 *pos, ie_len;
00121         int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
00122                       sizeof(mgmt->u.action.u.mesh_action);
00123 
00124         skb = dev_alloc_skb(local->tx_headroom +
00125                             hdr_len +
00126                             2 + 37); /* max HWMP IE */
00127         if (!skb)
00128                 return -1;
00129         skb_reserve(skb, local->tx_headroom);
00130         mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
00131         memset(mgmt, 0, hdr_len);
00132         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
00133                                           IEEE80211_STYPE_ACTION);
00134 
00135         memcpy(mgmt->da, da, ETH_ALEN);
00136         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
00137         /* BSSID == SA */
00138         memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
00139         mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
00140         mgmt->u.action.u.mesh_action.action_code =
00141                                         WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
00142 
00143         switch (action) {
00144         case MPATH_PREQ:
00145                 mhwmp_dbg("sending PREQ to %pM", target);
00146                 ie_len = 37;
00147                 pos = skb_put(skb, 2 + ie_len);
00148                 *pos++ = WLAN_EID_PREQ;
00149                 break;
00150         case MPATH_PREP:
00151                 mhwmp_dbg("sending PREP to %pM", target);
00152                 ie_len = 31;
00153                 pos = skb_put(skb, 2 + ie_len);
00154                 *pos++ = WLAN_EID_PREP;
00155                 break;
00156         case MPATH_RANN:
00157                 mhwmp_dbg("sending RANN from %pM", orig_addr);
00158                 ie_len = sizeof(struct ieee80211_rann_ie);
00159                 pos = skb_put(skb, 2 + ie_len);
00160                 *pos++ = WLAN_EID_RANN;
00161                 break;
00162         default:
00163                 kfree_skb(skb);
00164                 return -ENOTSUPP;
00165                 break;
00166         }
00167         *pos++ = ie_len;
00168         *pos++ = flags;
00169         *pos++ = hop_count;
00170         *pos++ = ttl;
00171         if (action == MPATH_PREP) {
00172                 memcpy(pos, target, ETH_ALEN);
00173                 pos += ETH_ALEN;
00174                 memcpy(pos, &target_sn, 4);
00175                 pos += 4;
00176         } else {
00177                 if (action == MPATH_PREQ) {
00178                         memcpy(pos, &preq_id, 4);
00179                         pos += 4;
00180                 }
00181                 memcpy(pos, orig_addr, ETH_ALEN);
00182                 pos += ETH_ALEN;
00183                 memcpy(pos, &orig_sn, 4);
00184                 pos += 4;
00185         }
00186         memcpy(pos, &lifetime, 4);      /* interval for RANN */
00187         pos += 4;
00188         memcpy(pos, &metric, 4);
00189         pos += 4;
00190         if (action == MPATH_PREQ) {
00191                 *pos++ = 1; /* destination count */
00192                 *pos++ = target_flags;
00193                 memcpy(pos, target, ETH_ALEN);
00194                 pos += ETH_ALEN;
00195                 memcpy(pos, &target_sn, 4);
00196                 pos += 4;
00197         } else if (action == MPATH_PREP) {
00198                 memcpy(pos, orig_addr, ETH_ALEN);
00199                 pos += ETH_ALEN;
00200                 memcpy(pos, &orig_sn, 4);
00201                 pos += 4;
00202         }
00203 
00204         ieee80211_tx_skb(sdata, skb);
00205         return 0;
00206 }
00207 
00208 
00209 /*  Headroom is not adjusted.  Caller should ensure that skb has sufficient
00210  *  headroom in case the frame is encrypted. */
00211 static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
00212                 struct sk_buff *skb)
00213 {
00214         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
00215 
00216         skb_set_mac_header(skb, 0);
00217         skb_set_network_header(skb, 0);
00218         skb_set_transport_header(skb, 0);
00219 
00220         /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
00221         skb_set_queue_mapping(skb, IEEE80211_AC_VO);
00222         skb->priority = 7;
00223 
00224         info->control.vif = &sdata->vif;
00225         ieee80211_set_qos_hdr(sdata, skb);
00226 }
00227 
00240 int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
00241                        __le16 target_rcode, const u8 *ra,
00242                        struct ieee80211_sub_if_data *sdata)
00243 {
00244         struct ieee80211_local *local = sdata->local;
00245         struct sk_buff *skb;
00246         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00247         struct ieee80211_mgmt *mgmt;
00248         u8 *pos, ie_len;
00249         int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
00250                       sizeof(mgmt->u.action.u.mesh_action);
00251 
00252         if (time_before(jiffies, ifmsh->next_perr))
00253                 return -EAGAIN;
00254 
00255         skb = dev_alloc_skb(local->tx_headroom +
00256                             hdr_len +
00257                             2 + 15 /* PERR IE */);
00258         if (!skb)
00259                 return -1;
00260         skb_reserve(skb, local->tx_headroom);
00261         mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
00262         memset(mgmt, 0, hdr_len);
00263         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
00264                                           IEEE80211_STYPE_ACTION);
00265 
00266         memcpy(mgmt->da, ra, ETH_ALEN);
00267         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
00268         /* BSSID == SA */
00269         memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
00270         mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
00271         mgmt->u.action.u.mesh_action.action_code =
00272                                         WLAN_MESH_ACTION_HWMP_PATH_SELECTION;
00273         ie_len = 15;
00274         pos = skb_put(skb, 2 + ie_len);
00275         *pos++ = WLAN_EID_PERR;
00276         *pos++ = ie_len;
00277         /* ttl */
00278         *pos++ = ttl;
00279         /* number of destinations */
00280         *pos++ = 1;
00281         /*
00282          * flags bit, bit 1 is unset if we know the sequence number and
00283          * bit 2 is set if we have a reason code
00284          */
00285         *pos = 0;
00286         if (!target_sn)
00287                 *pos |= MP_F_USN;
00288         if (target_rcode)
00289                 *pos |= MP_F_RCODE;
00290         pos++;
00291         memcpy(pos, target, ETH_ALEN);
00292         pos += ETH_ALEN;
00293         memcpy(pos, &target_sn, 4);
00294         pos += 4;
00295         memcpy(pos, &target_rcode, 2);
00296 
00297         /* see note in function header */
00298         prepare_frame_for_deferred_tx(sdata, skb);
00299         ifmsh->next_perr = TU_TO_EXP_TIME(
00300                                    ifmsh->mshcfg.dot11MeshHWMPperrMinInterval);
00301         ieee80211_add_pending_skb(local, skb);
00302         return 0;
00303 }
00304 
00305 void ieee80211s_update_metric(struct ieee80211_local *local,
00306                 struct sta_info *stainfo, struct sk_buff *skb)
00307 {
00308         struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
00309         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
00310         int failed;
00311 
00312         if (!ieee80211_is_data(hdr->frame_control))
00313                 return;
00314 
00315         failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);
00316 
00317         /* moving average, scaled to 100 */
00318         stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed);
00319         if (stainfo->fail_avg > 95)
00320                 mesh_plink_broken(stainfo);
00321 }
00322 
00323 static u32 airtime_link_metric_get(struct ieee80211_local *local,
00324                                    struct sta_info *sta)
00325 {
00326         struct ieee80211_supported_band *sband;
00327         struct rate_info rinfo;
00328         /* This should be adjusted for each device */
00329         int device_constant = 1 << ARITH_SHIFT;
00330         int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT;
00331         int s_unit = 1 << ARITH_SHIFT;
00332         int rate, err;
00333         u32 tx_time, estimated_retx;
00334         u64 result;
00335 
00336         sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
00337 
00338         if (sta->fail_avg >= 100)
00339                 return MAX_METRIC;
00340 
00341         sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo);
00342         rate = cfg80211_calculate_bitrate(&rinfo);
00343         if (WARN_ON(!rate))
00344                 return MAX_METRIC;
00345 
00346         err = (sta->fail_avg << ARITH_SHIFT) / 100;
00347 
00348         /* bitrate is in units of 100 Kbps, while we need rate in units of
00349          * 1Mbps. This will be corrected on tx_time computation.
00350          */
00351         tx_time = (device_constant + 10 * test_frame_len / rate);
00352         estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
00353         result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
00354         return (u32)result;
00355 }
00356 
00373 static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
00374                             struct ieee80211_mgmt *mgmt,
00375                             u8 *hwmp_ie, enum mpath_frame_type action)
00376 {
00377         struct ieee80211_local *local = sdata->local;
00378         struct mesh_path *mpath;
00379         struct sta_info *sta;
00380         bool fresh_info;
00381         u8 *orig_addr, *ta;
00382         u32 orig_sn, orig_metric;
00383         unsigned long orig_lifetime, exp_time;
00384         u32 last_hop_metric, new_metric;
00385         bool process = true;
00386 
00387         rcu_read_lock();
00388         sta = sta_info_get(sdata, mgmt->sa);
00389         if (!sta) {
00390                 rcu_read_unlock();
00391                 return 0;
00392         }
00393 
00394         last_hop_metric = airtime_link_metric_get(local, sta);
00395         /* Update and check originator routing info */
00396         fresh_info = true;
00397 
00398         switch (action) {
00399         case MPATH_PREQ:
00400                 orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie);
00401                 orig_sn = PREQ_IE_ORIG_SN(hwmp_ie);
00402                 orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
00403                 orig_metric = PREQ_IE_METRIC(hwmp_ie);
00404                 break;
00405         case MPATH_PREP:
00406                 /* Originator here refers to the MP that was the target in the
00407                  * Path Request. We divert from the nomenclature in the draft
00408                  * so that we can easily use a single function to gather path
00409                  * information from both PREQ and PREP frames.
00410                  */
00411                 orig_addr = PREP_IE_TARGET_ADDR(hwmp_ie);
00412                 orig_sn = PREP_IE_TARGET_SN(hwmp_ie);
00413                 orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
00414                 orig_metric = PREP_IE_METRIC(hwmp_ie);
00415                 break;
00416         default:
00417                 rcu_read_unlock();
00418                 return 0;
00419         }
00420         new_metric = orig_metric + last_hop_metric;
00421         if (new_metric < orig_metric)
00422                 new_metric = MAX_METRIC;
00423         exp_time = TU_TO_EXP_TIME(orig_lifetime);
00424 
00425         if (ether_addr_equal(orig_addr, sdata->vif.addr)) {
00426                 /* This MP is the originator, we are not interested in this
00427                  * frame, except for updating transmitter's path info.
00428                  */
00429                 process = false;
00430                 fresh_info = false;
00431         } else {
00432                 mpath = mesh_path_lookup(orig_addr, sdata);
00433                 if (mpath) {
00434                         spin_lock_bh(&mpath->state_lock);
00435                         if (mpath->flags & MESH_PATH_FIXED)
00436                                 fresh_info = false;
00437                         else if ((mpath->flags & MESH_PATH_ACTIVE) &&
00438                             (mpath->flags & MESH_PATH_SN_VALID)) {
00439                                 if (SN_GT(mpath->sn, orig_sn) ||
00440                                     (mpath->sn == orig_sn &&
00441                                      new_metric >= mpath->metric)) {
00442                                         process = false;
00443                                         fresh_info = false;
00444                                 }
00445                         }
00446                 } else {
00447                         mesh_path_add(orig_addr, sdata);
00448                         mpath = mesh_path_lookup(orig_addr, sdata);
00449                         if (!mpath) {
00450                                 rcu_read_unlock();
00451                                 return 0;
00452                         }
00453                         spin_lock_bh(&mpath->state_lock);
00454                 }
00455 
00456                 if (fresh_info) {
00457                         mesh_path_assign_nexthop(mpath, sta);
00458                         mpath->flags |= MESH_PATH_SN_VALID;
00459                         mpath->metric = new_metric;
00460                         mpath->sn = orig_sn;
00461                         mpath->exp_time = time_after(mpath->exp_time, exp_time)
00462                                           ?  mpath->exp_time : exp_time;
00463                         mesh_path_activate(mpath);
00464                         spin_unlock_bh(&mpath->state_lock);
00465                         mesh_path_tx_pending(mpath);
00466                         /* draft says preq_id should be saved to, but there does
00467                          * not seem to be any use for it, skipping by now
00468                          */
00469                 } else
00470                         spin_unlock_bh(&mpath->state_lock);
00471         }
00472 
00473         /* Update and check transmitter routing info */
00474         ta = mgmt->sa;
00475         if (ether_addr_equal(orig_addr, ta))
00476                 fresh_info = false;
00477         else {
00478                 fresh_info = true;
00479 
00480                 mpath = mesh_path_lookup(ta, sdata);
00481                 if (mpath) {
00482                         spin_lock_bh(&mpath->state_lock);
00483                         if ((mpath->flags & MESH_PATH_FIXED) ||
00484                                 ((mpath->flags & MESH_PATH_ACTIVE) &&
00485                                         (last_hop_metric > mpath->metric)))
00486                                 fresh_info = false;
00487                 } else {
00488                         mesh_path_add(ta, sdata);
00489                         mpath = mesh_path_lookup(ta, sdata);
00490                         if (!mpath) {
00491                                 rcu_read_unlock();
00492                                 return 0;
00493                         }
00494                         spin_lock_bh(&mpath->state_lock);
00495                 }
00496 
00497                 if (fresh_info) {
00498                         mesh_path_assign_nexthop(mpath, sta);
00499                         mpath->metric = last_hop_metric;
00500                         mpath->exp_time = time_after(mpath->exp_time, exp_time)
00501                                           ?  mpath->exp_time : exp_time;
00502                         mesh_path_activate(mpath);
00503                         spin_unlock_bh(&mpath->state_lock);
00504                         mesh_path_tx_pending(mpath);
00505                 } else
00506                         spin_unlock_bh(&mpath->state_lock);
00507         }
00508 
00509         rcu_read_unlock();
00510 
00511         return process ? new_metric : 0;
00512 }
00513 
00514 static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
00515                                     struct ieee80211_mgmt *mgmt,
00516                                     u8 *preq_elem, u32 metric)
00517 {
00518         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00519         struct mesh_path *mpath = NULL;
00520         u8 *target_addr, *orig_addr;
00521         const u8 *da;
00522         u8 target_flags, ttl;
00523         u32 orig_sn, target_sn, lifetime;
00524         bool reply = false;
00525         bool forward = true;
00526 
00527         /* Update target SN, if present */
00528         target_addr = PREQ_IE_TARGET_ADDR(preq_elem);
00529         orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
00530         target_sn = PREQ_IE_TARGET_SN(preq_elem);
00531         orig_sn = PREQ_IE_ORIG_SN(preq_elem);
00532         target_flags = PREQ_IE_TARGET_F(preq_elem);
00533 
00534         mhwmp_dbg("received PREQ from %pM", orig_addr);
00535 
00536         if (ether_addr_equal(target_addr, sdata->vif.addr)) {
00537                 mhwmp_dbg("PREQ is for us");
00538                 forward = false;
00539                 reply = true;
00540                 metric = 0;
00541                 if (time_after(jiffies, ifmsh->last_sn_update +
00542                                         net_traversal_jiffies(sdata)) ||
00543                     time_before(jiffies, ifmsh->last_sn_update)) {
00544                         target_sn = ++ifmsh->sn;
00545                         ifmsh->last_sn_update = jiffies;
00546                 }
00547         } else {
00548                 rcu_read_lock();
00549                 mpath = mesh_path_lookup(target_addr, sdata);
00550                 if (mpath) {
00551                         if ((!(mpath->flags & MESH_PATH_SN_VALID)) ||
00552                                         SN_LT(mpath->sn, target_sn)) {
00553                                 mpath->sn = target_sn;
00554                                 mpath->flags |= MESH_PATH_SN_VALID;
00555                         } else if ((!(target_flags & MP_F_DO)) &&
00556                                         (mpath->flags & MESH_PATH_ACTIVE)) {
00557                                 reply = true;
00558                                 metric = mpath->metric;
00559                                 target_sn = mpath->sn;
00560                                 if (target_flags & MP_F_RF)
00561                                         target_flags |= MP_F_DO;
00562                                 else
00563                                         forward = false;
00564                         }
00565                 }
00566                 rcu_read_unlock();
00567         }
00568 
00569         if (reply) {
00570                 lifetime = PREQ_IE_LIFETIME(preq_elem);
00571                 ttl = ifmsh->mshcfg.element_ttl;
00572                 if (ttl != 0) {
00573                         mhwmp_dbg("replying to the PREQ");
00574                         mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
00575                                 cpu_to_le32(orig_sn), 0, target_addr,
00576                                 cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
00577                                 cpu_to_le32(lifetime), cpu_to_le32(metric),
00578                                 0, sdata);
00579                 } else
00580                         ifmsh->mshstats.dropped_frames_ttl++;
00581         }
00582 
00583         if (forward && ifmsh->mshcfg.dot11MeshForwarding) {
00584                 u32 preq_id;
00585                 u8 hopcount, flags;
00586 
00587                 ttl = PREQ_IE_TTL(preq_elem);
00588                 lifetime = PREQ_IE_LIFETIME(preq_elem);
00589                 if (ttl <= 1) {
00590                         ifmsh->mshstats.dropped_frames_ttl++;
00591                         return;
00592                 }
00593                 mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
00594                 --ttl;
00595                 flags = PREQ_IE_FLAGS(preq_elem);
00596                 preq_id = PREQ_IE_PREQ_ID(preq_elem);
00597                 hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
00598                 da = (mpath && mpath->is_root) ?
00599                         mpath->rann_snd_addr : broadcast_addr;
00600                 mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
00601                                 cpu_to_le32(orig_sn), target_flags, target_addr,
00602                                 cpu_to_le32(target_sn), da,
00603                                 hopcount, ttl, cpu_to_le32(lifetime),
00604                                 cpu_to_le32(metric), cpu_to_le32(preq_id),
00605                                 sdata);
00606                 if (!is_multicast_ether_addr(da))
00607                         ifmsh->mshstats.fwded_unicast++;
00608                 else
00609                         ifmsh->mshstats.fwded_mcast++;
00610                 ifmsh->mshstats.fwded_frames++;
00611         }
00612 }
00613 
00614 
00615 static inline struct sta_info *
00616 next_hop_deref_protected(struct mesh_path *mpath)
00617 {
00618         return rcu_dereference_protected(mpath->next_hop,
00619                                          lockdep_is_held(&mpath->state_lock));
00620 }
00621 
00622 
00623 static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
00624                                     struct ieee80211_mgmt *mgmt,
00625                                     u8 *prep_elem, u32 metric)
00626 {
00627         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00628         struct mesh_path *mpath;
00629         u8 *target_addr, *orig_addr;
00630         u8 ttl, hopcount, flags;
00631         u8 next_hop[ETH_ALEN];
00632         u32 target_sn, orig_sn, lifetime;
00633 
00634         mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
00635 
00636         orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
00637         if (ether_addr_equal(orig_addr, sdata->vif.addr))
00638                 /* destination, no forwarding required */
00639                 return;
00640 
00641         if (!ifmsh->mshcfg.dot11MeshForwarding)
00642                 return;
00643 
00644         ttl = PREP_IE_TTL(prep_elem);
00645         if (ttl <= 1) {
00646                 sdata->u.mesh.mshstats.dropped_frames_ttl++;
00647                 return;
00648         }
00649 
00650         rcu_read_lock();
00651         mpath = mesh_path_lookup(orig_addr, sdata);
00652         if (mpath)
00653                 spin_lock_bh(&mpath->state_lock);
00654         else
00655                 goto fail;
00656         if (!(mpath->flags & MESH_PATH_ACTIVE)) {
00657                 spin_unlock_bh(&mpath->state_lock);
00658                 goto fail;
00659         }
00660         memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN);
00661         spin_unlock_bh(&mpath->state_lock);
00662         --ttl;
00663         flags = PREP_IE_FLAGS(prep_elem);
00664         lifetime = PREP_IE_LIFETIME(prep_elem);
00665         hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1;
00666         target_addr = PREP_IE_TARGET_ADDR(prep_elem);
00667         target_sn = PREP_IE_TARGET_SN(prep_elem);
00668         orig_sn = PREP_IE_ORIG_SN(prep_elem);
00669 
00670         mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
00671                 cpu_to_le32(orig_sn), 0, target_addr,
00672                 cpu_to_le32(target_sn), next_hop, hopcount,
00673                 ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
00674                 0, sdata);
00675         rcu_read_unlock();
00676 
00677         sdata->u.mesh.mshstats.fwded_unicast++;
00678         sdata->u.mesh.mshstats.fwded_frames++;
00679         return;
00680 
00681 fail:
00682         rcu_read_unlock();
00683         sdata->u.mesh.mshstats.dropped_frames_no_route++;
00684 }
00685 
00686 static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
00687                              struct ieee80211_mgmt *mgmt, u8 *perr_elem)
00688 {
00689         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00690         struct mesh_path *mpath;
00691         u8 ttl;
00692         u8 *ta, *target_addr;
00693         u32 target_sn;
00694         u16 target_rcode;
00695 
00696         ta = mgmt->sa;
00697         ttl = PERR_IE_TTL(perr_elem);
00698         if (ttl <= 1) {
00699                 ifmsh->mshstats.dropped_frames_ttl++;
00700                 return;
00701         }
00702         ttl--;
00703         target_addr = PERR_IE_TARGET_ADDR(perr_elem);
00704         target_sn = PERR_IE_TARGET_SN(perr_elem);
00705         target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
00706 
00707         rcu_read_lock();
00708         mpath = mesh_path_lookup(target_addr, sdata);
00709         if (mpath) {
00710                 struct sta_info *sta;
00711 
00712                 spin_lock_bh(&mpath->state_lock);
00713                 sta = next_hop_deref_protected(mpath);
00714                 if (mpath->flags & MESH_PATH_ACTIVE &&
00715                     ether_addr_equal(ta, sta->sta.addr) &&
00716                     (!(mpath->flags & MESH_PATH_SN_VALID) ||
00717                     SN_GT(target_sn, mpath->sn))) {
00718                         mpath->flags &= ~MESH_PATH_ACTIVE;
00719                         mpath->sn = target_sn;
00720                         spin_unlock_bh(&mpath->state_lock);
00721                         if (!ifmsh->mshcfg.dot11MeshForwarding)
00722                                 goto endperr;
00723                         mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
00724                                            cpu_to_le16(target_rcode),
00725                                            broadcast_addr, sdata);
00726                 } else
00727                         spin_unlock_bh(&mpath->state_lock);
00728         }
00729 endperr:
00730         rcu_read_unlock();
00731 }
00732 
00733 static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
00734                                 struct ieee80211_mgmt *mgmt,
00735                                 struct ieee80211_rann_ie *rann)
00736 {
00737         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00738         struct ieee80211_local *local = sdata->local;
00739         struct sta_info *sta;
00740         struct mesh_path *mpath;
00741         u8 ttl, flags, hopcount;
00742         u8 *orig_addr;
00743         u32 orig_sn, metric, metric_txsta, interval;
00744         bool root_is_gate;
00745 
00746         ttl = rann->rann_ttl;
00747         if (ttl <= 1) {
00748                 ifmsh->mshstats.dropped_frames_ttl++;
00749                 return;
00750         }
00751         ttl--;
00752         flags = rann->rann_flags;
00753         root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
00754         orig_addr = rann->rann_addr;
00755         orig_sn = le32_to_cpu(rann->rann_seq);
00756         interval = le32_to_cpu(rann->rann_interval);
00757         hopcount = rann->rann_hopcount;
00758         hopcount++;
00759         metric = le32_to_cpu(rann->rann_metric);
00760 
00761         /*  Ignore our own RANNs */
00762         if (ether_addr_equal(orig_addr, sdata->vif.addr))
00763                 return;
00764 
00765         mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)",
00766                         orig_addr, mgmt->sa, root_is_gate);
00767 
00768         rcu_read_lock();
00769         sta = sta_info_get(sdata, mgmt->sa);
00770         if (!sta) {
00771                 rcu_read_unlock();
00772                 return;
00773         }
00774 
00775         metric_txsta = airtime_link_metric_get(local, sta);
00776 
00777         mpath = mesh_path_lookup(orig_addr, sdata);
00778         if (!mpath) {
00779                 mesh_path_add(orig_addr, sdata);
00780                 mpath = mesh_path_lookup(orig_addr, sdata);
00781                 if (!mpath) {
00782                         rcu_read_unlock();
00783                         sdata->u.mesh.mshstats.dropped_frames_no_route++;
00784                         return;
00785                 }
00786         }
00787 
00788         if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
00789              time_after(jiffies, mpath->exp_time - 1*HZ)) &&
00790              !(mpath->flags & MESH_PATH_FIXED)) {
00791                 mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
00792                                                                orig_addr);
00793                 mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
00794         }
00795 
00796         if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn &&
00797            metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) {
00798                 mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
00799                                        cpu_to_le32(orig_sn),
00800                                        0, NULL, 0, broadcast_addr,
00801                                        hopcount, ttl, cpu_to_le32(interval),
00802                                        cpu_to_le32(metric + metric_txsta),
00803                                        0, sdata);
00804                 mpath->sn = orig_sn;
00805                 mpath->rann_metric = metric + metric_txsta;
00806                 /* Recording RANNs sender address to send individually
00807                  * addressed PREQs destined for root mesh STA */
00808                 memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN);
00809         }
00810 
00811         mpath->is_root = true;
00812 
00813         if (root_is_gate)
00814                 mesh_path_add_gate(mpath);
00815 
00816         rcu_read_unlock();
00817 }
00818 
00819 
00820 void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
00821                             struct ieee80211_mgmt *mgmt,
00822                             size_t len)
00823 {
00824         struct ieee802_11_elems elems;
00825         size_t baselen;
00826         u32 last_hop_metric;
00827         struct sta_info *sta;
00828 
00829         /* need action_code */
00830         if (len < IEEE80211_MIN_ACTION_SIZE + 1)
00831                 return;
00832 
00833         rcu_read_lock();
00834         sta = sta_info_get(sdata, mgmt->sa);
00835         if (!sta || sta->plink_state != NL80211_PLINK_ESTAB) {
00836                 rcu_read_unlock();
00837                 return;
00838         }
00839         rcu_read_unlock();
00840 
00841         baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
00842         ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
00843                         len - baselen, &elems);
00844 
00845         if (elems.preq) {
00846                 if (elems.preq_len != 37)
00847                         /* Right now we support just 1 destination and no AE */
00848                         return;
00849                 last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
00850                                                       MPATH_PREQ);
00851                 if (last_hop_metric)
00852                         hwmp_preq_frame_process(sdata, mgmt, elems.preq,
00853                                                 last_hop_metric);
00854         }
00855         if (elems.prep) {
00856                 if (elems.prep_len != 31)
00857                         /* Right now we support no AE */
00858                         return;
00859                 last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
00860                                                       MPATH_PREP);
00861                 if (last_hop_metric)
00862                         hwmp_prep_frame_process(sdata, mgmt, elems.prep,
00863                                                 last_hop_metric);
00864         }
00865         if (elems.perr) {
00866                 if (elems.perr_len != 15)
00867                         /* Right now we support only one destination per PERR */
00868                         return;
00869                 hwmp_perr_frame_process(sdata, mgmt, elems.perr);
00870         }
00871         if (elems.rann)
00872                 hwmp_rann_frame_process(sdata, mgmt, elems.rann);
00873 }
00874 
00884 static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
00885 {
00886         struct ieee80211_sub_if_data *sdata = mpath->sdata;
00887         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00888         struct mesh_preq_queue *preq_node;
00889 
00890         preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
00891         if (!preq_node) {
00892                 mhwmp_dbg("could not allocate PREQ node");
00893                 return;
00894         }
00895 
00896         spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
00897         if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
00898                 spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
00899                 kfree(preq_node);
00900                 if (printk_ratelimit())
00901                         mhwmp_dbg("PREQ node queue full");
00902                 return;
00903         }
00904 
00905         spin_lock(&mpath->state_lock);
00906         if (mpath->flags & MESH_PATH_REQ_QUEUED) {
00907                 spin_unlock(&mpath->state_lock);
00908                 spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
00909                 kfree(preq_node);
00910                 return;
00911         }
00912 
00913         memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
00914         preq_node->flags = flags;
00915 
00916         mpath->flags |= MESH_PATH_REQ_QUEUED;
00917         spin_unlock(&mpath->state_lock);
00918 
00919         list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
00920         ++ifmsh->preq_queue_len;
00921         spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
00922 
00923         if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
00924                 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
00925 
00926         else if (time_before(jiffies, ifmsh->last_preq)) {
00927                 /* avoid long wait if did not send preqs for a long time
00928                  * and jiffies wrapped around
00929                  */
00930                 ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
00931                 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
00932         } else
00933                 mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
00934                                                 min_preq_int_jiff(sdata));
00935 }
00936 
00942 void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
00943 {
00944         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00945         struct mesh_preq_queue *preq_node;
00946         struct mesh_path *mpath;
00947         u8 ttl, target_flags;
00948         const u8 *da;
00949         u32 lifetime;
00950 
00951         spin_lock_bh(&ifmsh->mesh_preq_queue_lock);
00952         if (!ifmsh->preq_queue_len ||
00953                 time_before(jiffies, ifmsh->last_preq +
00954                                 min_preq_int_jiff(sdata))) {
00955                 spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
00956                 return;
00957         }
00958 
00959         preq_node = list_first_entry(&ifmsh->preq_queue.list,
00960                         struct mesh_preq_queue, list);
00961         list_del(&preq_node->list);
00962         --ifmsh->preq_queue_len;
00963         spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
00964 
00965         rcu_read_lock();
00966         mpath = mesh_path_lookup(preq_node->dst, sdata);
00967         if (!mpath)
00968                 goto enddiscovery;
00969 
00970         spin_lock_bh(&mpath->state_lock);
00971         mpath->flags &= ~MESH_PATH_REQ_QUEUED;
00972         if (preq_node->flags & PREQ_Q_F_START) {
00973                 if (mpath->flags & MESH_PATH_RESOLVING) {
00974                         spin_unlock_bh(&mpath->state_lock);
00975                         goto enddiscovery;
00976                 } else {
00977                         mpath->flags &= ~MESH_PATH_RESOLVED;
00978                         mpath->flags |= MESH_PATH_RESOLVING;
00979                         mpath->discovery_retries = 0;
00980                         mpath->discovery_timeout = disc_timeout_jiff(sdata);
00981                 }
00982         } else if (!(mpath->flags & MESH_PATH_RESOLVING) ||
00983                         mpath->flags & MESH_PATH_RESOLVED) {
00984                 mpath->flags &= ~MESH_PATH_RESOLVING;
00985                 spin_unlock_bh(&mpath->state_lock);
00986                 goto enddiscovery;
00987         }
00988 
00989         ifmsh->last_preq = jiffies;
00990 
00991         if (time_after(jiffies, ifmsh->last_sn_update +
00992                                 net_traversal_jiffies(sdata)) ||
00993             time_before(jiffies, ifmsh->last_sn_update)) {
00994                 ++ifmsh->sn;
00995                 sdata->u.mesh.last_sn_update = jiffies;
00996         }
00997         lifetime = default_lifetime(sdata);
00998         ttl = sdata->u.mesh.mshcfg.element_ttl;
00999         if (ttl == 0) {
01000                 sdata->u.mesh.mshstats.dropped_frames_ttl++;
01001                 spin_unlock_bh(&mpath->state_lock);
01002                 goto enddiscovery;
01003         }
01004 
01005         if (preq_node->flags & PREQ_Q_F_REFRESH)
01006                 target_flags = MP_F_DO;
01007         else
01008                 target_flags = MP_F_RF;
01009 
01010         spin_unlock_bh(&mpath->state_lock);
01011         da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr;
01012         mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
01013                         cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
01014                         cpu_to_le32(mpath->sn), da, 0,
01015                         ttl, cpu_to_le32(lifetime), 0,
01016                         cpu_to_le32(ifmsh->preq_id++), sdata);
01017         mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
01018 
01019 enddiscovery:
01020         rcu_read_unlock();
01021         kfree(preq_node);
01022 }
01023 
01024 /* mesh_nexthop_resolve - lookup next hop for given skb and start path
01025  * discovery if no forwarding information is found.
01026  *
01027  * @skb: 802.11 frame to be sent
01028  * @sdata: network subif the frame will be sent through
01029  *
01030  * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
01031  * skb is freeed here if no mpath could be allocated.
01032  */
01033 int mesh_nexthop_resolve(struct sk_buff *skb,
01034                          struct ieee80211_sub_if_data *sdata)
01035 {
01036         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
01037         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
01038         struct mesh_path *mpath;
01039         struct sk_buff *skb_to_free = NULL;
01040         u8 *target_addr = hdr->addr3;
01041         int err = 0;
01042 
01043         rcu_read_lock();
01044         err = mesh_nexthop_lookup(skb, sdata);
01045         if (!err)
01046                 goto endlookup;
01047 
01048         /* no nexthop found, start resolving */
01049         mpath = mesh_path_lookup(target_addr, sdata);
01050         if (!mpath) {
01051                 mesh_path_add(target_addr, sdata);
01052                 mpath = mesh_path_lookup(target_addr, sdata);
01053                 if (!mpath) {
01054                         mesh_path_discard_frame(skb, sdata);
01055                         err = -ENOSPC;
01056                         goto endlookup;
01057                 }
01058         }
01059 
01060         if (!(mpath->flags & MESH_PATH_RESOLVING))
01061                 mesh_queue_preq(mpath, PREQ_Q_F_START);
01062 
01063         if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
01064                 skb_to_free = skb_dequeue(&mpath->frame_queue);
01065 
01066         info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
01067         ieee80211_set_qos_hdr(sdata, skb);
01068         skb_queue_tail(&mpath->frame_queue, skb);
01069         err = -ENOENT;
01070         if (skb_to_free)
01071                 mesh_path_discard_frame(skb_to_free, sdata);
01072 
01073 endlookup:
01074         rcu_read_unlock();
01075         return err;
01076 }
01087 int mesh_nexthop_lookup(struct sk_buff *skb,
01088                         struct ieee80211_sub_if_data *sdata)
01089 {
01090         struct mesh_path *mpath;
01091         struct sta_info *next_hop;
01092         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
01093         u8 *target_addr = hdr->addr3;
01094         int err = -ENOENT;
01095 
01096         rcu_read_lock();
01097         mpath = mesh_path_lookup(target_addr, sdata);
01098 
01099         if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
01100                 goto endlookup;
01101 
01102         if (time_after(jiffies,
01103                        mpath->exp_time -
01104                        msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
01105             ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
01106             !(mpath->flags & MESH_PATH_RESOLVING) &&
01107             !(mpath->flags & MESH_PATH_FIXED))
01108                 mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
01109 
01110         next_hop = rcu_dereference(mpath->next_hop);
01111         if (next_hop) {
01112                 memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
01113                 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
01114                 err = 0;
01115         }
01116 
01117 endlookup:
01118         rcu_read_unlock();
01119         return err;
01120 }
01121 
01122 void mesh_path_timer(unsigned long data)
01123 {
01124         struct mesh_path *mpath = (void *) data;
01125         struct ieee80211_sub_if_data *sdata = mpath->sdata;
01126         int ret;
01127 
01128         if (sdata->local->quiescing)
01129                 return;
01130 
01131         spin_lock_bh(&mpath->state_lock);
01132         if (mpath->flags & MESH_PATH_RESOLVED ||
01133                         (!(mpath->flags & MESH_PATH_RESOLVING))) {
01134                 mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
01135                 spin_unlock_bh(&mpath->state_lock);
01136         } else if (mpath->discovery_retries < max_preq_retries(sdata)) {
01137                 ++mpath->discovery_retries;
01138                 mpath->discovery_timeout *= 2;
01139                 mpath->flags &= ~MESH_PATH_REQ_QUEUED;
01140                 spin_unlock_bh(&mpath->state_lock);
01141                 mesh_queue_preq(mpath, 0);
01142         } else {
01143                 mpath->flags = 0;
01144                 mpath->exp_time = jiffies;
01145                 spin_unlock_bh(&mpath->state_lock);
01146                 if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
01147                         ret = mesh_path_send_to_gates(mpath);
01148                         if (ret)
01149                                 mhwmp_dbg("no gate was reachable");
01150                 } else
01151                         mesh_path_flush_pending(mpath);
01152         }
01153 }
01154 
01155 void
01156 mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
01157 {
01158         struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
01159         u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
01160         u8 flags;
01161 
01162         flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
01163                         ? RANN_FLAG_IS_GATE : 0;
01164         mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
01165                                cpu_to_le32(++ifmsh->sn),
01166                                0, NULL, 0, broadcast_addr,
01167                                0, sdata->u.mesh.mshcfg.element_ttl,
01168                                cpu_to_le32(interval), 0, 0, sdata);
01169 }


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