예제 #1
0
/**
 * dn_route_rx_packet - Try and find a route for an incoming packet
 * @skb: The packet to find a route for
 *
 * Returns: result of input function if route is found, error code otherwise
 */
static int dn_route_rx_packet(struct sk_buff *skb)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	int err;

	if ((err = dn_route_input(skb)) == 0)
		return dst_input(skb);

	if (decnet_debug_level & 4) {
		char *devname = skb->dev ? skb->dev->name : "???";
		struct dn_skb_cb *cb = DN_SKB_CB(skb);
		printk(KERN_DEBUG
			"DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
			(int)cb->rt_flags, devname, skb->len,
			dn_ntohs(cb->src), dn_ntohs(cb->dst),
			err, skb->pkt_type);
	}

	if ((skb->pkt_type == PACKET_HOST) && (cb->rt_flags & DN_RT_F_RQR)) {
		switch(cb->rt_flags & DN_RT_PKT_MSK) {
			case DN_RT_PKT_SHORT:
				return dn_return_short(skb);
			case DN_RT_PKT_LONG:
				return dn_return_long(skb);
		}
	}

	kfree_skb(skb);
	return NET_RX_DROP;
}
예제 #2
0
int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *q, unsigned short acknum)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct dn_scp *scp = DN_SK(sk);
	struct sk_buff *skb2, *n, *ack = NULL;
	int wakeup = 0;
	int try_retrans = 0;
	unsigned long reftime = cb->stamp;
	unsigned long pkttime;
	unsigned short xmit_count;
	unsigned short segnum;

	skb_queue_walk_safe(q, skb2, n) {
		struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);

		if (dn_before_or_equal(cb2->segnum, acknum))
			ack = skb2;

		

		if (ack == NULL)
			continue;

		

		
		try_retrans = 0;
		
		wakeup = 1;
		
		pkttime = cb2->stamp;
		xmit_count = cb2->xmit_count;
		segnum = cb2->segnum;
		
		skb_unlink(ack, q);
		kfree_skb(ack);
		ack = NULL;

		
		WARN_ON(xmit_count == 0);

		
		if (xmit_count == 1) {
			if (dn_equal(segnum, acknum))
				dn_nsp_rtt(sk, (long)(pkttime - reftime));

			if (scp->snd_window < scp->max_window)
				scp->snd_window++;
		}

		
		if (xmit_count > 1)
			try_retrans = 1;
	}

	if (try_retrans)
		dn_nsp_output(sk);

	return wakeup;
}
예제 #3
0
static int dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	int ret = NET_RX_DROP;

	
	if (cb->rt_flags & DN_RT_F_RTS)
		goto out;

	if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
		switch(cb->nsp_flags & 0x70) {
			case 0x10:
			case 0x60: 
				dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
				ret = NET_RX_SUCCESS;
				break;
			case 0x20: 
				dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
				ret = NET_RX_SUCCESS;
				break;
		}
	}

out:
	kfree_skb(skb);
	return ret;
}
예제 #4
0
static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
{
	struct dn_scp *scp = DN_SK(sk);
	unsigned short segnum;
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	int queued = 0;

	if (skb->len < 2)
		goto out;

	cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
	skb_pull(skb, 2);

	if (seq_next(scp->numoth_rcv, segnum)) {

		if (dn_queue_skb(sk, skb, SIGURG, &scp->other_receive_queue) == 0) {
			seq_add(&scp->numoth_rcv, 1);
			scp->other_report = 0;
			queued = 1;
		}
	}

	dn_nsp_send_oth_ack(sk);
out:
	if (!queued)
		kfree_skb(skb);
}
예제 #5
0
static int dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	int ret = NET_RX_DROP;

	/* Must not reply to returned packets */
	if (cb->rt_flags & DN_RT_F_RTS)
		goto out;

	if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
		switch (cb->nsp_flags & 0x70) {
		case 0x10:
		case 0x60: /* (Retransmitted) Connect Init */
			dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
			ret = NET_RX_SUCCESS;
			break;
		case 0x20: /* Connect Confirm */
			dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
			ret = NET_RX_SUCCESS;
			break;
		}
	}

