Esempio n. 1
0
static int clip_inarp_send(struct atm_vcc *vcc, u32 remote_ip, u16 op)
{
    struct sk_buff *skb;
    int allocated_size, error, size = 0;
    u8 *buff;
    u32 local_ip;
    struct atmarphdr *hdr;

    if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
	test_bit(ATM_VF_CLOSE, &vcc->flags))
    {
	return vcc->reply;
    }
    if (!test_bit(ATM_VF_READY, &vcc->flags))
	return -EPIPE;
    
    /* align to word boundary */
    allocated_size = (MAX_ATMARP_SIZE + RFC1483LLC_LEN + 3) & ~3;

    if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc, allocated_size))
    {
	DPRINTK("Sorry: tx_inuse = %d, size = %d, sndbuf = %d\n",
	    atomic_read(&vcc->tx_inuse), allocated_size, vcc->sk->sndbuf);
	return -1;
    }
    if(!(skb = alloc_skb(allocated_size, GFP_ATOMIC)))
	return -1;
    DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse), skb->truesize);
    atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);

    skb->dev = NULL; /* for paths shared with net_device interfaces */
    ATM_SKB(skb)->iovcnt = 0;
    ATM_SKB(skb)->atm_options = vcc->atm_options;
    buff = skb->data;
    memcpy(buff, llc_oui_arp, RFC1483LLC_LEN);
    hdr = (struct atmarphdr *) (buff + RFC1483LLC_LEN);
    memset(hdr, 0, MAX_ATMARP_SIZE);
    hdr->ar_hrd = htons(ARPHRD_ATM);
    hdr->ar_pro = htons(ETH_P_IP);
    hdr->ar_op = htons(op);
    local_ip = clip_vcc_to_local_ip(CLIP_VCC(vcc));
    size = hdr->data - buff;
    /* XXX: htonl might be needed */
    memcpy(hdr->data, &local_ip, sizeof(u32));
    hdr->ar_spln = sizeof(u32);
    size += sizeof(u32);
    if (remote_ip)
    {
	/* XXX: htonl might be needed */
	memcpy(hdr->data + sizeof(u32), &remote_ip, sizeof(u32));
	hdr->ar_tpln = sizeof(u32);
	size += sizeof(u32);
    }

    skb_put(skb, size);
    if (allocated_size != size)
	memset(skb->data + size, 0, allocated_size - size);
    error = vcc->dev->ops->send(vcc,skb);
    return error ? error : size;
}
static int clip6_start_xmit(struct sk_buff *skb,struct net_device *dev)
{
	struct clip6_priv *clip6_priv = PRIV(dev);
	struct atm_vcc *vcc;
	struct clip6_vcc *vccs;
	int old;
	unsigned long flags;

	DPRINTK("clip6_start_xmit (skb %p)\n",skb);

	vccs = clip6_priv->vccs;
	if (!vccs) {
		/* SVC is not supported yet. */
		printk(KERN_ERR "clip6_start_xmit: vccs == NULL\n");
		dev_kfree_skb(skb);
		clip6_priv->stats.tx_dropped++;
		return 0;
	}
	DPRINTK("vccs %p\n", vccs);
	ATM_SKB(skb)->vcc = vcc = vccs->vcc;
	DPRINTK("using p2p vcc %p\n",vcc);
	if (vccs->encap) {
		void *here;

		here = skb_push(skb,RFC1483LLC_LEN);
		memcpy(here,llc_oui,sizeof(llc_oui));
		((u16 *) here)[3] = skb->protocol;
	}
	atomic_add(skb->truesize, &vcc->sk->wmem_alloc);
	ATM_SKB(skb)->atm_options = vcc->atm_options;
		/* TODO: check */
	vccs->last_use = jiffies;
	DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
	old = xchg(&vccs->xoff,1); /* assume XOFF ... */
	if (old) {
		printk(KERN_WARNING "clip6_start_xmit: XOFF->XOFF transition\n");
		return 0;
	}
	clip6_priv->stats.tx_packets++;
	clip6_priv->stats.tx_bytes += skb->len;
	(void) vcc->send(vcc,skb);
	if (atm_may_send(vcc,0)) {
		vccs->xoff = 0;
		return 0;
	}
	spin_lock_irqsave(&clip6_priv->xoff_lock,flags);
	netif_stop_queue(dev); /* XOFF -> throttle immediately */
	barrier();
	if (!vccs->xoff)
		netif_start_queue(dev);
		/* Oh, we just raced with clip6_pop. netif_start_queue should be
		   good enough, because nothing should really be asleep because
		   of the brief netif_stop_queue. If this isn't true or if it
		   changes, use netif_wake_queue instead. */
	spin_unlock_irqrestore(&clip6_priv->xoff_lock,flags);
	return 0;
}
Esempio n. 3
0
static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
{
	struct clip_vcc *clip_vcc = CLIP_VCC(vcc);

	pr_debug("\n");

	if (!clip_devs) {
		atm_return(vcc, skb->truesize);
		kfree_skb(skb);
		return;
	}

	if (!skb) {
		pr_debug("removing VCC %p\n", clip_vcc);
		if (clip_vcc->entry)
			unlink_clip_vcc(clip_vcc);
		clip_vcc->old_push(vcc, NULL);	/* pass on the bad news */
		kfree(clip_vcc);
		return;
	}
	atm_return(vcc, skb->truesize);
	skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
	/* clip_vcc->entry == NULL if we don't have an IP address yet */
	if (!skb->dev) {
		dev_kfree_skb_any(skb);
		return;
	}
	ATM_SKB(skb)->vcc = vcc;
	skb_reset_mac_header(skb);
	if (!clip_vcc->encap ||
	    skb->len < RFC1483LLC_LEN ||
	    memcmp(skb->data, llc_oui, sizeof(llc_oui)))
		skb->protocol = htons(ETH_P_IP);
	else {
		skb->protocol = ((__be16 *)skb->data)[3];
		skb_pull(skb, RFC1483LLC_LEN);
		if (skb->protocol == htons(ETH_P_ARP)) {
			skb->dev->stats.rx_packets++;
			skb->dev->stats.rx_bytes += skb->len;
			clip_arp_rcv(skb);
			return;
		}
	}
	clip_vcc->last_use = jiffies;
	skb->dev->stats.rx_packets++;
	skb->dev->stats.rx_bytes += skb->len;
	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
	netif_rx(skb);
}
static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
{
	struct pppoatm_vcc *pvcc = chan_to_pvcc(chan);
	ATM_SKB(skb)->vcc = pvcc->atmvcc;
	pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
	if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
		(void) skb_pull(skb, 1);
	switch (pvcc->encaps) {		/* LLC encapsulation needed */
	case e_llc:
		if (skb_headroom(skb) < LLC_LEN) {
			struct sk_buff *n;
			n = skb_realloc_headroom(skb, LLC_LEN);
			if (n != NULL &&
			    !atm_may_send(pvcc->atmvcc, n->truesize)) {
				kfree_skb(n);
				goto nospace;
			}
			kfree_skb(skb);
			skb = n;
			if (skb == NULL)
				return DROP_PACKET;
		} else if (!atm_may_send(pvcc->atmvcc, skb->truesize))
			goto nospace;
		memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
		break;
	case e_vc:
		if (!atm_may_send(pvcc->atmvcc, skb->truesize))
			goto nospace;
		break;
	case e_autodetect:
		pr_debug("Trying to send without setting encaps!\n");
		kfree_skb(skb);
		return 1;
	}

	atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
	ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
		 skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
	return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
	    ? DROP_PACKET : 1;
nospace:
	/*
	 * We don't have space to send this SKB now, but we might have
	 * already applied SC_COMP_PROT compression, so may need to undo
	 */
	if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
	    skb->data[-1] == '\0')
		(void) skb_push(skb, 1);
	return 0;
}
Esempio n. 5
0
static int clip_arp_rcv(struct sk_buff *skb)
{
	struct atm_vcc *vcc;

	DPRINTK("clip_arp_rcv\n");
	vcc = ATM_SKB(skb)->vcc;
	if (!vcc || !atm_charge(vcc,skb->truesize)) {
		dev_kfree_skb_any(skb);
		return 0;
	}
	DPRINTK("pushing to %p\n",vcc);
	DPRINTK("using %p\n",CLIP_VCC(vcc)->old_push);
	CLIP_VCC(vcc)->old_push(vcc,skb);
	return 0;
}
Esempio n. 6
0
static int clip_arp_rcv(struct sk_buff *skb)
{
    struct atm_vcc *vcc;

    DPRINTK("clip_arp_rcv\n");
    vcc = ATM_SKB(skb)->vcc;
    if (!vcc)
	goto Exit;

    incoming_arp(CLIP_VCC(vcc), (struct atmarphdr *)skb->data, skb->len);

Exit:
    dev_kfree_skb_any(skb);
    return 0;
}
void clip6_push(struct atm_vcc *vcc,struct sk_buff *skb)
{
	struct clip6_vcc *clip6_vcc = CLIP6_VCC(vcc);

	DPRINTK("clip6 push\n");
	if (!skb) {
		DPRINTK("removing VCC %p\n",clip6_vcc);
		clip6_vcc->old_push(vcc,NULL); /* pass on the bad news */
		kfree(clip6_vcc);
		return;
	}
	atm_return(vcc,skb->truesize);
	skb->dev = clip6_vcc->dev;
		/* clip6_vcc->entry == NULL if we don't have an IP address yet */
	if (!skb->dev) {
		dev_kfree_skb_any(skb);
		return;
	}
	ATM_SKB(skb)->vcc = vcc;
	skb->mac.raw = skb->data;
	if (!clip6_vcc->encap || skb->len < RFC1483LLC_LEN || memcmp(skb->data,
	    llc_oui,sizeof(llc_oui))) {
		skb->protocol = ((u16 *) skb->data)[3];
				/* ??? Should I validate skb->protocol is
				   either ETH_P_IPV6 or ETH_P_IP? */
	}
	else {
		skb->protocol = ((u16 *) skb->data)[3];
		skb_pull(skb,RFC1483LLC_LEN);
				/* TODO: check */
#if 0
		if (skb->protocol == htons(ETH_P_ARP)) {
			PRIV(skb->dev)->stats.rx_packets++;
			PRIV(skb->dev)->stats.rx_bytes += skb->len;
			clip6_arp_rcv(skb);
			return;
		}
#endif /* if 0 */
	}
	clip6_vcc->last_use = jiffies;
	PRIV(skb->dev)->stats.rx_packets++;
	PRIV(skb->dev)->stats.rx_bytes += skb->len;
	netif_rx(skb);
}
Esempio n. 8
0
void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
{
    struct clip_vcc *clip_vcc = CLIP_VCC(vcc);

    DPRINTK("clip push\n");
    if (!skb)
    {
	clip_vcc_remove(clip_vcc);
	return;
    }
    atm_return(vcc, skb->truesize);
    skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
    /* clip_vcc->entry == NULL if we don't have an IP address yet */
    if (!skb->dev)
    {
	dev_kfree_skb_any(skb);
	return;
    }
    ATM_SKB(skb)->vcc = vcc;
    skb->mac.raw = skb->data;
    if (!clip_vcc->encap || skb->len < RFC1483LLC_LEN || memcmp(skb->data,
	llc_oui, sizeof(llc_oui))) skb->protocol = htons(ETH_P_IP);
    else
    {
	skb->protocol = ((u16 *) skb->data)[3];
	skb_pull(skb, RFC1483LLC_LEN);
	if (skb->protocol == htons(ETH_P_ARP))
	{
	    PRIV(skb->dev)->stats.rx_packets++;
	    PRIV(skb->dev)->stats.rx_bytes += skb->len;
	    clip_arp_rcv(skb);
	    return;
	}
    }
    clip_vcc->last_use = jiffies;
    PRIV(skb->dev)->stats.rx_packets++;
    PRIV(skb->dev)->stats.rx_bytes += skb->len;
    netif_rx(skb);
}
Esempio n. 9
0
static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
{
	struct net_device *dev = (struct net_device *)vcc->proto_data;
	struct sk_buff *new_skb;
	eg_cache_entry *eg;
	struct mpoa_client *mpc;
	uint32_t tag;
	char *tmp;
	
	ddprintk("mpoa: (%s) mpc_push:\n", dev->name);
	if (skb == NULL) {
		dprintk("mpoa: (%s) mpc_push: null skb, closing VCC\n", dev->name);
		mpc_vcc_close(vcc, dev);
		return;
	}
	
	skb->dev = dev;
	if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
		struct sock *sk = sk_atm(vcc);

		dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
		/* Pass control packets to daemon */
		skb_queue_tail(&sk->sk_receive_queue, skb);
		sk->sk_data_ready(sk, skb->len);
		return;
	}

	/* data coming over the shortcut */
	atm_return(vcc, skb->truesize);

	mpc = find_mpc_by_lec(dev);
	if (mpc == NULL) {
		printk("mpoa: (%s) mpc_push: unknown MPC\n", dev->name);
		return;
	}

	if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */
		ddprintk("mpoa: (%s) mpc_push: tagged data packet arrived\n", dev->name);

	} else if (memcmp(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */
		printk("mpoa: (%s) mpc_push: non-tagged data packet arrived\n", dev->name);
		printk("           mpc_push: non-tagged data unsupported, purging\n");
		dev_kfree_skb_any(skb);
		return;
	} else {
		printk("mpoa: (%s) mpc_push: garbage arrived, purging\n", dev->name);
		dev_kfree_skb_any(skb);
		return;
	}

	tmp = skb->data + sizeof(struct llc_snap_hdr);
	tag = *(uint32_t *)tmp;

	eg = mpc->eg_ops->get_by_tag(tag, mpc);
	if (eg == NULL) {
		printk("mpoa: (%s) mpc_push: Didn't find egress cache entry, tag = %u\n",
		       dev->name,tag);
		purge_egress_shortcut(vcc, NULL);
		dev_kfree_skb_any(skb);
		return;
	}
	
	/*
	 * See if ingress MPC is using shortcut we opened as a return channel.
	 * This means we have a bi-directional vcc opened by us.
	 */ 
	if (eg->shortcut == NULL) {
		eg->shortcut = vcc;
		printk("mpoa: (%s) mpc_push: egress SVC in use\n", dev->name);
	}

	skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); /* get rid of LLC/SNAP header */
	new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); /* LLC/SNAP is shorter than MAC header :( */
	dev_kfree_skb_any(skb);
	if (new_skb == NULL){
		mpc->eg_ops->put(eg);
		return;
	}
	skb_push(new_skb, eg->ctrl_info.DH_length);     /* add MAC header */
	memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length);
	new_skb->protocol = eth_type_trans(new_skb, dev);
	new_skb->nh.raw = new_skb->data;

	eg->latest_ip_addr = new_skb->nh.iph->saddr;
	eg->packets_rcvd++;
	mpc->eg_ops->put(eg);

	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
	netif_rx(new_skb);

	return;
}
Esempio n. 10
0
static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
{
	in_cache_entry *entry;
	struct iphdr *iph;
	char *buff;
	uint32_t ipaddr = 0;

	static struct {
		struct llc_snap_hdr hdr;
		uint32_t tag;
	} tagged_llc_snap_hdr = {
		{0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}},
		0
	};

	buff = skb->data + mpc->dev->hard_header_len;
	iph = (struct iphdr *)buff;
	ipaddr = iph->daddr;

	ddprintk("mpoa: (%s) send_via_shortcut: ipaddr 0x%x\n", mpc->dev->name, ipaddr);        

	entry = mpc->in_ops->get(ipaddr, mpc);
	if (entry == NULL) {
		entry = mpc->in_ops->add_entry(ipaddr, mpc);
		if (entry != NULL) mpc->in_ops->put(entry);
		return 1;
	}
	if (mpc->in_ops->cache_hit(entry, mpc) != OPEN){   /* threshold not exceeded or VCC not ready */
		ddprintk("mpoa: (%s) send_via_shortcut: cache_hit: returns != OPEN\n", mpc->dev->name);        
		mpc->in_ops->put(entry);
		return 1;
	}

	ddprintk("mpoa: (%s) send_via_shortcut: using shortcut\n", mpc->dev->name);        
	/* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
	if (iph->ttl <= 1) {
		ddprintk("mpoa: (%s) send_via_shortcut: IP ttl = %u, using LANE\n", mpc->dev->name, iph->ttl);        
		mpc->in_ops->put(entry);
		return 1;
	}
	iph->ttl--;
	iph->check = 0;
	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);

	if (entry->ctrl_info.tag != 0) {
		ddprintk("mpoa: (%s) send_via_shortcut: adding tag 0x%x\n", mpc->dev->name, entry->ctrl_info.tag);
		tagged_llc_snap_hdr.tag = entry->ctrl_info.tag;
		skb_pull(skb, ETH_HLEN);                       /* get rid of Eth header */
		skb_push(skb, sizeof(tagged_llc_snap_hdr));    /* add LLC/SNAP header   */
		memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr));
	} else {
		skb_pull(skb, ETH_HLEN);                        /* get rid of Eth header */
		skb_push(skb, sizeof(struct llc_snap_hdr));     /* add LLC/SNAP header + tag  */
		memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
	}

	atomic_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
	ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
	entry->shortcut->send(entry->shortcut, skb);
	entry->packets_fwded++;
	mpc->in_ops->put(entry);

	return 0;
}
Esempio n. 11
0
static void poll_rx(struct atm_dev *dev,int mbx)
{
	struct zatm_dev *zatm_dev;
	unsigned long pos;
	u32 x;
	int error;

	EVENT("poll_rx\n",0,0);
	zatm_dev = ZATM_DEV(dev);
	pos = (zatm_dev->mbx_start[mbx] & ~0xffffUL) | zin(MTA(mbx));
	while (x = zin(MWA(mbx)), (pos & 0xffff) != x) {
		u32 *here;
		struct sk_buff *skb;
		struct atm_vcc *vcc;
		int cells,size,chan;

		EVENT("MBX: host 0x%lx, nic 0x%x\n",pos,x);
		here = (u32 *) pos;
		if (((pos += 16) & 0xffff) == zatm_dev->mbx_end[mbx])
			pos = zatm_dev->mbx_start[mbx];
		cells = here[0] & uPD98401_AAL5_SIZE;
#if 0
printk("RX IND: 0x%x, 0x%x, 0x%x, 0x%x\n",here[0],here[1],here[2],here[3]);
{
unsigned long *x;
		printk("POOL: 0x%08x, 0x%08x\n",zpeekl(zatm_dev,
		      zatm_dev->pool_base),
		      zpeekl(zatm_dev,zatm_dev->pool_base+1));
		x = (unsigned long *) here[2];
		printk("[0..3] = 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n",
		    x[0],x[1],x[2],x[3]);
}
#endif
		error = 0;
		if (here[3] & uPD98401_AAL5_ERR) {
			error = (here[3] & uPD98401_AAL5_ES) >>
			    uPD98401_AAL5_ES_SHIFT;
			if (error == uPD98401_AAL5_ES_DEACT ||
			    error == uPD98401_AAL5_ES_FREE) continue;
		}
EVENT("error code 0x%x/0x%x\n",(here[3] & uPD98401_AAL5_ES) >>
  uPD98401_AAL5_ES_SHIFT,error);
		skb = ((struct rx_buffer_head *) bus_to_virt(here[2]))->skb;
		__net_timestamp(skb);
#if 0
printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3],
  ((unsigned *) skb->data)[-2],((unsigned *) skb->data)[-1],
  ((unsigned *) skb->data)[0]);
