cregit-Linux how code gets into the kernel

Release 4.14 net/decnet/dn_nsp_in.c

Directory: net/decnet
/*
 * DECnet       An implementation of the DECnet protocol suite for the LINUX
 *              operating system.  DECnet is implemented using the  BSD Socket
 *              interface as the means of communication with the user level.
 *
 *              DECnet Network Services Protocol (Input)
 *
 * Author:      Eduardo Marcelo Serrat <emserrat@geocities.com>
 *
 * Changes:
 *
 *    Steve Whitehouse:  Split into dn_nsp_in.c and dn_nsp_out.c from
 *                       original dn_nsp.c.
 *    Steve Whitehouse:  Updated to work with my new routing architecture.
 *    Steve Whitehouse:  Add changes from Eduardo Serrat's patches.
 *    Steve Whitehouse:  Put all ack handling code in a common routine.
 *    Steve Whitehouse:  Put other common bits into dn_nsp_rx()
 *    Steve Whitehouse:  More checks on skb->len to catch bogus packets
 *                       Fixed various race conditions and possible nasties.
 *    Steve Whitehouse:  Now handles returned conninit frames.
 *     David S. Miller:  New socket locking
 *    Steve Whitehouse:  Fixed lockup when socket filtering was enabled.
 *         Paul Koning:  Fix to push CC sockets into RUN when acks are
 *                       received.
 *    Steve Whitehouse:
 *   Patrick Caulfield:  Checking conninits for correctness & sending of error
 *                       responses.
 *    Steve Whitehouse:  Added backlog congestion level return codes.
 *   Patrick Caulfield:
 *    Steve Whitehouse:  Added flow control support (outbound)
 *    Steve Whitehouse:  Prepare for nonlinear skbs
 */

/******************************************************************************
    (c) 1995-1998 E.M. Serrat           emserrat@geocities.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
*******************************************************************************/

#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/route.h>
#include <linux/slab.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/termios.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/netfilter_decnet.h>
#include <net/neighbour.h>
#include <net/dst.h>
#include <net/dn.h>
#include <net/dn_nsp.h>
#include <net/dn_dev.h>
#include <net/dn_route.h>

extern int decnet_log_martians;


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

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6981.18%233.33%
Steven Whitehouse89.41%116.67%
Harvey Harrison44.71%116.67%
Linus Torvalds33.53%116.67%
Joe Perches11.18%116.67%
Total85100.00%6100.00%

