Esempio n. 1
0
/**
 * mesh_nexthop_resolve - lookup next hop; conditionally start path discovery
 *
 * @skb: 802.11 frame to be sent
 * @sdata: network subif the frame will be sent through
 *
 * Lookup next hop for given skb and start path discovery if no
 * forwarding information is found.
 *
 * Returns: 0 if the next hop was found and -ENOENT if the frame was queued.
 * skb is freeed here if no mpath could be allocated.
 */
int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
			 struct sk_buff *skb)
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct mesh_path *mpath;
	struct sk_buff *skb_to_free = NULL;
	u8 *target_addr = hdr->addr3;
	int err = 0;

	/* Nulls are only sent to peers for PS and should be pre-addressed */
	if (ieee80211_is_qos_nullfunc(hdr->frame_control))
		return 0;

	rcu_read_lock();
	err = mesh_nexthop_lookup(sdata, skb);
	if (!err)
		goto endlookup;

	/* no nexthop found, start resolving */
	mpath = mesh_path_lookup(sdata, target_addr);
	if (!mpath) {
		mesh_path_add(sdata, target_addr);
		mpath = mesh_path_lookup(sdata, target_addr);
		if (!mpath) {
			mesh_path_discard_frame(sdata, skb);
			err = -ENOSPC;
			goto endlookup;
		}
	}

	if (!(mpath->flags & MESH_PATH_RESOLVING))
		mesh_queue_preq(mpath, PREQ_Q_F_START);

	if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
		skb_to_free = skb_dequeue(&mpath->frame_queue);

	info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
	ieee80211_set_qos_hdr(sdata, skb);
	skb_queue_tail(&mpath->frame_queue, skb);
	err = -ENOENT;
	if (skb_to_free)
		mesh_path_discard_frame(sdata, skb_to_free);

endlookup:
	rcu_read_unlock();
	return err;
}
Esempio n. 2
0
/**
 * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame
 *
 * @skb: 802.11 frame to be sent
 * @sdata: network subif the frame will be sent through
 *
 * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
 * found, the function will start a path discovery and queue the frame so it is
 * sent when the path is resolved. This means the caller must not free the skb
 * in this case.
 */
int mesh_nexthop_lookup(struct sk_buff *skb,
			struct ieee80211_sub_if_data *sdata)
{
	struct sk_buff *skb_to_free = NULL;
	struct mesh_path *mpath;
	struct sta_info *next_hop;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	u8 *target_addr = hdr->addr3;
	int err = 0;

	rcu_read_lock();
	mpath = mesh_path_lookup(target_addr, sdata);

	if (!mpath) {
		mesh_path_add(target_addr, sdata);
		mpath = mesh_path_lookup(target_addr, sdata);
		if (!mpath) {
			sdata->u.mesh.mshstats.dropped_frames_no_route++;
			err = -ENOSPC;
			goto endlookup;
		}
	}

	if (mpath->flags & MESH_PATH_ACTIVE) {
		if (time_after(jiffies,
			       mpath->exp_time -
			       msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
		    !memcmp(sdata->vif.addr, hdr->addr4, ETH_ALEN) &&
		    !(mpath->flags & MESH_PATH_RESOLVING) &&
		    !(mpath->flags & MESH_PATH_FIXED)) {
			mesh_queue_preq(mpath,
					PREQ_Q_F_START | PREQ_Q_F_REFRESH);
		}
		next_hop = rcu_dereference(mpath->next_hop);
		if (next_hop)
			memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
		else
			err = -ENOENT;
	} else {
		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
			/* Start discovery only if it is not running yet */
			mesh_queue_preq(mpath, PREQ_Q_F_START);
		}

		if (skb_queue_len(&mpath->frame_queue) >=
				MESH_FRAME_QUEUE_LEN)
			skb_to_free = skb_dequeue(&mpath->frame_queue);

		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
		skb_queue_tail(&mpath->frame_queue, skb);
		if (skb_to_free)
			mesh_path_discard_frame(skb_to_free, sdata);
		err = -ENOENT;
	}

endlookup:
	rcu_read_unlock();
	return err;
}
Esempio n. 3
0
/**
 * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame
 *
 * @next_hop: output argument for next hop address
 * @skb: frame to be sent
 * @dev: network device the frame will be sent through
 *
 * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
 * found, the function will start a path discovery and queue the frame so it is
 * sent when the path is resolved. This means the caller must not free the skb
 * in this case.
 */
int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
		struct net_device *dev)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	struct sk_buff *skb_to_free = NULL;
	struct mesh_path *mpath;
	int err = 0;

	rcu_read_lock();
	mpath = mesh_path_lookup(skb->data, dev);

	if (!mpath) {
		mesh_path_add(skb->data, dev);
		mpath = mesh_path_lookup(skb->data, dev);
		if (!mpath) {
			dev_kfree_skb(skb);
			sdata->u.sta.mshstats.dropped_frames_no_route++;
			err = -ENOSPC;
			goto endlookup;
		}
	}

	if (mpath->flags & MESH_PATH_ACTIVE) {
		if (time_after(jiffies, mpath->exp_time -
			msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time))
				&& skb->pkt_type != PACKET_OTHERHOST
				&& !(mpath->flags & MESH_PATH_RESOLVING)
				&& !(mpath->flags & MESH_PATH_FIXED)) {
			mesh_queue_preq(mpath,
					PREQ_Q_F_START | PREQ_Q_F_REFRESH);
		}
		memcpy(next_hop, mpath->next_hop->addr,
				ETH_ALEN);
	} else {
		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
			/* Start discovery only if it is not running yet */
			mesh_queue_preq(mpath, PREQ_Q_F_START);
		}

		if (skb_queue_len(&mpath->frame_queue) >=
				MESH_FRAME_QUEUE_LEN) {
			skb_to_free = mpath->frame_queue.next;
			skb_unlink(skb_to_free, &mpath->frame_queue);
		}

		skb_queue_tail(&mpath->frame_queue, skb);
		if (skb_to_free)
			mesh_path_discard_frame(skb_to_free, dev);
		err = -ENOENT;
	}

endlookup:
	rcu_read_unlock();
	return err;
}