out:
	kfree_skb(skb);
	return ret;
}
예제 #6
0
/**
 * dn_return_short - Return a short packet to its sender
 * @skb: The packet to return
 *
 */
static int dn_return_short(struct sk_buff *skb)
{
	struct dn_skb_cb *cb;
	unsigned char *ptr;
	__le16 *src;
	__le16 *dst;
	__le16 tmp;

	/* Add back headers */
	skb_push(skb, skb->data - skb->nh.raw);

	if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL)
		return NET_RX_DROP;

	cb = DN_SKB_CB(skb);
	/* Skip packet length and point to flags */
	ptr = skb->data + 2;
	*ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS;

	dst = (__le16 *)ptr;
	ptr += 2;
	src = (__le16 *)ptr;
	ptr += 2;
	*ptr = 0; /* Zero hop count */

	/* Swap source and destination */
	tmp  = *src;
	*src = *dst;
	*dst = tmp;

	skb->pkt_type = PACKET_OUTGOING;
	dn_rt_finish_output(skb, NULL, NULL);
	return NET_RX_SUCCESS;
}
예제 #7
0
static void dn_nsp_data(struct sock *sk, struct sk_buff *skb)
{
	int queued = 0;
	unsigned short segnum;
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct dn_scp *scp = DN_SK(sk);

	if (skb->len < 2)
		goto out;

	cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
	skb_pull(skb, 2);

	if (seq_next(scp->numdat_rcv, segnum)) {
		if (dn_queue_skb(sk, skb, SIGIO, &sk->sk_receive_queue) == 0) {
			seq_add(&scp->numdat_rcv, 1);
			queued = 1;
		}

		if ((scp->flowloc_sw == DN_SEND) && dn_congested(sk)) {
			scp->flowloc_sw = DN_DONTSEND;
			dn_nsp_send_link(sk, DN_DONTSEND, 0);
		}
	}

	dn_nsp_send_data_ack(sk);
out:
	if (!queued)
		kfree_skb(skb);
}
예제 #8
0
static int dn_route_rx_long(struct sk_buff *skb)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	unsigned char *ptr = skb->data;

	if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */
		goto drop_it;

	skb_pull(skb, 20);
	skb->h.raw = skb->data;

        /* Destination info */
        ptr += 2;
	cb->dst = dn_eth2dn(ptr);
        if (memcmp(ptr, dn_hiord_addr, 4) != 0)
                goto drop_it;
        ptr += 6;


        /* Source info */
        ptr += 2;
	cb->src = dn_eth2dn(ptr);
        if (memcmp(ptr, dn_hiord_addr, 4) != 0)
                goto drop_it;
        ptr += 6;
        /* Other junk */
        ptr++;
        cb->hops = *ptr++; /* Visit Count */

	return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet);