/* * For this function we've flipped the cross-subchannel bit * if the message is an otherdata or linkservice message. Thus * we can use it to work out what to update. */
static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack) { struct dn_scp *scp = DN_SK(sk); unsigned short type = ((ack >> 12) & 0x0003); int wakeup = 0; switch (type) { case 0: /* ACK - Data */ if (dn_after(ack, scp->ackrcv_dat)) { scp->ackrcv_dat = ack & 0x0fff; wakeup |= dn_nsp_check_xmit_queue(sk, skb, &scp->data_xmit_queue, ack); } break; case 1: /* NAK - Data */ break; case 2: /* ACK - OtherData */ if (dn_after(ack, scp->ackrcv_oth)) { scp->ackrcv_oth = ack & 0x0fff; wakeup |= dn_nsp_check_xmit_queue(sk, skb, &scp->other_xmit_queue, ack); } break; case 3: /* NAK - OtherData */ break; } if (wakeup && !sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15793.45%116.67%
Arnaldo Carvalho de Melo42.38%233.33%
Linus Torvalds31.79%116.67%
David S. Miller21.19%116.67%
James Morris21.19%116.67%
Total168100.00%6100.00%

/* * This function is a universal ack processor. */
static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth) { __le16 *ptr = (__le16 *)skb->data; int len = 0; unsigned short ack; if (skb->len < 2) return len; if ((ack = le16_to_cpu(*ptr)) & 0x8000) { skb_pull(skb, 2); ptr++; len += 2; if ((ack & 0x4000) == 0) { if (oth) ack ^= 0x2000; dn_ack(sk, skb, ack); } } if (skb->len < 2) return len; if ((ack = le16_to_cpu(*ptr)) & 0x8000) { skb_pull(skb, 2); len += 2; if ((ack & 0x4000) == 0) { if (oth) ack ^= 0x2000; dn_ack(sk, skb, ack); } } return len; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)17697.78%133.33%
Steven Whitehouse21.11%133.33%
Harvey Harrison21.11%133.33%
Total180100.00%3100.00%

/** * dn_check_idf - Check an image data field format is correct. * @pptr: Pointer to pointer to image data * @len: Pointer to length of image data * @max: The maximum allowed length of the data in the image data field * @follow_on: Check that this many bytes exist beyond the end of the image data * * Returns: 0 if ok, -1 on error */
static inline int dn_check_idf(unsigned char **pptr, int *len, unsigned char max, unsigned char follow_on) { unsigned char *ptr = *pptr; unsigned char flen = *ptr++; (*len)--; if (flen > max) return -1; if ((flen + follow_on) > *len) return -1; *len -= flen; *pptr = ptr + flen; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)87100.00%1100.00%
Total87100.00%1100.00%

/* * Table of reason codes to pass back to node which sent us a badly * formed message, plus text messages for the log. A zero entry in * the reason field means "don't reply" otherwise a disc init is sent with * the specified reason code. */ static struct { unsigned short reason; const char *text; } ci_err_table[] = { { 0, "CI: Truncated message" }, { NSP_REASON_ID, "CI: Destination username error" }, { NSP_REASON_ID, "CI: Destination username type" }, { NSP_REASON_US, "CI: Source username error" }, { 0, "CI: Truncated at menuver" }, { 0, "CI: Truncated before access or user data" }, { NSP_REASON_IO, "CI: Access data format error" }, { NSP_REASON_IO, "CI: User data format error" } }; /* * This function uses a slightly different lookup method * to find its sockets, since it searches on object name/number * rather than port numbers. Various tests are done to ensure that * the incoming data is in the correct format before it is queued to * a socket. */
static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason) { struct dn_skb_cb *cb = DN_SKB_CB(skb); struct nsp_conn_init_msg *msg = (struct nsp_conn_init_msg *)skb->data; struct sockaddr_dn dstaddr; struct sockaddr_dn srcaddr; unsigned char type = 0; int dstlen; int srclen; unsigned char *ptr; int len; int err = 0; unsigned char menuver; memset(&dstaddr, 0, sizeof(struct sockaddr_dn)); memset(&srcaddr, 0, sizeof(struct sockaddr_dn)); /* * 1. Decode & remove message header */ cb->src_port = msg->srcaddr; cb->dst_port = msg->dstaddr; cb->services = msg->services; cb->info = msg->info; cb->segsize = le16_to_cpu(msg->segsize); if (!pskb_may_pull(skb, sizeof(*msg))) goto err_out; skb_pull(skb, sizeof(*msg)); len = skb->len; ptr = skb->data; /* * 2. Check destination end username format */ dstlen = dn_username2sockaddr(ptr, len, &dstaddr, &type); err++; if (dstlen < 0) goto err_out; err++; if (type > 1) goto err_out; len -= dstlen; ptr += dstlen; /* * 3. Check source end username format */ srclen = dn_username2sockaddr(ptr, len, &srcaddr, &type); err++; if (srclen < 0) goto err_out; len -= srclen; ptr += srclen; err++; if (len < 1) goto err_out; menuver = *ptr; ptr++; len--; /* * 4. Check that optional data actually exists if menuver says it does */ err++; if ((menuver & (DN_MENUVER_ACC | DN_MENUVER_USR)) && (len < 1)) goto err_out; /* * 5. Check optional access data format */ err++; if (menuver & DN_MENUVER_ACC) { if (dn_check_idf(&ptr, &len, 39, 1)) goto err_out; if (dn_check_idf(&ptr, &len, 39, 1)) goto err_out; if (dn_check_idf(&ptr, &len, 39, (menuver & DN_MENUVER_USR) ? 1 : 0)) goto err_out; } /* * 6. Check optional user data format */ err++; if (menuver & DN_MENUVER_USR) { if (dn_check_idf(&ptr, &len, 16, 0)) goto err_out; } /* * 7. Look up socket based on destination end username */ return dn_sklist_find_listener(&dstaddr); err_out: dn_log_martian(skb, ci_err_table[err].text); *reason = ci_err_table[err].reason; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)45398.05%350.00%
Steven Whitehouse51.08%116.67%
Linus Torvalds30.65%116.67%
Harvey Harrison10.22%116.67%
Total462100.00%6100.00%


static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb) { if (sk_acceptq_is_full(sk)) { kfree_skb(skb); return; } sk->sk_ack_backlog++; skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_state_change(sk); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4788.68%250.00%
Arnaldo Carvalho de Melo611.32%250.00%
Total53100.00%4100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)19973.43%110.00%
Linus Torvalds5419.93%220.00%
Arnaldo Carvalho de Melo103.69%330.00%
Steven Whitehouse41.48%220.00%
James Morris20.74%110.00%
Harvey Harrison20.74%110.00%
Total271100.00%10100.00%