#endif
		EVENT("skb 0x%lx, here 0x%lx\n",(unsigned long) skb,
		    (unsigned long) here);
#if 0
printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
#endif
		size = error ? 0 : ntohs(((__be16 *) skb->data)[cells*
		    ATM_CELL_PAYLOAD/sizeof(u16)-3]);
		EVENT("got skb 0x%lx, size %d\n",(unsigned long) skb,size);
		chan = (here[3] & uPD98401_AAL5_CHAN) >>
		    uPD98401_AAL5_CHAN_SHIFT;
		if (chan < zatm_dev->chans && zatm_dev->rx_map[chan]) {
			int pos;
			vcc = zatm_dev->rx_map[chan];
			pos = ZATM_VCC(vcc)->pool;
			if (skb == zatm_dev->last_free[pos])
				zatm_dev->last_free[pos] = NULL;
			skb_unlink(skb, zatm_dev->pool + pos);
		}
		else {
			printk(KERN_ERR DEV_LABEL "(itf %d): RX indication "
			    "for non-existing channel\n",dev->number);
			size = 0;
			vcc = NULL;
			event_dump();
		}
		if (error) {
			static unsigned long silence = 0;
			static int last_error = 0;

			if (error != last_error ||
			    time_after(jiffies, silence)  || silence == 0){
				printk(KERN_WARNING DEV_LABEL "(itf %d): "
				    "chan %d error %s\n",dev->number,chan,
				    err_txt[error]);
				last_error = error;
				silence = (jiffies+2*HZ)|1;
			}
			size = 0;
		}
		if (size && (size > cells*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER ||
		    size <= (cells-1)*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER)) {
			printk(KERN_ERR DEV_LABEL "(itf %d): size %d with %d "
			    "cells\n",dev->number,size,cells);
			size = 0;
			event_dump();
		}
		if (size > ATM_MAX_AAL5_PDU) {
			printk(KERN_ERR DEV_LABEL "(itf %d): size too big "
			    "(%d)\n",dev->number,size);
			size = 0;
			event_dump();
		}
		if (!size) {
			dev_kfree_skb_irq(skb);
			if (vcc) atomic_inc(&vcc->stats->rx_err);
			continue;
		}
		if (!atm_charge(vcc,skb->truesize)) {
			dev_kfree_skb_irq(skb);
			continue;
		}
		skb->len = size;
		ATM_SKB(skb)->vcc = vcc;
		vcc->push(vcc,skb);
		atomic_inc(&vcc->stats->rx);
	}