drop_it:
	kfree_skb(skb);
	return NET_RX_DROP;
}
예제 #9
0
int dn_route_input(struct sk_buff *skb)
{
	struct dn_route *rt;
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	unsigned hash = dn_hash(cb->src, cb->dst);

	if (skb->dst)
		return 0;

	rcu_read_lock();
	for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL;
	    rt = rcu_dereference(rt->u.rt_next)) {
		if ((rt->fl.fld_src == cb->src) &&
	 	    (rt->fl.fld_dst == cb->dst) &&
		    (rt->fl.oif == 0) &&
#ifdef CONFIG_DECNET_ROUTE_FWMARK
		    (rt->fl.fld_fwmark == skb->nfmark) &&
#endif
		    (rt->fl.iif == cb->iif)) {
			rt->u.dst.lastuse = jiffies;
			dst_hold(&rt->u.dst);
			rt->u.dst.__use++;
			rcu_read_unlock();
			skb->dst = (struct dst_entry *)rt;
			return 0;
		}
	}
	rcu_read_unlock();

	return dn_route_input_slow(skb);
}
예제 #10
0
void dn_nsp_queue_xmit(struct sock *sk, struct sk_buff *skb,
			gfp_t gfp, int oth)
{
	struct dn_scp *scp = DN_SK(sk);
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	unsigned long t = ((scp->nsp_srtt >> 2) + scp->nsp_rttvar) >> 1;

	cb->xmit_count = 0;
	dn_nsp_mk_data_header(sk, skb, oth);

	/*
	 * Slow start: If we have been idle for more than
	 * one RTT, then reset window to min size.
	 */
	if ((jiffies - scp->stamp) > t)
		scp->snd_window = NSP_MIN_WINDOW;

	if (oth)
		skb_queue_tail(&scp->other_xmit_queue, skb);
	else
		skb_queue_tail(&scp->data_xmit_queue, skb);

	if (scp->flowrem_sw != DN_SEND)
		return;

	dn_nsp_clone_and_send(skb, gfp);
}
예제 #11
0
파일: dn_nsp_in.c 프로젝트: Mr-Aloof/wl500g
static void dn_log_martian(struct sk_buff *skb, const char *msg)
{
	if (decnet_log_martians && net_ratelimit()) {
		char *devname = skb->dev ? skb->dev->name : "???";
		struct dn_skb_cb *cb = DN_SKB_CB(skb);
		printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, dn_ntohs(cb->src), dn_ntohs(cb->dst), dn_ntohs(cb->src_port), dn_ntohs(cb->dst_port));
	}
}
예제 #12
0
static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
{
	struct dn_scp *scp = DN_SK(sk);
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	unsigned short reason;

	if (skb->len < 2)
		goto out;

	reason = le16_to_cpu(*(__le16 *)skb->data);
	skb_pull(skb, 2);

	scp->discdata_in.opt_status = cpu_to_le16(reason);
	scp->discdata_in.opt_optl   = 0;
	memset(scp->discdata_in.opt_data, 0, 16);

	if (skb->len > 0) {
		u16 dlen = *skb->data;
		if ((dlen <= 16) && (dlen <= skb->len)) {
			scp->discdata_in.opt_optl = cpu_to_le16(dlen);
			skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen);
		}
	}

	scp->addrrem = cb->src_port;
	sk->sk_state = TCP_CLOSE;

	switch(scp->state) {
		case DN_CI:
		case DN_CD:
			scp->state = DN_RJ;
			sk->sk_err = ECONNREFUSED;
			break;
		case DN_RUN:
			sk->sk_shutdown |= SHUTDOWN_MASK;
			scp->state = DN_DN;
			break;
		case DN_DI:
			scp->state = DN_DIC;
			break;
	}

	if (!sock_flag(sk, SOCK_DEAD)) {
		if (sk->sk_socket->state != SS_UNCONNECTED)
			sk->sk_socket->state = SS_DISCONNECTING;
		sk->sk_state_change(sk);
	}

	
	if (scp->addrrem) {
		dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
	}
	scp->persist_fxn = dn_destroy_timer;
	scp->persist = dn_nsp_persist(sk);

out:
	kfree_skb(skb);
}
예제 #13
0
void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
			unsigned short reason)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	int ddl = 0;
	gfp_t gfp = GFP_ATOMIC;

	dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb_dst(skb), ddl,
			NULL, cb->src_port, cb->dst_port);
}
예제 #14
0
static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
{
	struct dn_scp *scp = DN_SK(sk);
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	unsigned short reason;

	if (skb->len < 2)
		goto out;

	reason = dn_ntohs(*(__u16 *)skb->data);
	skb_pull(skb, 2);

	scp->discdata_in.opt_status = reason;
	scp->discdata_in.opt_optl   = 0;
	memset(scp->discdata_in.opt_data, 0, 16);

	if (skb->len > 0) {
		unsigned char dlen = *skb->data;
		if ((dlen <= 16) && (dlen <= skb->len)) {
			scp->discdata_in.opt_optl = dlen;
			memcpy(scp->discdata_in.opt_data, skb->data + 1, dlen);
		}
	}

	scp->addrrem = cb->src_port;
	sk->state    = TCP_CLOSE;

	switch(scp->state) {
		case DN_CI:
		case DN_CD:
			scp->state = DN_RJ;
			break;
		case DN_RUN:
			sk->shutdown |= SHUTDOWN_MASK;
			scp->state = DN_DN;
			break;
		case DN_DI:
			scp->state = DN_DIC;
			break;
	}

	if (!sk->dead) {
		if (sk->socket->state != SS_UNCONNECTED)
			sk->socket->state = SS_DISCONNECTING;
		sk->state_change(sk);
	}

	dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
	scp->persist_fxn = dn_destroy_timer;
	scp->persist = dn_nsp_persist(sk);

out:
	kfree_skb(skb);
}
예제 #15
0
/*
 * Used to catch bugs. This should never normally get
 * called.
 */