static void dn_nsp_conn_ack(struct sock *sk, struct sk_buff *skb) { struct dn_scp *scp = DN_SK(sk); if (scp->state == DN_CI) { scp->state = DN_CD; scp->persist = 0; } kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5094.34%150.00%
Linus Torvalds35.66%150.00%
Total53100.00%2100.00%


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); } /* * It appears that its possible for remote machines to send disc * init messages with no port identifier if we are in the CI and * possibly also the CD state. Obviously we shouldn't reply with * a message if we don't know what the end point is. */ 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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)26785.58%215.38%
Steven Whitehouse144.49%323.08%
Arnaldo Carvalho de Melo134.17%323.08%
Patrick Caulfield61.92%17.69%
Linus Torvalds61.92%17.69%
Harvey Harrison30.96%17.69%
James Morris20.64%17.69%
Hideaki Yoshifuji / 吉藤英明10.32%17.69%
Total312100.00%13100.00%

/* * disc_conf messages are also called no_resources or no_link * messages depending upon the "reason" field. */
static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb) { struct dn_scp *scp = DN_SK(sk); unsigned short reason; if (skb->len != 2) goto out; reason = le16_to_cpu(*(__le16 *)skb->data); sk->sk_state = TCP_CLOSE; switch (scp->state) { case DN_CI: scp->state = DN_NR; break; case DN_DR: if (reason == NSP_REASON_DC) scp->state = DN_DRC; if (reason == NSP_REASON_NL) scp->state = DN_CN; break; case DN_DI: scp->state = DN_DIC; break; case DN_RUN: sk->sk_shutdown |= SHUTDOWN_MASK; case DN_CC: scp->state = DN_CN; } if (!sock_flag(sk, SOCK_DEAD)) { if (sk->sk_socket->state != SS_UNCONNECTED) sk->sk_socket->state = SS_DISCONNECTING; sk->sk_state_change(sk); } scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); out: kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)17992.27%333.33%
Arnaldo Carvalho de Melo84.12%222.22%
Linus Torvalds31.55%111.11%
James Morris21.03%111.11%
Harvey Harrison10.52%111.11%
Steven Whitehouse10.52%111.11%
Total194100.00%9100.00%


static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb) { struct dn_scp *scp = DN_SK(sk); unsigned short segnum; unsigned char lsflags; signed char fcval; int wake_up = 0; char *ptr = skb->data; unsigned char fctype = scp->services_rem & NSP_FC_MASK; if (skb->len != 4) goto out; segnum = le16_to_cpu(*(__le16 *)ptr); ptr += 2; lsflags = *(unsigned char *)ptr++; fcval = *ptr; /* * Here we ignore erronous packets which should really * should cause a connection abort. It is not critical * for now though. */ if (lsflags & 0xf8) goto out; if (seq_next(scp->numoth_rcv, segnum)) { seq_add(&scp->numoth_rcv, 1); switch(lsflags & 0x04) { /* FCVAL INT */ case 0x00: /* Normal Request */ switch(lsflags & 0x03) { /* FCVAL MOD */ case 0x00: /* Request count */ if (fcval < 0) { unsigned char p_fcval = -fcval; if ((scp->flowrem_dat > p_fcval) && (fctype == NSP_FC_SCMC)) { scp->flowrem_dat -= p_fcval; } } else if (fcval > 0) { scp->flowrem_dat += fcval; wake_up = 1; } break; case 0x01: /* Stop outgoing data */ scp->flowrem_sw = DN_DONTSEND; break; case 0x02: /* Ok to start again */ scp->flowrem_sw = DN_SEND; dn_nsp_output(sk); wake_up = 1; } break; case 0x04: /* Interrupt Request */ if (fcval > 0) { scp->flowrem_oth += fcval; wake_up = 1; } break; } if (wake_up && !sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); } dn_nsp_send_oth_ack(sk); out: kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds15951.79%111.11%
Linus Torvalds (pre-git)13844.95%111.11%
Arnaldo Carvalho de Melo41.30%222.22%
James Morris20.65%111.11%
Steven Whitehouse10.33%111.11%
Hideaki Yoshifuji / 吉藤英明10.33%111.11%
Harvey Harrison10.33%111.11%
Olaf Hering10.33%111.11%
Total307100.00%9100.00%

/* * Copy of sock_queue_rcv_skb (from sock.h) without * bh_lock_sock() (its already held when this is called) which * also allows data and other data to be queued to a socket. */
static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue) { int err; /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= (unsigned int)sk->sk_rcvbuf) { err = -ENOMEM; goto out; } err = sk_filter(sk, skb); if (err) goto out; skb_set_owner_r(skb, sk); skb_queue_tail(queue, skb); if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8575.22%330.00%
James Morris2017.70%220.00%
Arnaldo Carvalho de Melo54.42%220.00%
Eric Dumazet10.88%110.00%
Steven Whitehouse10.88%110.00%
Hideaki Yoshifuji / 吉藤英明10.88%110.00%
Total113100.00%10100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13186.75%240.00%
Linus Torvalds1811.92%120.00%
Steven Whitehouse10.66%120.00%
Harvey Harrison10.66%120.00%
Total151100.00%5100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15386.44%233.33%
Linus Torvalds2111.86%116.67%
Steven Whitehouse10.56%116.67%
Harvey Harrison10.56%116.67%
Arnaldo Carvalho de Melo10.56%116.67%
Total177100.00%6100.00%