Esempio n. 12
0
static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
{
	struct clip_priv *clip_priv = PRIV(dev);
	struct atmarp_entry *entry;
	struct atm_vcc *vcc;
	int old;
	unsigned long flags;

	DPRINTK("clip_start_xmit (skb %p)\n",skb);
	if (!skb->dst) {
		printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n");
		dev_kfree_skb(skb);
		clip_priv->stats.tx_dropped++;
		return 0;
	}
	if (!skb->dst->neighbour) {
#if 0
		skb->dst->neighbour = clip_find_neighbour(skb->dst,1);
		if (!skb->dst->neighbour) {
			dev_kfree_skb(skb); /* lost that one */
			clip_priv->stats.tx_dropped++;
			return 0;
		}
#endif
		printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
		dev_kfree_skb(skb);
		clip_priv->stats.tx_dropped++;
		return 0;
	}
	entry = NEIGH2ENTRY(skb->dst->neighbour);
	if (!entry->vccs) {
		if (time_after(jiffies, entry->expires)) {
			/* should be resolved */
			entry->expires = jiffies+ATMARP_RETRY_DELAY*HZ;
			to_atmarpd(act_need,PRIV(dev)->number,entry->ip);
		}
		if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)
			skb_queue_tail(&entry->neigh->arp_queue,skb);
		else {
			dev_kfree_skb(skb);
			clip_priv->stats.tx_dropped++;
		}
		return 0;
	}
	DPRINTK("neigh %p, vccs %p\n",entry,entry->vccs);
	ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
	DPRINTK("using neighbour %p, vcc %p\n",skb->dst->neighbour,vcc);
	if (entry->vccs->encap) {
		void *here;

		here = skb_push(skb,RFC1483LLC_LEN);
		memcpy(here,llc_oui,sizeof(llc_oui));
		((u16 *) here)[3] = skb->protocol;
	}
	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
	ATM_SKB(skb)->atm_options = vcc->atm_options;
	entry->vccs->last_use = jiffies;
	DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
	old = xchg(&entry->vccs->xoff,1); /* assume XOFF ... */
	if (old) {
		printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
		return 0;
	}
	clip_priv->stats.tx_packets++;
	clip_priv->stats.tx_bytes += skb->len;
	(void) vcc->send(vcc,skb);
	if (atm_may_send(vcc,0)) {
		entry->vccs->xoff = 0;
		return 0;
	}
	spin_lock_irqsave(&clip_priv->xoff_lock,flags);
	netif_stop_queue(dev); /* XOFF -> throttle immediately */
	barrier();
	if (!entry->vccs->xoff)
		netif_start_queue(dev);
		/* Oh, we just raced with clip_pop. netif_start_queue should be
		   good enough, because nothing should really be asleep because
		   of the brief netif_stop_queue. If this isn't true or if it
		   changes, use netif_wake_queue instead. */
	spin_unlock_irqrestore(&clip_priv->xoff_lock,flags);
	return 0;
}
Esempio n. 13
0
static int clip_start_xmit(struct sk_buff *skb, knet_netdev_t *dev)
{
    struct clip_priv *clip_priv = PRIV(dev);
    struct atmarp_entry *entry;
    struct atm_vcc *vcc;
    int old;
    unsigned long flags;

    DPRINTK("clip_start_xmit (skb %p)\n", skb);
    if (!skb->dst)
    {
	printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n");
	dev_kfree_skb(skb);
	clip_priv->stats.tx_dropped++;
	return 0;
    }
    if (!skb->dst->neighbour)
    {
	printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR!\n");
	dev_kfree_skb(skb);
	clip_priv->stats.tx_dropped++;
	return 0;
    }
    entry = NEIGH2ENTRY(skb->dst->neighbour);
    if (!entry->vccs)
    {
	if (time_after(jiffies, entry->expires))
	{
	    /* should be resolved */
	    entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ;
	} 
	if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)
	    skb_queue_tail(&entry->neigh->arp_queue, skb);
	else
	{
	    dev_kfree_skb(skb);
	    clip_priv->stats.tx_dropped++;
	}

	/* If a vcc was not resolved for a long time, it sends an InARP
	 * packet every 5 minutes. But if the other side connected now
	 * we do not want to wait.
	 */
	all_clip_vccs_start_resolving();
	return 0;
    }
    DPRINTK("neigh %p, vccs %p\n", entry, entry->vccs);
    ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
    DPRINTK("using neighbour %p, vcc %p\n", skb->dst->neighbour, vcc);
    if (entry->vccs->encap)
    {
	void *here;

	here = skb_push(skb, RFC1483LLC_LEN);
	memcpy(here, llc_oui, sizeof(llc_oui));
	((u16 *) here)[3] = skb->protocol;
    }
    atomic_add(skb->truesize, &vcc->tx_inuse);
    ATM_SKB(skb)->iovcnt = 0;
    ATM_SKB(skb)->atm_options = vcc->atm_options;
    entry->vccs->last_use = jiffies;
    DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc,vcc->dev);
    old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
    if (old)
    {
	printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
	return 0;
    }
    clip_priv->stats.tx_packets++;
    clip_priv->stats.tx_bytes += skb->len;
    vcc->dev->ops->send(vcc, skb);
    if (atm_may_send(vcc, 0))
    {
	entry->vccs->xoff = 0;
	return 0;
    }
    spin_lock_irqsave(&clip_priv->xoff_lock, flags);
    knet_netdev_stop_queue(dev); /* XOFF -> throttle immediately */
    barrier();
    if (!entry->vccs->xoff)
	knet_netdev_start_queue(dev);
    /* Oh, we just raced with clip_pop. netif_start_queue should be
       good enough, because nothing should really be asleep because
       of the brief netif_stop_queue. If this isn't true or if it
       changes, use netif_wake_queue instead. */
    spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
    return 0;
}
Esempio n. 14
0
static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
				   struct net_device *dev)
{
	struct clip_priv *clip_priv = PRIV(dev);
	struct dst_entry *dst = skb_dst(skb);
	struct atmarp_entry *entry;
	struct neighbour *n;
	struct atm_vcc *vcc;
	struct rtable *rt;
	__be32 *daddr;
	int old;
	unsigned long flags;

