X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=net%2Fmac80211%2Fmesh.c;h=859ee5f3d94146a5103b5c2188847da3a302d12d;hb=83515bc7df812555e20cda48614674e2f346f9f5;hp=a49a3374acb1a37643c847fa79bd598a7a8f4f7e;hpb=3491707a070c1183c709516b2f876f798c7a9a84;p=safe%2Fjmp%2Flinux-2.6 diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a49a337..859ee5f 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 open80211s Ltd. + * Copyright (c) 2008, 2009 open80211s Ltd. * Authors: Luis Carlos Cobo * Javier Cardona * @@ -8,24 +8,21 @@ * published by the Free Software Foundation. */ +#include #include #include "ieee80211_i.h" #include "mesh.h" #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) +#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) -#define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ -#define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ -#define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */ -#define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */ -#define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */ -#define MESHCONF_CAPAB_OFFSET 6 #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 #define MESHCONF_CAPAB_FORWARDING 0x08 #define TMR_RUNNING_HK 0 #define TMR_RUNNING_MP 1 +#define TMR_RUNNING_MPR 2 int mesh_allocated; static struct kmem_cache *rm_cache; @@ -85,12 +82,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ if (ifmsh->mesh_id_len == ie->mesh_id_len && memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && - (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&& - (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&& - (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&& - (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&& - (ifmsh->mesh_auth_id == *(ie->mesh_config + - MESHCONF_AUTH_OFFSET))) + (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) && + (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) && + (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) && + (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) && + (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)) return true; return false; @@ -103,7 +99,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) { - return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) & + return (ie->mesh_config->meshconf_cap & MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; } @@ -200,8 +196,8 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, list_del(&p->list); kmem_cache_free(rm_cache, p); --entries; - } else if ((seqnum == p->seqnum) - && (memcmp(sa, p->sa, ETH_ALEN) == 0)) + } else if ((seqnum == p->seqnum) && + (memcmp(sa, p->sa, ETH_ALEN) == 0)) return -1; } @@ -223,6 +219,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) struct ieee80211_supported_band *sband; u8 *pos; int len, i, rate; + u8 neighbors; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; len = sband->n_bitrates; @@ -246,15 +243,22 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) } } + if (sband->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); + } + pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); *pos++ = WLAN_EID_MESH_ID; *pos++ = sdata->u.mesh.mesh_id_len; if (sdata->u.mesh.mesh_id_len) memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); - pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); + pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie)); *pos++ = WLAN_EID_MESH_CONFIG; - *pos++ = IEEE80211_MESH_CONFIG_LEN; + *pos++ = sizeof(struct ieee80211_meshconf_ie); /* Active path selection protocol ID */ *pos++ = sdata->u.mesh.mesh_pp_id; @@ -271,9 +275,11 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) /* Authentication Protocol identifier */ *pos++ = sdata->u.mesh.mesh_auth_id; - /* Mesh Formation Info */ - memset(pos, 0x00, 1); - pos += 1; + /* Mesh Formation Info - number of neighbors */ + neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); + /* Number of neighbor mesh STAs or 15 whichever is smaller */ + neighbors = (neighbors > 15) ? 15 : neighbors; + *pos++ = neighbors << 1; /* Mesh capability */ sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); @@ -344,6 +350,34 @@ static void ieee80211_mesh_path_timer(unsigned long data) ieee80211_queue_work(&local->hw, &ifmsh->work); } +static void ieee80211_mesh_path_root_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; + + set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); + + if (local->quiescing) { + set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); + return; + } + + ieee80211_queue_work(&local->hw, &ifmsh->work); +} + +void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) +{ + if (ifmsh->mshcfg.dot11MeshHWMPRootMode) + set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); + else { + clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); + /* stop running timer */ + del_timer_sync(&ifmsh->mesh_path_root_timer); + } +} + /** * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * @hdr: 802.11 frame header @@ -354,8 +388,9 @@ static void ieee80211_mesh_path_timer(unsigned long data) * * Return the length of the 802.11 (does not include a mesh control header) */ -int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char - *meshda, char *meshsa) { +int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, + const u8 *meshda, const u8 *meshsa) +{ if (is_multicast_ether_addr(meshda)) { *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA TA SA */ @@ -393,7 +428,7 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, char *addr5, char *addr6) { int aelen = 0; - memset(meshhdr, 0, sizeof(meshhdr)); + memset(meshhdr, 0, sizeof(*meshhdr)); meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); sdata->u.mesh.mesh_seqnum++; @@ -423,7 +458,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: running mesh housekeeping\n", - sdata->dev->name); + sdata->name); #endif ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); @@ -437,6 +472,15 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } +static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + mesh_path_tx_root_frame(sdata); + mod_timer(&ifmsh->mesh_path_root_timer, + round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); +} + #ifdef CONFIG_PM void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) { @@ -451,6 +495,8 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); if (del_timer_sync(&ifmsh->mesh_path_timer)) set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); + if (del_timer_sync(&ifmsh->mesh_path_root_timer)) + set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); } void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) @@ -461,6 +507,9 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) add_timer(&ifmsh->housekeeping_timer); if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) add_timer(&ifmsh->mesh_path_timer); + if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) + add_timer(&ifmsh->mesh_path_root_timer); + ieee80211_mesh_root_setup(ifmsh); } #endif @@ -470,6 +519,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); + ieee80211_mesh_root_setup(ifmsh); ieee80211_queue_work(&local->hw, &ifmsh->work); sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | @@ -480,6 +530,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { del_timer_sync(&sdata->u.mesh.housekeeping_timer); + del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); /* * If the timer fired while we waited for it, it will have * requeued the work. Now the work will be running again @@ -515,7 +566,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, /* ignore ProbeResp to foreign address */ if (stype == IEEE80211_STYPE_PROBE_RESP && - compare_ether_addr(mgmt->da, sdata->dev->dev_addr)) + compare_ether_addr(mgmt->da, sdata->vif.addr)) return; baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; @@ -550,7 +601,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_status *rx_status) { switch (mgmt->u.action.category) { - case PLINK_CATEGORY: + case MESH_PLINK_CATEGORY: mesh_rx_plink_frame(sdata, mgmt, len, rx_status); break; case MESH_PATH_SEL_CATEGORY: @@ -595,7 +646,7 @@ static void ieee80211_mesh_work(struct work_struct *work) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct sk_buff *skb; - if (!netif_running(sdata->dev)) + if (!ieee80211_sdata_running(sdata)) return; if (local->scanning) @@ -617,6 +668,9 @@ static void ieee80211_mesh_work(struct work_struct *work) if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) ieee80211_mesh_housekeeping(sdata, ifmsh); + + if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) + ieee80211_mesh_rootpath(sdata); } void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) @@ -662,7 +716,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) MESH_MIN_DISCOVERY_TIMEOUT; ifmsh->accepting_plinks = true; ifmsh->preq_id = 0; - ifmsh->dsn = 0; + ifmsh->sn = 0; atomic_set(&ifmsh->mpaths, 0); mesh_rmc_init(sdata); ifmsh->last_preq = jiffies; @@ -673,6 +727,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) setup_timer(&ifmsh->mesh_path_timer, ieee80211_mesh_path_timer, (unsigned long) sdata); + setup_timer(&ifmsh->mesh_path_root_timer, + ieee80211_mesh_path_root_timer, + (unsigned long) sdata); INIT_LIST_HEAD(&ifmsh->preq_queue.list); spin_lock_init(&ifmsh->mesh_preq_queue_lock); } @@ -693,9 +750,6 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_ACTION: - if (skb->len < IEEE80211_MIN_ACTION_SIZE) - return RX_DROP_MONITOR; - /* fall through */ case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: skb_queue_tail(&ifmsh->skb_queue, skb);