/* * If one of our conninit messages is returned, this function * deals with it. It puts the socket into the NO_COMMUNICATION * state. */
static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb) { struct dn_scp *scp = DN_SK(sk); if (scp->state == DN_CI) { scp->state = DN_NC; sk->sk_state = TCP_CLOSE; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); } kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6085.71%233.33%
Arnaldo Carvalho de Melo57.14%233.33%
Linus Torvalds34.29%116.67%
James Morris22.86%116.67%
Total70100.00%6100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8972.36%266.67%
Linus Torvalds3427.64%133.33%
Total123100.00%3100.00%


static int dn_nsp_rx_packet(struct net *net, struct sock *sk2, struct sk_buff *skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); struct sock *sk = NULL; unsigned char *ptr = (unsigned char *)skb->data; unsigned short reason = NSP_REASON_NL; if (!pskb_may_pull(skb, 2)) goto free_out; skb_reset_transport_header(skb); cb->nsp_flags = *ptr++; if (decnet_debug_level & 2) printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags); if (cb->nsp_flags & 0x83) goto free_out; /* * Filter out conninits and useless packet types */ if ((cb->nsp_flags & 0x0c) == 0x08) { switch (cb->nsp_flags & 0x70) { case 0x00: /* NOP */ case 0x70: /* Reserved */ case 0x50: /* Reserved, Phase II node init */ goto free_out; case 0x10: case 0x60: if (unlikely(cb->rt_flags & DN_RT_F_RTS)) goto free_out; sk = dn_find_listener(skb, &reason); goto got_it; } } if (!pskb_may_pull(skb, 3)) goto free_out; /* * Grab the destination address. */ cb->dst_port = *(__le16 *)ptr; cb->src_port = 0; ptr += 2; /* * If not a connack, grab the source address too. */ if (pskb_may_pull(skb, 5)) { cb->src_port = *(__le16 *)ptr; ptr += 2; skb_pull(skb, 5); } /* * Returned packets... * Swap src & dst and look up in the normal way. */ if (unlikely(cb->rt_flags & DN_RT_F_RTS)) { __le16 tmp = cb->dst_port; cb->dst_port = cb->src_port; cb->src_port = tmp; tmp = cb->dst; cb->dst = cb->src; cb->src = tmp; } /* * Find the socket to which this skb is destined. */ sk = dn_find_by_skb(skb); got_it: if (sk != NULL) { struct dn_scp *scp = DN_SK(sk); /* Reset backoff */ scp->nsp_rxtshift = 0; /* * We linearize everything except data segments here. */ if (cb->nsp_flags & ~0x60) { if (unlikely(skb_linearize(skb))) goto free_out; } return sk_receive_skb(sk, skb, 0); } return dn_nsp_no_socket(skb, reason); free_out: kfree_skb(skb); return NET_RX_DROP; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)25664.16%535.71%
Steven Whitehouse11729.32%214.29%
Linus Torvalds82.01%17.14%
Arnaldo Carvalho de Melo71.75%321.43%
David S. Miller51.25%17.14%
Eric W. Biedermann51.25%17.14%
Herbert Xu10.25%17.14%
Total399100.00%14100.00%


int dn_nsp_rx(struct sk_buff *skb) { return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN, &init_net, NULL, skb, skb->dev, NULL, dn_nsp_rx_packet); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2781.82%240.00%
Eric W. Biedermann39.09%120.00%
David S. Miller26.06%120.00%
Jan Engelhardt13.03%120.00%
Total33100.00%5100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)29789.46%337.50%
Steven Whitehouse206.02%112.50%
Linus Torvalds82.41%112.50%
Arnaldo Carvalho de Melo51.51%225.00%
James Morris20.60%112.50%
Total332100.00%8100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)308082.33%923.08%
Linus Torvalds3268.71%25.13%
Steven Whitehouse1764.70%512.82%
Arnaldo Carvalho de Melo691.84%820.51%
James Morris340.91%25.13%
Harvey Harrison160.43%12.56%
David S. Miller140.37%25.13%
Eric W. Biedermann80.21%25.13%
Patrick Caulfield60.16%12.56%
Hideaki Yoshifuji / 吉藤英明40.11%12.56%
Tejun Heo30.08%12.56%
Herbert Xu10.03%12.56%
Olaf Hering10.03%12.56%
Eric Dumazet10.03%12.56%
Jan Engelhardt10.03%12.56%
Joe Perches10.03%12.56%
Total3741100.00%39100.00%
Directory: net/decnet
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.