cregit-Linux how code gets into the kernel

Release 4.8 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
pre-gitpre-git6981.18%233.33%
steven whitehousesteven whitehouse89.41%116.67%
harvey harrisonharvey harrison44.71%116.67%
linus torvaldslinus torvalds33.53%116.67%
joe perchesjoe 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
pre-gitpre-git15793.45%116.67%
arnaldo carvalho de meloarnaldo carvalho de melo42.38%233.33%
linus torvaldslinus torvalds31.79%116.67%
david s. millerdavid s. miller21.19%116.67%
james morrisjames 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
pre-gitpre-git17697.78%133.33%
harvey harrisonharvey harrison21.11%133.33%
steven whitehousesteven whitehouse21.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
pre-gitpre-git87100.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
pre-gitpre-git45398.05%350.00%
steven whitehousesteven whitehouse51.08%116.67%
linus torvaldslinus torvalds30.65%116.67%
harvey harrisonharvey 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
pre-gitpre-git4788.68%250.00%
arnaldo carvalho de meloarnaldo 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
pre-gitpre-git19973.43%110.00%
linus torvaldslinus torvalds5419.93%220.00%
arnaldo carvalho de meloarnaldo carvalho de melo103.69%330.00%
steven whitehousesteven whitehouse41.48%220.00%
harvey harrisonharvey harrison20.74%110.00%
james morrisjames morris20.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
pre-gitpre-git5094.34%150.00%
linus torvaldslinus 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
pre-gitpre-git26785.58%215.38%
steven whitehousesteven whitehouse144.49%323.08%
arnaldo carvalho de meloarnaldo carvalho de melo134.17%323.08%
patrick caulfieldpatrick caulfield61.92%17.69%
linus torvaldslinus torvalds61.92%17.69%
harvey harrisonharvey harrison30.96%17.69%
james morrisjames morris20.64%17.69%
hideaki yoshifujihideaki yoshifuji10.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
pre-gitpre-git17992.27%333.33%
arnaldo carvalho de meloarnaldo carvalho de melo84.12%222.22%
linus torvaldslinus torvalds31.55%111.11%
james morrisjames morris21.03%111.11%
steven whitehousesteven whitehouse10.52%111.11%
harvey harrisonharvey harrison10.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 torvaldslinus torvalds15951.79%111.11%
pre-gitpre-git13844.95%111.11%
arnaldo carvalho de meloarnaldo carvalho de melo41.30%222.22%
james morrisjames morris20.65%111.11%
steven whitehousesteven whitehouse10.33%111.11%
olaf heringolaf hering10.33%111.11%
hideaki yoshifujihideaki yoshifuji10.33%111.11%
harvey harrisonharvey harrison10.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
pre-gitpre-git8575.22%330.00%
james morrisjames morris2017.70%220.00%
arnaldo carvalho de meloarnaldo carvalho de melo54.42%220.00%
steven whitehousesteven whitehouse10.88%110.00%
hideaki yoshifujihideaki yoshifuji10.88%110.00%
eric dumazeteric dumazet10.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
pre-gitpre-git13186.75%240.00%
linus torvaldslinus torvalds1811.92%120.00%
harvey harrisonharvey harrison10.66%120.00%
steven whitehousesteven whitehouse10.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
pre-gitpre-git15386.44%233.33%
linus torvaldslinus torvalds2111.86%116.67%
steven whitehousesteven whitehouse10.56%116.67%
arnaldo carvalho de meloarnaldo carvalho de melo10.56%116.67%
harvey harrisonharvey harrison10.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
pre-gitpre-git6085.71%233.33%
arnaldo carvalho de meloarnaldo carvalho de melo57.14%233.33%
linus torvaldslinus torvalds34.29%116.67%
james morrisjames 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
pre-gitpre-git8972.36%266.67%
linus torvaldslinus 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