static int dn_rt_bug(struct sk_buff *skb)
{
	if (net_ratelimit()) {
		struct dn_skb_cb *cb = DN_SKB_CB(skb);

		printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n",
				dn_ntohs(cb->src), dn_ntohs(cb->dst));
	}

	kfree_skb(skb);

	return NET_RX_BAD;
}
예제 #16
0
static void dn_log_martian(struct sk_buff *skb, const char *msg)
{
	if (decnet_log_martians) {
		char *devname = skb->dev ? skb->dev->name : "???";
		struct dn_skb_cb *cb = DN_SKB_CB(skb);
		net_info_ratelimited("DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
				     msg, devname,
				     le16_to_cpu(cb->src),
				     le16_to_cpu(cb->dst),
				     le16_to_cpu(cb->src_port),
				     le16_to_cpu(cb->dst_port));
	}
}
예제 #17
0
static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb,
					     gfp_t gfp)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct sk_buff *skb2;
	int ret = 0;

	if ((skb2 = skb_clone(skb, gfp)) != NULL) {
		ret = cb->xmit_count;
		cb->xmit_count++;
		cb->stamp = jiffies;
		skb2->sk = skb->sk;
		dn_nsp_send(skb2);
	}

	return ret;
}
예제 #18
0
static __le16 *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth)
{
	struct dn_scp *scp = DN_SK(sk);
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	__le16 *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth);

	if (unlikely(oth)) {
		cb->segnum = scp->numoth;
		seq_add(&scp->numoth, 1);
	} else {
		cb->segnum = scp->numdat;
		seq_add(&scp->numdat, 1);
	}
	*(ptr++) = cpu_to_le16(cb->segnum);

	return ptr;
}
예제 #19
0
static int dn_long_output(struct sk_buff *skb)
{
    struct dst_entry *dst = skb->dst;
    struct neighbour *neigh = dst->neighbour;
    struct net_device *dev = neigh->dev;
    int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
    unsigned char *data;
    struct dn_long_packet *lp;
    struct dn_skb_cb *cb = DN_SKB_CB(skb);


    if (skb_headroom(skb) < headroom) {
        struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
        if (skb2 == NULL) {
            if (net_ratelimit())
                printk(KERN_CRIT "dn_long_output: no memory\n");
            kfree_skb(skb);
            return -ENOBUFS;
        }
        kfree_skb(skb);
        skb = skb2;
        if (net_ratelimit())
            printk(KERN_INFO "dn_long_output: Increasing headroom\n");
    }

    data = skb_push(skb, sizeof(struct dn_long_packet) + 3);
    lp = (struct dn_long_packet *)(data+3);

    *((unsigned short *)data) = dn_htons(skb->len - 2);
    *(data + 2) = 1 | DN_RT_F_PF; /* Padding */

    lp->msgflg   = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS));
    lp->d_area   = lp->d_subarea = 0;
    dn_dn2eth(lp->d_id, dn_ntohs(cb->dst));
    lp->s_area   = lp->s_subarea = 0;
    dn_dn2eth(lp->s_id, dn_ntohs(cb->src));
    lp->nl2      = 0;
    lp->visit_ct = cb->hops & 0x3f;
    lp->s_class  = 0;
    lp->pt       = 0;

    skb->nh.raw = skb->data;

    return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
}
예제 #20
0
static int dn_forward(struct sk_buff *skb)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct dst_entry *dst = skb->dst;
	struct dn_dev *dn_db = dst->dev->dn_ptr;
	struct dn_route *rt;
	struct neighbour *neigh = dst->neighbour;
	int header_len;
