struct batman_packet *batman_packet)
{
- /* don't care if bonding is not enabled */
- if (!atomic_read(&bat_priv->bonding_enabled)) {
- orig_node->bond.candidates = 0;
- return;
- }
-
if (batman_packet->flags & PRIMARIES_FIRST_HOP)
memcpy(orig_neigh_node->primary_addr,
orig_node->orig, ETH_ALEN);
struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
struct neigh_node *first_candidate, *last_candidate;
- /* don't care if bonding is not enabled */
- if (!atomic_read(&bat_priv->bonding_enabled)) {
- orig_node->bond.candidates = 0;
- return;
- }
-
/* update the candidates for this originator */
if (!orig_node->router) {
orig_node->bond.candidates = 0;
/* find a suitable router for this originator, and use
* bonding if possible. */
-struct neigh_node *find_router(struct orig_node *orig_node)
+struct neigh_node *find_router(struct orig_node *orig_node,
+ struct batman_if *recv_if)
{
/* FIXME: each orig_node->batman_if will be attached to a softif */
struct bat_priv *bat_priv = netdev_priv(soft_device);
struct orig_node *primary_orig_node;
struct orig_node *router_orig;
- struct neigh_node *router;
+ struct neigh_node *router, *first_candidate, *best_router;
static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+ int bonding_enabled;
if (!orig_node)
return NULL;
if (!orig_node->router)
return NULL;
- /* don't care if bonding is not enabled */
- if (!atomic_read(&bat_priv->bonding_enabled))
- return orig_node->router;
+ /* without bonding, the first node should
+ * always choose the default router. */
+
+ bonding_enabled = atomic_read(&bat_priv->bonding_enabled);
+ if (!bonding_enabled && (recv_if == NULL))
+ return orig_node->router;
router_orig = orig_node->router->orig_node;
if (primary_orig_node->bond.candidates < 2)
return orig_node->router;
- router = primary_orig_node->bond.selected;
- /* sanity check - this should never happen. */
- if (!router)
- return orig_node->router;
+ /* all nodes between should choose a candidate which
+ * is is not on the interface where the packet came
+ * in. */
+ first_candidate = primary_orig_node->bond.selected;
+ router = first_candidate;
+
+ if (bonding_enabled) {
+ /* in the bonding case, send the packets in a round
+ * robin fashion over the remaining interfaces. */
+ do {
+ /* recv_if == NULL on the first node. */
+ if (router->if_incoming != recv_if)
+ break;
+
+ router = router->next_bond_candidate;
+ } while (router != first_candidate);
+
+ primary_orig_node->bond.selected = router->next_bond_candidate;
- /* select the next bonding partner ... */
- primary_orig_node->bond.selected = router->next_bond_candidate;
+ } else {
+ /* if bonding is disabled, use the best of the
+ * remaining candidates which are not using
+ * this interface. */
+ best_router = first_candidate;
+
+ do {
+ /* recv_if == NULL on the first node. */
+ if ((router->if_incoming != recv_if) &&
+ (router->tq_avg > best_router->tq_avg))
+ best_router = router;
+
+ router = router->next_bond_candidate;
+ } while (router != first_candidate);
+
+ router = best_router;
+ }
return router;
}
-int recv_unicast_packet(struct sk_buff *skb)
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
{
struct unicast_packet *unicast_packet;
struct orig_node *orig_node;
orig_node = ((struct orig_node *)
hash_find(orig_hash, unicast_packet->dest));
- router = find_router(orig_node);
+ router = find_router(orig_node, recv_if);
if (!router) {
spin_unlock_irqrestore(&orig_hash_lock, flags);
struct neigh_node *neigh_node,
unsigned char *hna_buff, int hna_buff_len);
int recv_icmp_packet(struct sk_buff *skb);
-int recv_unicast_packet(struct sk_buff *skb);
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_bcast_packet(struct sk_buff *skb);
int recv_vis_packet(struct sk_buff *skb);
int recv_bat_packet(struct sk_buff *skb,
struct batman_if *batman_if);
-struct neigh_node *find_router(struct orig_node *orig_node);
+struct neigh_node *find_router(struct orig_node *orig_node,
+ struct batman_if *recv_if);
void update_bonding_candidates(struct bat_priv *bat_priv,
struct orig_node *orig_node);