예제 #1
0
int atm_charge(struct atm_vcc *vcc, int truesize)
{
	atm_force_charge(vcc, truesize);
	if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf)
		return 1;
	atm_return(vcc, truesize);
	atomic_inc(&vcc->stats->rx_drop);
	return 0;
}
예제 #2
0
static void sigd_put_skb(struct sk_buff *skb)
{
	if (!sigd) {
		pr_debug("atmsvc: no signaling daemon\n");
		kfree_skb(skb);
		return;
	}
	atm_force_charge(sigd, skb->truesize);
	skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb);
	sk_atm(sigd)->sk_data_ready(sk_atm(sigd));
}
예제 #3
0
static void svc_disconnect(struct atm_vcc *vcc)
{
	DEFINE_WAIT(wait);
	struct sk_buff *skb;
	struct sock *sk = sk_atm(vcc);

	pr_debug("svc_disconnect %p\n",vcc);
	if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
		sigd_enq(vcc,as_close,NULL,NULL,NULL);
		while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
			schedule();
			prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
		}
		finish_wait(sk->sk_sleep, &wait);
	}
	
	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
		atm_return(vcc, skb->truesize);
		pr_debug("LISTEN REL\n");
		sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
		dev_kfree_skb(skb);
	}
	clear_bit(ATM_VF_REGIS, &vcc->flags);
	
}
예제 #4
0
static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
	struct sock *sk = sk_atm(vcc);

	seq_printf(seq, "%pK ", vcc);
	if (!vcc->dev)
		seq_printf(seq, "Unassigned    ");
	else
		seq_printf(seq, "%3d %3d %5d ", vcc->dev->number, vcc->vpi,
			vcc->vci);
	switch (sk->sk_family) {
	case AF_ATMPVC:
		seq_printf(seq, "PVC");
		break;
	case AF_ATMSVC:
		seq_printf(seq, "SVC");
		break;
	default:
		seq_printf(seq, "%3d", sk->sk_family);
	}
	seq_printf(seq, " %04lx  %5d %7d/%7d %7d/%7d [%d]\n",
		   vcc->flags, sk->sk_err,
		   sk_wmem_alloc_get(sk), sk->sk_sndbuf,
		   sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
		   atomic_read(&sk->sk_refcnt));
}
예제 #5
0
static void svc_disconnect(struct atm_vcc *vcc)
{
	DEFINE_WAIT(wait);
	struct sk_buff *skb;
	struct sock *sk = sk_atm(vcc);

	DPRINTK("svc_disconnect %p\n",vcc);
	if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
		sigd_enq(vcc,as_close,NULL,NULL,NULL);
		while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
			schedule();
			prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
		}
		finish_wait(sk->sk_sleep, &wait);
	}
	/* beware - socket is still in use by atmsigd until the last
	   as_indicate has been answered */
	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
		atm_return(vcc, skb->truesize);
		DPRINTK("LISTEN REL\n");
		sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
		dev_kfree_skb(skb);
	}
	clear_bit(ATM_VF_REGIS, &vcc->flags);
	/* ... may retry later */
}
예제 #6
0
static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
{
	struct sock *sk;
	struct k_message *purge_msg;
	struct sk_buff *skb;

	dprintk("mpoa: purge_egress_shortcut: entering\n");
	if (vcc == NULL) {
		printk("mpoa: purge_egress_shortcut: vcc == NULL\n");
		return;
	}

	skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
	if (skb == NULL) {
		 printk("mpoa: purge_egress_shortcut: out of memory\n");
		return;
	}

	skb_put(skb, sizeof(struct k_message));
	memset(skb->data, 0, sizeof(struct k_message));
	purge_msg = (struct k_message *)skb->data;
	purge_msg->type = DATA_PLANE_PURGE;
	if (entry != NULL)
		purge_msg->content.eg_info = entry->ctrl_info;

	atm_force_charge(vcc, skb->truesize);

	sk = sk_atm(vcc);
	skb_queue_tail(&sk->sk_receive_queue, skb);
	sk->sk_data_ready(sk, skb->len);
	dprintk("mpoa: purge_egress_shortcut: exiting:\n");

	return;
}
예제 #7
0
static void mpoad_close(struct atm_vcc *vcc)
{
	struct mpoa_client *mpc;
	struct sk_buff *skb;

	mpc = find_mpc_by_vcc(vcc);
	if (mpc == NULL) {
		pr_info("did not find MPC\n");
		return;
	}
	if (!mpc->mpoad_vcc) {
		pr_info("close for non-present mpoad\n");
		return;
	}

	mpc->mpoad_vcc = NULL;
	if (mpc->dev) {
		struct lec_priv *priv = netdev_priv(mpc->dev);
		priv->lane2_ops->associate_indicator = NULL;
		stop_mpc(mpc);
		dev_put(mpc->dev);
	}

	mpc->in_ops->destroy_cache(mpc);
	mpc->eg_ops->destroy_cache(mpc);

	while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
		atm_return(vcc, skb->truesize);
		kfree_skb(skb);
	}

	pr_info("(%s) going down\n",
		(mpc->dev) ? mpc->dev->name : "<unknown>");
	module_put(THIS_MODULE);
}
예제 #8
0
static void purge_vcc(struct atm_vcc *vcc)
{
	if (sk_atm(vcc)->sk_family == PF_ATMSVC &&
	    !test_bit(ATM_VF_META, &vcc->flags)) {
		set_bit(ATM_VF_RELEASED, &vcc->flags);
		clear_bit(ATM_VF_REGIS, &vcc->flags);
		vcc_release_async(vcc, -EUNATCH);
	}
}
예제 #9
0
static void atm_push_raw(struct atm_vcc *vcc, struct sk_buff *skb)
{
	if (skb) {
		struct sock *sk = sk_atm(vcc);

		skb_queue_tail(&sk->sk_receive_queue, skb);
		sk->sk_data_ready(sk, skb->len);
	}
}
예제 #10
0
static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
{
	struct sock *sk = sk_atm(vcc);

	pr_debug("(%d) %d -= %d\n",
		 vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
	atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
	dev_kfree_skb_any(skb);
	sk->sk_write_space(sk);
}
예제 #11
0
파일: common.c 프로젝트: CSCLOG/beaglebone
void vcc_release_async(struct atm_vcc *vcc, int reply)
{
	struct sock *sk = sk_atm(vcc);

	set_bit(ATM_VF_CLOSE, &vcc->flags);
	sk->sk_shutdown |= RCV_SHUTDOWN;
	sk->sk_err = -reply;
	clear_bit(ATM_VF_WAITING, &vcc->flags);
	sk->sk_state_change(sk);
}
예제 #12
0
static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb)
{

	struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
	struct k_message *mesg = (struct k_message *)skb->data;
	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);

	if (mpc == NULL) {
		pr_info("no mpc found\n");
		return 0;
	}
	dprintk("(%s)", mpc->dev ? mpc->dev->name : "<unknown>");
	switch (mesg->type) {
	case MPOA_RES_REPLY_RCVD:
		dprintk_cont("mpoa_res_reply_rcvd\n");
		MPOA_res_reply_rcvd(mesg, mpc);
		break;
	case MPOA_TRIGGER_RCVD:
		dprintk_cont("mpoa_trigger_rcvd\n");
		MPOA_trigger_rcvd(mesg, mpc);
		break;
	case INGRESS_PURGE_RCVD:
		dprintk_cont("nhrp_purge_rcvd\n");
		ingress_purge_rcvd(mesg, mpc);
		break;
	case EGRESS_PURGE_RCVD:
		dprintk_cont("egress_purge_reply_rcvd\n");
		egress_purge_rcvd(mesg, mpc);
		break;
	case MPS_DEATH:
		dprintk_cont("mps_death\n");
		mps_death(mesg, mpc);
		break;
	case CACHE_IMPOS_RCVD:
		dprintk_cont("cache_impos_rcvd\n");
		MPOA_cache_impos_rcvd(mesg, mpc);
		break;
	case SET_MPC_CTRL_ADDR:
		dprintk_cont("set_mpc_ctrl_addr\n");
		set_mpc_ctrl_addr_rcvd(mesg, mpc);
		break;
	case SET_MPS_MAC_ADDR:
		dprintk_cont("set_mps_mac_addr\n");
		set_mps_mac_addr_rcvd(mesg, mpc);
		break;
	case CLEAN_UP_AND_EXIT:
		dprintk_cont("clean_up_and_exit\n");
		clean_up(mesg, mpc, DIE);
		break;
	case RELOAD:
		dprintk_cont("reload\n");
		clean_up(mesg, mpc, RELOAD);
		break;
	case SET_MPC_PA
예제 #13
0
static void sigd_close(struct atm_vcc *vcc)
{
	struct sock *s;
	int i;

	pr_debug("\n");
	sigd = NULL;
	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
		pr_err("closing with requests pending\n");
	skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);

	read_lock(&vcc_sklist_lock);
	for (i = 0; i < VCC_HTABLE_SIZE; ++i) {
		struct hlist_head *head = &vcc_hash[i];

		sk_for_each(s, head) {
			vcc = atm_sk(s);

			purge_vcc(vcc);
		}
	}
예제 #14
0
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;
}
예제 #15
0
int sigd_attach(struct atm_vcc *vcc)
{
	if (sigd) return -EADDRINUSE;
	DPRINTK("sigd_attach\n");
	sigd = vcc;
	vcc->dev = &sigd_dev;
	vcc_insert_socket(sk_atm(vcc));
	set_bit(ATM_VF_META,&vcc->flags);
	set_bit(ATM_VF_READY,&vcc->flags);
#ifdef WAIT_FOR_DEMON
	wake_up(&sigd_sleep);
#endif
	return 0;
}
예제 #16
0
static void sigd_put_skb(struct sk_buff *skb)
{
#ifdef WAIT_FOR_DEMON
	DECLARE_WAITQUEUE(wait,current);

	add_wait_queue(&sigd_sleep,&wait);
	while (!sigd) {
		set_current_state(TASK_UNINTERRUPTIBLE);
		pr_debug("atmsvc: waiting for signaling demon...\n");
		schedule();
	}
	current->state = TASK_RUNNING;
	remove_wait_queue(&sigd_sleep,&wait);
#else
	if (!sigd) {
		pr_debug("atmsvc: no signaling demon\n");
		kfree_skb(skb);
		return;
	}
#endif
	atm_force_charge(sigd,skb->truesize);
	skb_queue_tail(&sk_atm(sigd)->sk_receive_queue,skb);
	sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len);
}
예제 #17
0
static void sigd_close(struct atm_vcc *vcc)
{
	struct hlist_node *node;
	struct sock *s;
	int i;

	DPRINTK("sigd_close\n");
	sigd = NULL;
	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
		printk(KERN_ERR "sigd_close: closing with requests pending\n");
	skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);

	read_lock(&vcc_sklist_lock);
	for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
		struct hlist_head *head = &vcc_hash[i];

		sk_for_each(s, node, head) {
			struct atm_vcc *vcc = atm_sk(s);

			purge_vcc(vcc);
		}
	}
	read_unlock(&vcc_sklist_lock);
}
예제 #18
0
파일: common.c 프로젝트: CSCLOG/beaglebone
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
{
	struct sk_buff *skb;
	struct sock *sk = sk_atm(vcc);

	if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
		pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
			 sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
		return NULL;
	}
	while (!(skb = alloc_skb(size, GFP_KERNEL)))
		schedule();
	pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
	atomic_add(skb->truesize, &sk->sk_wmem_alloc);
	return skb;
}
예제 #19
0
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
	struct sock *sk = sk_atm(vcc);
	DEFINE_WAIT(wait);

	set_bit(ATM_VF_WAITING, &vcc->flags);
	prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
	sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
	while (test_bit(ATM_VF_WAITING, &vcc->flags) &&
	       !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
		schedule();
		prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
	}
	finish_wait(sk->sk_sleep, &wait);
	if (!sigd) return -EUNATCH;
	return -sk->sk_err;
}
예제 #20
0
struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size,
				 gfp_t gfp_flags)
{
	struct sock *sk = sk_atm(vcc);
	int guess = atm_guess_pdu2truesize(pdu_size);

	atm_force_charge(vcc, guess);
	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
		struct sk_buff *skb = alloc_skb(pdu_size, gfp_flags);

		if (skb) {
			atomic_add(skb->truesize-guess,
				   &sk->sk_rmem_alloc);
			return skb;
		}
	}
	atm_return(vcc, guess);
	atomic_inc(&vcc->stats->rx_drop);
	return NULL;
}
예제 #21
0
static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
{
	struct sock *sk;
	struct atmarp_ctrl *ctrl;
	struct sk_buff *skb;

	DPRINTK("to_atmarpd(%d)\n",type);
	if (!atmarpd) return -EUNATCH;
	skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC);
	if (!skb) return -ENOMEM;
	ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl));
	ctrl->type = type;
	ctrl->itf_num = itf;
	ctrl->ip = ip;
	atm_force_charge(atmarpd,skb->truesize);

	sk = sk_atm(atmarpd);
	skb_queue_tail(&sk->sk_receive_queue, skb);
	sk->sk_data_ready(sk, skb->len);
	return 0;
}
예제 #22
0
static int clip_mkip(struct atm_vcc *vcc,int timeout)
{
	struct clip_vcc *clip_vcc;
	struct sk_buff_head copy;
	struct sk_buff *skb;

	if (!vcc->push) return -EBADFD;
	clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL);
	if (!clip_vcc) return -ENOMEM;
	DPRINTK("mkip clip_vcc %p vcc %p\n",clip_vcc,vcc);
	clip_vcc->vcc = vcc;
	vcc->user_back = clip_vcc;
	set_bit(ATM_VF_IS_CLIP, &vcc->flags);
	clip_vcc->entry = NULL;
	clip_vcc->xoff = 0;
	clip_vcc->encap = 1;
	clip_vcc->last_use = jiffies;
	clip_vcc->idle_timeout = timeout*HZ;
	clip_vcc->old_push = vcc->push;
	clip_vcc->old_pop = vcc->pop;
	vcc->push = clip_push;
	vcc->pop = clip_pop;
	skb_queue_head_init(&copy);
	skb_migrate(&sk_atm(vcc)->sk_receive_queue, &copy);
	/* re-process everything received between connection setup and MKIP */
	while ((skb = skb_dequeue(&copy)) != NULL)
		if (!clip_devs) {
			atm_return(vcc,skb->truesize);
			kfree_skb(skb);
		}
		else {
			unsigned int len = skb->len;

			clip_push(vcc,skb);
			PRIV(skb->dev)->stats.rx_packets--;
			PRIV(skb->dev)->stats.rx_bytes -= len;
		}
	return 0;
}
예제 #23
0
/* Remember that this function may not do things that sleep */
int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)
{
	struct sk_buff *skb;
	struct sock *sk;

	if (mpc == NULL || !mpc->mpoad_vcc) {
		printk("mpoa: msg_to_mpoad: mesg %d to a non-existent mpoad\n", mesg->type);
		return -ENXIO;
	}

	skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
	if (skb == NULL)
		return -ENOMEM;
	skb_put(skb, sizeof(struct k_message));
	memcpy(skb->data, mesg, sizeof(struct k_message));
	atm_force_charge(mpc->mpoad_vcc, skb->truesize);
	
	sk = sk_atm(mpc->mpoad_vcc);
	skb_queue_tail(&sk->sk_receive_queue, skb);
	sk->sk_data_ready(sk, skb->len);

	return 0;
}
예제 #24
0
static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
{
	struct mpoa_client *mpc;
	struct lec_priv *priv;
	int err;
	
	if (mpcs == NULL) {
		init_timer(&mpc_timer);
		mpc_timer_refresh();

		/* This lets us now how our LECs are doing */
		err = register_netdevice_notifier(&mpoa_notifier);
		if (err < 0) {
			del_timer(&mpc_timer);
			return err;
		}
	}
	
	mpc = find_mpc_by_itfnum(arg);
	if (mpc == NULL) {
		dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
		mpc = alloc_mpc();
		if (mpc == NULL)
			return -ENOMEM;
		mpc->dev_num = arg;
		mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
	}
	if (mpc->mpoad_vcc) {
		printk("mpoa: mpoad_attach: mpoad is already present for itf %d\n", arg);
		return -EADDRINUSE;
	}

	if (mpc->dev) { /* check if the lec is LANE2 capable */
		priv = (struct lec_priv *)mpc->dev->priv;
		if (priv->lane_version < 2) {
			dev_put(mpc->dev);
			mpc->dev = NULL;
		} else
			priv->lane2_ops->associate_indicator = lane2_assoc_ind;  
	}

	mpc->mpoad_vcc = vcc;
	vcc->dev = &mpc_dev;
	vcc_insert_socket(sk_atm(vcc));
	set_bit(ATM_VF_META,&vcc->flags);
	set_bit(ATM_VF_READY,&vcc->flags);

	if (mpc->dev) {
		char empty[ATM_ESA_LEN];
		memset(empty, 0, ATM_ESA_LEN);
		
		start_mpc(mpc, mpc->dev);
		/* set address if mpcd e.g. gets killed and restarted.
		 * If we do not do it now we have to wait for the next LE_ARP
		 */
		if ( memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0 )
			send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
	}

	__module_get(THIS_MODULE);
	return arg;
}
예제 #25
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;
}
예제 #26
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;
}
예제 #27
0
static int clip_mkip(struct atm_vcc *vcc, int timeout)
{
	struct clip_vcc *clip_vcc;
	struct sk_buff *skb;
	struct sk_buff_head *rq;
	unsigned long flags;

	if (!vcc->push)
		return -EBADFD;
	clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL);
	if (!clip_vcc)
		return -ENOMEM;
	DPRINTK("mkip clip_vcc %p vcc %p\n", clip_vcc, vcc);
	clip_vcc->vcc = vcc;
	vcc->user_back = clip_vcc;
	set_bit(ATM_VF_IS_CLIP, &vcc->flags);
	clip_vcc->entry = NULL;
	clip_vcc->xoff = 0;
	clip_vcc->encap = 1;
	clip_vcc->last_use = jiffies;
	clip_vcc->idle_timeout = timeout * HZ;
	clip_vcc->old_push = vcc->push;
	clip_vcc->old_pop = vcc->pop;
	vcc->push = clip_push;
	vcc->pop = clip_pop;

	rq = &sk_atm(vcc)->sk_receive_queue;

	spin_lock_irqsave(&rq->lock, flags);
	if (skb_queue_empty(rq)) {
		skb = NULL;
	} else {
		/* NULL terminate the list.  */
		rq->prev->next = NULL;
		skb = rq->next;
	}
	rq->prev = rq->next = (struct sk_buff *)rq;
	rq->qlen = 0;
	spin_unlock_irqrestore(&rq->lock, flags);

	/* re-process everything received between connection setup and MKIP */
	while (skb) {
		struct sk_buff *next = skb->next;

		skb->next = skb->prev = NULL;
		if (!clip_devs) {
			atm_return(vcc, skb->truesize);
			kfree_skb(skb);
		} else {
			unsigned int len = skb->len;

			skb_get(skb);
			clip_push(vcc, skb);
			PRIV(skb->dev)->stats.rx_packets--;
			PRIV(skb->dev)->stats.rx_bytes -= len;
			kfree_skb(skb);
		}

		skb = next;
	}
	return 0;
}
예제 #28
0
static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
{
	struct sock *sk = sock->sk;
	struct sk_buff *skb;
	struct atmsvc_msg *msg;
	struct atm_vcc *old_vcc = ATM_SD(sock);
	struct atm_vcc *new_vcc;
	int error;

	lock_sock(sk);

	error = svc_create(newsock,0);
	if (error)
		goto out;

	new_vcc = ATM_SD(newsock);

	DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc);
	while (1) {
		DEFINE_WAIT(wait);

		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
		while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
		       sigd) {
			if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
			if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
				error = -sk->sk_err;
				break;
			}
			if (flags & O_NONBLOCK) {
				error = -EAGAIN;
				break;
			}
			release_sock(sk);
			schedule();
			lock_sock(sk);
			if (signal_pending(current)) {
				error = -ERESTARTSYS;
				break;
			}
			prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
		}
		finish_wait(sk->sk_sleep, &wait);
		if (error)
			goto out;
		if (!skb) {
			error = -EUNATCH;
			goto out;
		}
		msg = (struct atmsvc_msg *) skb->data;
		new_vcc->qos = msg->qos;
		set_bit(ATM_VF_HASQOS,&new_vcc->flags);
		new_vcc->remote = msg->svc;
		new_vcc->local = msg->local;
		new_vcc->sap = msg->sap;
		error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
				    msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci);
		dev_kfree_skb(skb);
		sk->sk_ack_backlog--;
		if (error) {
			sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
			    &old_vcc->qos,error);
			error = error == -EAGAIN ? -EBUSY : error;
			goto out;
		}
		/* wait should be short, so we ignore the non-blocking flag */
		set_bit(ATM_VF_WAITING, &new_vcc->flags);
		prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
		while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) {
			release_sock(sk);
			schedule();
			lock_sock(sk);
			prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
		}
		finish_wait(sk_atm(new_vcc)->sk_sleep, &wait);
		if (!sigd) {
			error = -EUNATCH;
			goto out;
		}
		if (!sk_atm(new_vcc)->sk_err)
			break;
		if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) {
			error = -sk_atm(new_vcc)->sk_err;
			goto out;
		}
	}
	newsock->state = SS_CONNECTED;
