static void teql_destroy(struct Qdisc* sch) { struct Qdisc *q, *prev; struct teql_sched_data *dat = (struct teql_sched_data *)sch->data; struct teql_master *master = dat->m; if ((prev = master->slaves) != NULL) { do { q = NEXT_SLAVE(prev); if (q == sch) { NEXT_SLAVE(prev) = NEXT_SLAVE(q); if (q == master->slaves) { master->slaves = NEXT_SLAVE(q); if (q == master->slaves) { master->slaves = NULL; spin_lock_bh(&master->dev.queue_lock); qdisc_reset(master->dev.qdisc); spin_unlock_bh(&master->dev.queue_lock); } } skb_queue_purge(&dat->q); teql_neigh_release(xchg(&dat->ncache, NULL)); break; } } while ((prev = q) != master->slaves); } MOD_DEC_USE_COUNT; }
static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) { struct net_device *dev = qdisc_dev(sch); struct teql_master *m = (struct teql_master *)sch->ops; struct teql_sched_data *q = qdisc_priv(sch); if (dev->hard_header_len > m->dev->hard_header_len) return -EINVAL; if (m->dev == dev) return -ELOOP; q->m = m; skb_queue_head_init(&q->q); if (m->slaves) { if (m->dev->flags & IFF_UP) { if ((m->dev->flags & IFF_POINTOPOINT && !(dev->flags & IFF_POINTOPOINT)) || (m->dev->flags & IFF_BROADCAST && !(dev->flags & IFF_BROADCAST)) || (m->dev->flags & IFF_MULTICAST && !(dev->flags & IFF_MULTICAST)) || dev->mtu < m->dev->mtu) return -EINVAL; } else { if (!(dev->flags&IFF_POINTOPOINT)) m->dev->flags &= ~IFF_POINTOPOINT; if (!(dev->flags&IFF_BROADCAST)) m->dev->flags &= ~IFF_BROADCAST; if (!(dev->flags&IFF_MULTICAST)) m->dev->flags &= ~IFF_MULTICAST; if (dev->mtu < m->dev->mtu) m->dev->mtu = dev->mtu; } q->next = NEXT_SLAVE(m->slaves); NEXT_SLAVE(m->slaves) = sch; } else { q->next = sch; m->slaves = sch; m->dev->mtu = dev->mtu; m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK); } return 0; }
static void teql_destroy(struct Qdisc *sch) { struct Qdisc *q, *prev; struct teql_sched_data *dat = qdisc_priv(sch); struct teql_master *master = dat->m; prev = master->slaves; if (prev) { do { q = NEXT_SLAVE(prev); if (q == sch) { NEXT_SLAVE(prev) = NEXT_SLAVE(q); if (q == master->slaves) { master->slaves = NEXT_SLAVE(q); if (q == master->slaves) { struct netdev_queue *txq; spinlock_t *root_lock; txq = netdev_get_tx_queue(master->dev, 0); master->slaves = NULL; root_lock = qdisc_root_sleeping_lock(txq->qdisc); spin_lock_bh(root_lock); qdisc_reset(txq->qdisc); spin_unlock_bh(root_lock); } } skb_queue_purge(&dat->q); teql_neigh_release(xchg(&dat->ncache, NULL)); break; } } while ((prev = q) != master->slaves); } }
static int teql_master_mtu(struct net_device *dev, int new_mtu) { struct teql_master *m = (void*)dev->priv; struct Qdisc *q; if (new_mtu < 68) return -EINVAL; q = m->slaves; if (q) { do { if (new_mtu > q->dev->mtu) return -EINVAL; } while ((q=NEXT_SLAVE(q)) != m->slaves); } dev->mtu = new_mtu; return 0; }
static int teql_master_open(struct net_device *dev) { struct Qdisc * q; struct teql_master *m = (void*)dev->priv; int mtu = 0xFFFE; unsigned flags = IFF_NOARP|IFF_MULTICAST; if (m->slaves == NULL) return -EUNATCH; flags = FMASK; q = m->slaves; do { struct net_device *slave = q->dev; if (slave == NULL) return -EUNATCH; if (slave->mtu < mtu) mtu = slave->mtu; if (slave->hard_header_len > LL_MAX_HEADER) return -EINVAL; /* If all the slaves are BROADCAST, master is BROADCAST If all the slaves are PtP, master is PtP Otherwise, master is NBMA. */ if (!(slave->flags&IFF_POINTOPOINT)) flags &= ~IFF_POINTOPOINT; if (!(slave->flags&IFF_BROADCAST)) flags &= ~IFF_BROADCAST; if (!(slave->flags&IFF_MULTICAST)) flags &= ~IFF_MULTICAST; } while ((q = NEXT_SLAVE(q)) != m->slaves); m->dev.mtu = mtu; m->dev.flags = (m->dev.flags&~FMASK) | flags; netif_start_queue(&m->dev); MOD_INC_USE_COUNT; return 0; }
static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev) { struct teql_master *master = (void*)dev->priv; struct Qdisc *start, *q; int busy; int nores; int len = skb->len; struct sk_buff *skb_res = NULL; start = master->slaves; restart: nores = 0; busy = 0; if ((q = start) == NULL) goto drop; do { struct net_device *slave = q->dev; if (slave->qdisc_sleeping != q) continue; if (netif_queue_stopped(slave) || ! netif_running(slave)) { busy = 1; continue; } switch (teql_resolve(skb, skb_res, slave)) { case 0: if (spin_trylock(&slave->xmit_lock)) { slave->xmit_lock_owner = smp_processor_id(); if (!netif_queue_stopped(slave) && slave->hard_start_xmit(skb, slave) == 0) { slave->xmit_lock_owner = -1; spin_unlock(&slave->xmit_lock); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); master->stats.tx_packets++; master->stats.tx_bytes += len; return 0; } slave->xmit_lock_owner = -1; spin_unlock(&slave->xmit_lock); } if (netif_queue_stopped(dev)) busy = 1; break; case 1: master->slaves = NEXT_SLAVE(q); return 0; default: nores = 1; break; } __skb_pull(skb, skb->nh.raw - skb->data); } while ((q = NEXT_SLAVE(q)) != start); if (nores && skb_res == NULL) { skb_res = skb; goto restart; } if (busy) { netif_stop_queue(dev); return 1; } master->stats.tx_errors++; drop: master->stats.tx_dropped++; dev_kfree_skb(skb); return 0; }