#ifdef CONFIG_NETFILTER
	struct net_device *dev = skb->dev;
#endif

	if (skb->pkt_type != PACKET_HOST)
		goto drop;

	/* Ensure that we have enough space for headers */
	rt = (struct dn_route *)skb->dst;
	header_len = dn_db->use_long ? 21 : 6;
	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len))
		goto drop;

	/*
	 * Hop count exceeded.
	 */
	if (++cb->hops > 30)
		goto drop;

	skb->dev = rt->u.dst.dev;

	/*
	 * If packet goes out same interface it came in on, then set
	 * the Intra-Ethernet bit. This has no effect for short
	 * packets, so we don't need to test for them here.
	 */
	cb->rt_flags &= ~DN_RT_F_IE;
	if (rt->rt_flags & RTCF_DOREDIRECT)
		cb->rt_flags |= DN_RT_F_IE;

	return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);

drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}
예제 #21
0
static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct dn_scp *scp = DN_SK(sk);
	unsigned char *ptr;

	if (skb->len < 4)
		goto out;

	ptr = skb->data;
	cb->services = *ptr++;
	cb->info = *ptr++;
	cb->segsize = le16_to_cpu(*(__le16 *)ptr);

	if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
		scp->persist = 0;
		scp->addrrem = cb->src_port;
		sk->sk_state = TCP_ESTABLISHED;
		scp->state = DN_RUN;
		scp->services_rem = cb->services;
		scp->info_rem = cb->info;
		scp->segsize_rem = cb->segsize;

		if ((scp->services_rem & NSP_FC_MASK) == NSP_FC_NONE)
			scp->max_window = decnet_no_fc_max_cwnd;

		if (skb->len > 0) {
			u16 dlen = *skb->data;
			if ((dlen <= 16) && (dlen <= skb->len)) {
				scp->conndata_in.opt_optl = cpu_to_le16(dlen);
				skb_copy_from_linear_data_offset(skb, 1,
					      scp->conndata_in.opt_data, dlen);
			}
		}
		dn_nsp_send_link(sk, DN_NOCHANGE, 0);
		if (!sock_flag(sk, SOCK_DEAD))
			sk->sk_state_change(sk);
	}

out:
	kfree_skb(skb);
}
예제 #22
0
static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct dn_scp *scp = DN_SK(sk);
	unsigned char *ptr;

	if (skb->len < 4)
		goto out;

	ptr = skb->data;
	cb->services = *ptr++;
	cb->info = *ptr++;
	cb->segsize = dn_ntohs(*(__u16 *)ptr);

	if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
		scp->persist = 0;
                scp->addrrem = cb->src_port;
                sk->state = TCP_ESTABLISHED;
                scp->state = DN_RUN;
		scp->services_rem = cb->services;
		scp->info_rem = cb->info;
		scp->segsize_rem = cb->segsize;

		if ((scp->services_rem & NSP_FC_MASK) == NSP_FC_NONE)
			scp->max_window = decnet_no_fc_max_cwnd;

		if (skb->len > 0) {
			unsigned char dlen = *skb->data;
			if ((dlen <= 16) && (dlen <= skb->len)) {
				scp->conndata_in.opt_optl = dlen;
				memcpy(scp->conndata_in.opt_data, skb->data + 1, dlen);
			}
		}
                dn_nsp_send_link(sk, DN_NOCHANGE, 0);
                if (!sk->dead)
                	sk->state_change(sk);
        }

