Skip to content
Snippets Groups Projects
lec.c 60.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		entry = make_entry(priv, bus_mac);
    		if (entry == NULL)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			goto out;
    
    		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
    		memset(entry->mac_addr, 0, ETH_ALEN);
    		entry->recv_vcc = vcc;
    		entry->old_recv_push = old_push;
    		entry->status = ESI_UNKNOWN;
    		entry->timer.expires = jiffies + priv->vcc_timeout_period;
    		entry->timer.function = lec_arp_expire_vcc;
    
    		hlist_add_head(&entry->next, &priv->lec_no_forward);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		dump_arp_table(priv);
    		goto out;
    
    	pr_debug("LEC_ARP:Attaching data direct, default: %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
    		 ioc_data->atm_addr[0], ioc_data->atm_addr[1],
    		 ioc_data->atm_addr[2], ioc_data->atm_addr[3],
    		 ioc_data->atm_addr[4], ioc_data->atm_addr[5],
    		 ioc_data->atm_addr[6], ioc_data->atm_addr[7],
    		 ioc_data->atm_addr[8], ioc_data->atm_addr[9],
    		 ioc_data->atm_addr[10], ioc_data->atm_addr[11],
    		 ioc_data->atm_addr[12], ioc_data->atm_addr[13],
    		 ioc_data->atm_addr[14], ioc_data->atm_addr[15],
    		 ioc_data->atm_addr[16], ioc_data->atm_addr[17],
    		 ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
    
    	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
    
    		hlist_for_each_entry(entry,
    
    				     &priv->lec_arp_tables[i], next) {
    
    			if (memcmp
    			    (ioc_data->atm_addr, entry->atm_addr,
    			     ATM_ESA_LEN) == 0) {
    
    				pr_debug("LEC_ARP: Attaching data direct\n");
    				pr_debug("Currently -> Vcc: %d, Rvcc:%d\n",
    
    					 entry->vcc ? entry->vcc->vci : 0,
    					 entry->recv_vcc ? entry->recv_vcc->
    					 vci : 0);
    
    				found_entry = 1;
    				del_timer(&entry->timer);
    				entry->vcc = vcc;
    				entry->old_push = old_push;
    				if (entry->status == ESI_VC_PENDING) {
    					if (priv->maximum_unknown_frame_count
    					    == 0)
    						entry->status =
    						    ESI_FORWARD_DIRECT;
    					else {
    						entry->timestamp = jiffies;
    						entry->status =
    						    ESI_FLUSH_PENDING;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #if 0
    
    						send_to_lecd(priv, l_flush_xmt,
    							     NULL,
    							     entry->atm_addr,
    							     NULL);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif
    
    					}
    				} else {
    					/*
    					 * They were forming a connection
    					 * to us, and we to them. Our
    					 * ATM address is numerically lower
    					 * than theirs, so we make connection
    					 * we formed into default VCC (8.1.11).
    					 * Connection they made gets torn
    					 * down. This might confuse some
    					 * clients. Can be changed if
    					 * someone reports trouble...
    					 */
    					;
    				}
    			}
    		}
    	}
    	if (found_entry) {
    
    		pr_debug("After vcc was added\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		goto out;
    
    	}
    	/*
    	 * Not found, snatch address from first data packet that arrives
    	 * from this vcc
    	 */
    	entry = make_entry(priv, bus_mac);
    	if (!entry)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		goto out;
    
    	entry->vcc = vcc;
    	entry->old_push = old_push;
    	memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
    	memset(entry->mac_addr, 0, ETH_ALEN);
    	entry->status = ESI_UNKNOWN;
    
    	hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
    
    	entry->timer.expires = jiffies + priv->vcc_timeout_period;
    	entry->timer.function = lec_arp_expire_vcc;
    	add_timer(&entry->timer);
    
    	pr_debug("After vcc was added\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	dump_arp_table(priv);
    out:
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    }
    
    
    static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned long flags;
    
    	struct lec_arp_table *entry;
    	int i;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	pr_debug("%lx\n", tran_id);
    
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
    
    		hlist_for_each_entry(entry,
    
    				     &priv->lec_arp_tables[i], next) {
    			if (entry->flush_tran_id == tran_id &&
    			    entry->status == ESI_FLUSH_PENDING) {
    
    				struct atm_vcc *vcc = entry->vcc;
    
    				spin_unlock_irqrestore(&priv->lec_arp_lock,
    						       flags);
    
    				while ((skb = skb_dequeue(&entry->tx_wait)))
    
    				entry->status = ESI_FORWARD_DIRECT;
    
    				pr_debug("LEC_ARP: Flushed\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void
    lec_set_flush_tran_id(struct lec_priv *priv,
    
    		      const unsigned char *atm_addr, unsigned long tran_id)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned long flags;
    
    	struct lec_arp_table *entry;
    	int i;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    
    	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
    
    		hlist_for_each_entry(entry,
    
    				     &priv->lec_arp_tables[i], next) {
    
    			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
    				entry->flush_tran_id = tran_id;
    
    				pr_debug("Set flush transaction id to %lx for %p\n",
    
    					 tran_id, entry);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    }
    
    
    static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned long flags;
    
    	unsigned char mac_addr[] = {
    		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    	};
    	struct lec_arp_table *to_add;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	struct lec_vcc_priv *vpriv;
    	int err = 0;
    
    	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
    	if (!vpriv)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		return -ENOMEM;
    	vpriv->xoff = 0;
    	vpriv->old_pop = vcc->pop;
    	vcc->user_back = vpriv;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    
    	to_add = make_entry(priv, mac_addr);
    	if (!to_add) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		vcc->pop = vpriv->old_pop;
    		kfree(vpriv);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		goto out;
    
    	}
    	memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
    	to_add->status = ESI_FORWARD_DIRECT;
    	to_add->flags |= LEC_PERMANENT_FLAG;
    	to_add->vcc = vcc;
    	to_add->old_push = vcc->push;
    	vcc->push = lec_push;
    	priv->mcast_vcc = vcc;
    	lec_arp_add(priv, to_add);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    
    static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned long flags;
    
    	struct hlist_node *next;
    
    	struct lec_arp_table *entry;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	pr_debug("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    
    	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
    
    		hlist_for_each_entry_safe(entry, next,
    
    					  &priv->lec_arp_tables[i], next) {
    
    			if (vcc == entry->vcc) {
    				lec_arp_remove(priv, entry);
    
    				if (priv->mcast_vcc == vcc)
    
    	hlist_for_each_entry_safe(entry, next,
    
    				  &priv->lec_arp_empty_ones, next) {
    
    		if (entry->vcc == vcc) {
    
    			lec_arp_clear_vccs(entry);
    			del_timer(&entry->timer);
    
    			hlist_del(&entry->next);
    
    	hlist_for_each_entry_safe(entry, next,
    
    				  &priv->lec_no_forward, next) {
    
    		if (entry->recv_vcc == vcc) {
    			lec_arp_clear_vccs(entry);
    			del_timer(&entry->timer);
    
    			hlist_del(&entry->next);
    
    	hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {
    
    		if (entry->recv_vcc == vcc) {
    			lec_arp_clear_vccs(entry);
    			/* No timer, LANEv2 7.1.20 and 2.3.5.3 */
    
    			hlist_del(&entry->next);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    	dump_arp_table(priv);
    }
    
    static void
    lec_arp_check_empties(struct lec_priv *priv,
    
    		      struct atm_vcc *vcc, struct sk_buff *skb)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	struct hlist_node *next;
    
    	struct lec_arp_table *entry, *tmp;
    
    	struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
    
    	unsigned char *src = hdr->h_source;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    
    	hlist_for_each_entry_safe(entry, next,
    
    				  &priv->lec_arp_empty_ones, next) {
    
    		if (vcc == entry->vcc) {
    			del_timer(&entry->timer);
    
    Joe Perches's avatar
    Joe Perches committed
    			ether_addr_copy(entry->mac_addr, src);
    
    			entry->status = ESI_FORWARD_DIRECT;
    			entry->last_used = jiffies;
    			/* We might have got an entry */
    
    			tmp = lec_arp_find(priv, src);
    			if (tmp) {
    
    				lec_arp_remove(priv, tmp);
    
    			}
    			hlist_del(&entry->next);
    			lec_arp_add(priv, entry);
    			goto out;
    
    	pr_debug("LEC_ARP: Arp_check_empties: entry not found!\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    }
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    MODULE_LICENSE("GPL");