out:
	release_sock(sk);
	return error;
}
예제 #29
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;
}
예제 #30
0
static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
{
	struct atmsvc_msg *msg;
	struct atm_vcc *session_vcc;
	struct sock *sk;

	msg = (struct atmsvc_msg *) skb->data;
	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
	DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,
	  (unsigned long) msg->vcc);
	vcc = *(struct atm_vcc **) &msg->vcc;
	sk = sk_atm(vcc);

	switch (msg->type) {
		case as_okay:
			sk->sk_err = -msg->reply;
			clear_bit(ATM_VF_WAITING, &vcc->flags);
			if (!*vcc->local.sas_addr.prv &&
			    !*vcc->local.sas_addr.pub) {
				vcc->local.sas_family = AF_ATMSVC;
				memcpy(vcc->local.sas_addr.prv,
				    msg->local.sas_addr.prv,ATM_ESA_LEN);
				memcpy(vcc->local.sas_addr.pub,
				    msg->local.sas_addr.pub,ATM_E164_LEN+1);
			}
			session_vcc = vcc->session ? vcc->session : vcc;
			if (session_vcc->vpi || session_vcc->vci) break;
			session_vcc->itf = msg->pvc.sap_addr.itf;
			session_vcc->vpi = msg->pvc.sap_addr.vpi;
			session_vcc->vci = msg->pvc.sap_addr.vci;
			if (session_vcc->vpi || session_vcc->vci)
				session_vcc->qos = msg->qos;
			break;
		case as_error:
			clear_bit(ATM_VF_REGIS,&vcc->flags);
			clear_bit(ATM_VF_READY,&vcc->flags);
			sk->sk_err = -msg->reply;
			clear_bit(ATM_VF_WAITING, &vcc->flags);
			break;
		case as_indicate:
			vcc = *(struct atm_vcc **) &msg->listen_vcc;
			sk = sk_atm(vcc);
			DPRINTK("as_indicate!!!\n");
			lock_sock(sk);
			if (sk_acceptq_is_full(sk)) {
				sigd_enq(NULL,as_reject,vcc,NULL,NULL);
				dev_kfree_skb(skb);
				goto as_indicate_complete;
			}
			sk->sk_ack_backlog++;
			skb_queue_tail(&sk->sk_receive_queue, skb);
			DPRINTK("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
			sk->sk_state_change(sk);
as_indicate_complete:
			release_sock(sk);
			return 0;
		case as_close:
			set_bit(ATM_VF_RELEASED,&vcc->flags);
			vcc_release_async(vcc, msg->reply);
			goto out;
		case as_modify:
			modify_qos(vcc,msg);
			break;
		case as_addparty:
		case as_dropparty:
			sk->sk_err_soft = msg->reply;	/* < 0 failure, otherwise ep_ref */
			clear_bit(ATM_VF_WAITING, &vcc->flags);
			break;
		default:
			printk(KERN_ALERT "sigd_send: bad message type %d\n",
			    (int) msg->type);
			return -EINVAL;
	}
	sk->sk_state_change(sk);
out:
	dev_kfree_skb(skb);
	return 0;
}