/** * 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; }
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; }
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; }
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); }
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; }
/** * 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; }
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); }
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; }
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); }
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); }
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)); } }
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); }
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); }
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); }
/* * 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; }
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)); } }
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; }
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; }
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); }
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; }
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); }
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); }
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; }
/** * 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; }
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); }
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; }
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; }
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); }
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; }
/* * 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; }