out:
        kfree_skb(skb);
}
예제 #23
0
void dn_nsp_send_link(struct sock *sk, unsigned char lsflags, char fcval)
{
	struct dn_scp *scp = DN_SK(sk);
	struct sk_buff *skb;
	unsigned char *ptr;
	gfp_t gfp = GFP_ATOMIC;

	if ((skb = dn_alloc_skb(sk, DN_MAX_NSP_DATA_HEADER + 2, gfp)) == NULL)
		return;

	skb_reserve(skb, DN_MAX_NSP_DATA_HEADER);
	ptr = skb_put(skb, 2);
	DN_SKB_CB(skb)->nsp_flags = 0x10;
	*ptr++ = lsflags;
	*ptr = fcval;

	dn_nsp_queue_xmit(sk, skb, gfp, 1);

	scp->persist = dn_nsp_persist(sk);
	scp->persist_fxn = dn_nsp_xmit_timeout;
}
예제 #24
0
/**
 * dn_return_long - Return a long packet to its sender
 * @skb: The long format packet to return
 *
 */
static int dn_return_long(struct sk_buff *skb)
{
	struct dn_skb_cb *cb;
	unsigned char *ptr;
	unsigned char *src_addr, *dst_addr;
	unsigned char tmp[ETH_ALEN];

	/* Add back all headers */
	skb_push(skb, skb->data - skb->nh.raw);

	if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL)
		return NET_RX_DROP;

	cb = DN_SKB_CB(skb);
	/* Ignore packet length and point to flags */
	ptr = skb->data + 2;

	/* Skip padding */
	if (*ptr & DN_RT_F_PF) {
		char padlen = (*ptr & ~DN_RT_F_PF);
		ptr += padlen;
	}

	*ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS;
	ptr += 2;
	dst_addr = ptr;
	ptr += 8;
	src_addr = ptr;
	ptr += 6;
	*ptr = 0; /* Zero hop count */

	/* Swap source and destination */
	memcpy(tmp, src_addr, ETH_ALEN);
	memcpy(src_addr, dst_addr, ETH_ALEN);
	memcpy(dst_addr, tmp, ETH_ALEN);

	skb->pkt_type = PACKET_OUTGOING;
	dn_rt_finish_output(skb, dst_addr, src_addr);
	return NET_RX_SUCCESS;
}
예제 #25
0
static int dn_short_output(struct sk_buff *skb)
{
    struct dst_entry *dst = skb->dst;
    struct neighbour *neigh = dst->neighbour;
    struct net_device *dev = neigh->dev;
    int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
    struct dn_short_packet *sp;
    unsigned char *data;
    struct dn_skb_cb *cb = DN_SKB_CB(skb);


    if (skb_headroom(skb) < headroom) {
        struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
        if (skb2 == NULL) {
            if (net_ratelimit())
                printk(KERN_CRIT "dn_short_output: no memory\n");
            kfree_skb(skb);
            return -ENOBUFS;
        }
        kfree_skb(skb);
        skb = skb2;
        if (net_ratelimit())
            printk(KERN_INFO "dn_short_output: Increasing headroom\n");
    }

    data = skb_push(skb, sizeof(struct dn_short_packet) + 2);
    *((unsigned short *)data) = dn_htons(skb->len - 2);
    sp = (struct dn_short_packet *)(data+2);

    sp->msgflg     = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS));
    sp->dstnode    = cb->dst;
    sp->srcnode    = cb->src;
    sp->forward    = cb->hops & 0x3f;

    skb->nh.raw = skb->data;

    return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
}
예제 #26
0
static int dn_route_rx_short(struct sk_buff *skb)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	unsigned char *ptr = skb->data;

	if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */
		goto drop_it;

	skb_pull(skb, 5);
	skb->h.raw = skb->data;

	cb->dst = *(__le16 *)ptr;
        ptr += 2;
        cb->src = *(__le16 *)ptr;
        ptr += 2;
        cb->hops = *ptr & 0x3f;

	return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet);