	pr_debug("(skb %p)\n", skb);
	if (!dst) {
		pr_err("skb_dst(skb) == NULL\n");
		dev_kfree_skb(skb);
		dev->stats.tx_dropped++;
		return NETDEV_TX_OK;
	}
	rt = (struct rtable *) dst;
	if (rt->rt_gateway)
		daddr = &rt->rt_gateway;
	else
		daddr = &ip_hdr(skb)->daddr;
	n = dst_neigh_lookup(dst, daddr);
	if (!n) {
		pr_err("NO NEIGHBOUR !\n");
		dev_kfree_skb(skb);
		dev->stats.tx_dropped++;
		return NETDEV_TX_OK;
	}
	entry = neighbour_priv(n);
	if (!entry->vccs) {
		if (time_after(jiffies, entry->expires)) {
			/* should be resolved */
			entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ;
			to_atmarpd(act_need, PRIV(dev)->number, *((__be32 *)n->primary_key));
		}
		if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)
			skb_queue_tail(&entry->neigh->arp_queue, skb);
		else {
			dev_kfree_skb(skb);
			dev->stats.tx_dropped++;
		}
		goto out_release_neigh;
	}
	pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
	ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
	pr_debug("using neighbour %p, vcc %p\n", n, vcc);
	if (entry->vccs->encap) {
		void *here;

		here = skb_push(skb, RFC1483LLC_LEN);
		memcpy(here, llc_oui, sizeof(llc_oui));
		((__be16 *) here)[3] = skb->protocol;
	}
	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
	ATM_SKB(skb)->atm_options = vcc->atm_options;
	entry->vccs->last_use = jiffies;
	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
	old = xchg(&entry->vccs->xoff, 1);	/* assume XOFF ... */
	if (old) {
		pr_warning("XOFF->XOFF transition\n");
		goto out_release_neigh;
	}
	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;
	vcc->send(vcc, skb);
	if (atm_may_send(vcc, 0)) {
		entry->vccs->xoff = 0;
		goto out_release_neigh;
	}
	spin_lock_irqsave(&clip_priv->xoff_lock, flags);
	netif_stop_queue(dev);	/* XOFF -> throttle immediately */
	barrier();
	if (!entry->vccs->xoff)
		netif_start_queue(dev);
	/* Oh, we just raced with clip_pop. netif_start_queue should be
	   good enough, because nothing should really be asleep because
	   of the brief netif_stop_queue. If this isn't true or if it
	   changes, use netif_wake_queue instead. */
	spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
out_release_neigh:
	neigh_release(n);
	return NETDEV_TX_OK;
}