Skip to content
Snippets Groups Projects
lec.c 63.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 				tmp = lec_arp_find(priv, mac_addr);
    				if (tmp) {
    					del_timer(&tmp->timer);
    					tmp->status = ESI_FORWARD_DIRECT;
    					memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
    					tmp->vcc = entry->vcc;
    					tmp->old_push = entry->old_push;
    					tmp->last_used = jiffies;
    					del_timer(&entry->timer);
    
    					entry = tmp;
    				} else {
    					entry->status = ESI_FORWARD_DIRECT;
    					memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
    					entry->last_used = jiffies;
    					lec_arp_add(priv, entry);
    				}
    				if (remoteflag)
    					entry->flags |= LEC_REMOTE_FLAG;
    				else
    					entry->flags &= ~LEC_REMOTE_FLAG;
    
    				pr_debug("After update\n");
    
    				dump_arp_table(priv);
    				goto out;
    
    	entry = lec_arp_find(priv, mac_addr);
    	if (!entry) {
    		entry = make_entry(priv, mac_addr);
    		if (!entry)
    			goto out;
    		entry->status = ESI_UNKNOWN;
    		lec_arp_add(priv, entry);
    		/* Temporary, changes before end of function */
    	}
    	memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
    	del_timer(&entry->timer);
    	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
    
    		hlist_for_each_entry(tmp, node,
    				     &priv->lec_arp_tables[i], next) {
    
    			if (entry != tmp &&
    			    !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
    				/* Vcc to this host exists */
    				if (tmp->status > ESI_VC_PENDING) {
    					/*
    					 * ESI_FLUSH_PENDING,
    					 * ESI_FORWARD_DIRECT
    					 */
    					entry->vcc = tmp->vcc;
    					entry->old_push = tmp->old_push;
    				}
    				entry->status = tmp->status;
    				break;
    			}
    		}
    	}
    	if (remoteflag)
    		entry->flags |= LEC_REMOTE_FLAG;
    	else
    		entry->flags &= ~LEC_REMOTE_FLAG;
    	if (entry->status == ESI_ARP_PENDING || entry->status == ESI_UNKNOWN) {
    		entry->status = ESI_VC_PENDING;
    
    		send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
    
    	pr_debug("After update2\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
    }
    
    /*
    
     * Notifies: Vcc setup ready
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    static void
    
    lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
    
    	      struct atm_vcc *vcc,
    	      void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned long flags;
    
    	struct hlist_node *node;
    
    	struct lec_arp_table *entry;
    	int i, found_entry = 0;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    
    	/* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
    
    	if (ioc_data->receive == 2) {
    
    		pr_debug("LEC_ARP: Attaching mcast forward\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #if 0
    
    		entry = lec_arp_find(priv, bus_mac);
    		if (!entry) {
    
    			pr_info("LEC_ARP: Multicast entry not found!\n");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			goto out;
    
    		}
    		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
    		entry->recv_vcc = vcc;
    		entry->old_recv_push = old_push;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif
    
    		entry = make_entry(priv, bus_mac);
    		if (entry == NULL)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			goto out;
    
    		del_timer(&entry->timer);
    		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
    		entry->recv_vcc = vcc;
    		entry->old_recv_push = old_push;
    
    		hlist_add_head(&entry->next, &priv->mcast_fwds);
    
    		goto out;
    	} else if (ioc_data->receive == 1) {
    		/*
    		 * Vcc which we don't want to make default vcc,
    		 * attach it anyway.
    		 */
    
    		pr_debug("LEC_ARP:Attaching data direct, not 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]);
    
    		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, node,
    				     &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 hlist_node *node;
    
    	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, node,
    				     &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 hlist_node *node;
    
    	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, node,
    				     &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 *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, node, 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, node, 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, node, 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, node, 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 *node, *next;
    	struct lec_arp_table *entry, *tmp;
    
    	struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
    	unsigned char *src;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #ifdef CONFIG_TR
    
    	struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	if (priv->is_trdev)
    		src = tr_hdr->h_source;
    	else
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	spin_lock_irqsave(&priv->lec_arp_lock, flags);
    
    	hlist_for_each_entry_safe(entry, node, next,
    				  &priv->lec_arp_empty_ones, next) {
    
    		if (vcc == entry->vcc) {
    			del_timer(&entry->timer);
    			memcpy(entry->mac_addr, src, ETH_ALEN);
    			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");