drop_it:
        kfree_skb(skb);
        return NET_RX_DROP;
}
예제 #27
0
static int dn_output(struct sk_buff *skb)
{
	struct dst_entry *dst = skb->dst;
	struct dn_route *rt = (struct dn_route *)dst;
	struct net_device *dev = dst->dev;
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct neighbour *neigh;

	int err = -EINVAL;

	if ((neigh = dst->neighbour) == NULL)
		goto error;

	skb->dev = dev;

	cb->src = rt->rt_saddr;
	cb->dst = rt->rt_daddr;

	/*
	 * Always set the Intra-Ethernet bit on all outgoing packets
	 * originated on this node. Only valid flag from upper layers
	 * is return-to-sender-requested. Set hop count to 0 too.
	 */
	cb->rt_flags &= ~DN_RT_F_RQR;
	cb->rt_flags |= DN_RT_F_IE;
	cb->hops = 0;

	return NF_HOOK(PF_DECnet, NF_DN_LOCAL_OUT, skb, NULL, dev, neigh->output);

error:
	if (net_ratelimit())
		printk(KERN_DEBUG "dn_output: This should not happen\n");

	kfree_skb(skb);

	return err;
}
예제 #28
0
void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
{
	struct dn_scp *scp = DN_SK(sk);
	struct nsp_conn_init_msg *msg;
	unsigned char aux;
	unsigned char menuver;
	struct dn_skb_cb *cb;
	unsigned char type = 1;
	gfp_t allocation = (msgflg == NSP_CI) ? sk->sk_allocation : GFP_ATOMIC;
	struct sk_buff *skb = dn_alloc_skb(sk, 200, allocation);

	if (!skb)
		return;

	cb  = DN_SKB_CB(skb);
	msg = (struct nsp_conn_init_msg *)skb_put(skb,sizeof(*msg));

	msg->msgflg	= msgflg;
	msg->dstaddr	= 0x0000;		/* Remote Node will assign it*/

	msg->srcaddr	= scp->addrloc;
	msg->services	= scp->services_loc;	/* Requested flow control    */
	msg->info	= scp->info_loc;	/* Version Number            */
	msg->segsize	= cpu_to_le16(scp->segsize_loc);	/* Max segment size  */

	if (scp->peer.sdn_objnum)
		type = 0;

	skb_put(skb, dn_sockaddr2username(&scp->peer,
					  skb_tail_pointer(skb), type));
	skb_put(skb, dn_sockaddr2username(&scp->addr,
					  skb_tail_pointer(skb), 2));

	menuver = DN_MENUVER_ACC | DN_MENUVER_USR;
	if (scp->peer.sdn_flags & SDF_PROXY)
		menuver |= DN_MENUVER_PRX;
	if (scp->peer.sdn_flags & SDF_UICPROXY)
		menuver |= DN_MENUVER_UIC;

	*skb_put(skb, 1) = menuver;	/* Menu Version		*/

	aux = scp->accessdata.acc_userl;
	*skb_put(skb, 1) = aux;
	if (aux > 0)
	memcpy(skb_put(skb, aux), scp->accessdata.acc_user, aux);

	aux = scp->accessdata.acc_passl;
	*skb_put(skb, 1) = aux;
	if (aux > 0)
	memcpy(skb_put(skb, aux), scp->accessdata.acc_pass, aux);

	aux = scp->accessdata.acc_accl;
	*skb_put(skb, 1) = aux;
	if (aux > 0)
	memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux);

	aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl);
	*skb_put(skb, 1) = aux;
	if (aux > 0)
	memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux);

	scp->persist = dn_nsp_persist(sk);
	scp->persist_fxn = dn_nsp_retrans_conninit;

	cb->rt_flags = DN_RT_F_RQR;

	dn_nsp_send(skb);
}
예제 #29
0
int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff_head *q, unsigned short acknum)
{
	struct dn_skb_cb *cb = DN_SKB_CB(skb);
	struct dn_scp *scp = DN_SK(sk);
	struct sk_buff *skb2, *n, *ack = NULL;
	int wakeup = 0;
	int try_retrans = 0;
	unsigned long reftime = cb->stamp;
	unsigned long pkttime;
	unsigned short xmit_count;
	unsigned short segnum;

	skb_queue_walk_safe(q, skb2, n) {
		struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);

		if (dn_before_or_equal(cb2->segnum, acknum))
			ack = skb2;

		/* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */

		if (ack == NULL)
			continue;

		/* printk(KERN_DEBUG "check_xmit_queue: %04x, %d\n", acknum, cb2->xmit_count); */

		/* Does _last_ packet acked have xmit_count > 1 */
		try_retrans = 0;
		/* Remember to wake up the sending process */
		wakeup = 1;
		/* Keep various statistics */
		pkttime = cb2->stamp;
		xmit_count = cb2->xmit_count;
		segnum = cb2->segnum;
		/* Remove and drop ack'ed packet */
		skb_unlink(ack, q);
		kfree_skb(ack);
		ack = NULL;

		/*
		 * We don't expect to see acknowledgements for packets we
		 * haven't sent yet.
		 */
		WARN_ON(xmit_count == 0);

		/*
		 * If the packet has only been sent once, we can use it
		 * to calculate the RTT and also open the window a little
		 * further.
		 */
		if (xmit_count == 1) {
			if (dn_equal(segnum, acknum))
				dn_nsp_rtt(sk, (long)(pkttime - reftime));

			if (scp->snd_window < scp->max_window)
				scp->snd_window++;
		}

		/*
		 * Packet has been sent more than once. If this is the last
		 * packet to be acknowledged then we want to send the next
		 * packet in the send queue again (assumes the remote host does
		 * go-back-N error control).
		 */
		if (xmit_count > 1)
			try_retrans = 1;
	}

	if (try_retrans)
		dn_nsp_output(sk);

	return wakeup;
}
예제 #30
0
/*
 * This is the main receive routine for sockets. It is called
 * from the above when the socket is not busy, and also from
 * sock_release() when there is a backlog queued up.
 */
int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
	struct dn_scp *scp = DN_SK(sk);
	struct dn_skb_cb *cb = DN_SKB_CB(skb);

	if (cb->rt_flags & DN_RT_F_RTS) {
		if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
			dn_returned_conn_init(sk, skb);
		else
			kfree_skb(skb);
		return NET_RX_SUCCESS;
	}

	/*
	 * Control packet.
	 */
	if ((cb->nsp_flags & 0x0c) == 0x08) {
		switch (cb->nsp_flags & 0x70) {
		case 0x10:
		case 0x60:
			dn_nsp_conn_init(sk, skb);
			break;
		case 0x20:
			dn_nsp_conn_conf(sk, skb);
			break;
		case 0x30:
			dn_nsp_disc_init(sk, skb);
			break;
		case 0x40:
			dn_nsp_disc_conf(sk, skb);
			break;
		}

	} else if (cb->nsp_flags == 0x24) {
		/*
		 * Special for connacks, 'cos they don't have
		 * ack data or ack otherdata info.
		 */
		dn_nsp_conn_ack(sk, skb);
	} else {
		int other = 1;

		/* both data and ack frames can kick a CC socket into RUN */
		if ((scp->state == DN_CC) && !sock_flag(sk, SOCK_DEAD)) {
			scp->state = DN_RUN;
			sk->sk_state = TCP_ESTABLISHED;
			sk->sk_state_change(sk);
		}

		if ((cb->nsp_flags & 0x1c) == 0)
			other = 0;
		if (cb->nsp_flags == 0x04)
			other = 0;

		/*
		 * Read out ack data here, this applies equally
		 * to data, other data, link serivce and both
		 * ack data and ack otherdata.
		 */
		dn_process_ack(sk, skb, other);

		/*
		 * If we've some sort of data here then call a
		 * suitable routine for dealing with it, otherwise
		 * the packet is an ack and can be discarded.
		 */
		if ((cb->nsp_flags & 0x0c) == 0) {

			if (scp->state != DN_RUN)
				goto free_out;

			switch (cb->nsp_flags) {
			case 0x10: /* LS */
				dn_nsp_linkservice(sk, skb);
				break;
			case 0x30: /* OD */
				dn_nsp_otherdata(sk, skb);
				break;
			default:
				dn_nsp_data(sk, skb);
			}

		} else { /* Ack, chuck it out here */
free_out:
			kfree_skb(skb);
		}
	}

	return NET_RX_SUCCESS;
}