cregit-Linux how code gets into the kernel

Release 4.8 net/ipx/af_ipx.c

Directory: net/ipx
/*
 *      Implements an IPX socket layer.
 *
 *      This code is derived from work by
 *              Ross Biro       :       Writing the original IP stack
 *              Fred Van Kempen :       Tidying up the TCP/IP
 *
 *      Many thanks go to Keith Baker, Institute For Industrial Information
 *      Technology Ltd, Swansea University for allowing me to work on this
 *      in my own time even though it was in some ways related to commercial
 *      work I am currently employed to do there.
 *
 *      All the material in this file is subject to the Gnu license version 2.
 *      Neither Alan Cox nor the Swansea University Computer Society admit
 *      liability nor provide warranty for any of this software. This material
 *      is provided as is and at no charge.
 *
 *      Portions Copyright (c) 2000-2003 Conectiva, Inc. <acme@conectiva.com.br>
 *      Neither Arnaldo Carvalho de Melo nor Conectiva, Inc. admit liability nor
 *      provide warranty for any of this software. This material is provided
 *      "AS-IS" and at no charge.
 *
 *      Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com>
 *      Neither Greg Page nor Caldera, Inc. admit liability nor provide
 *      warranty for any of this software. This material is provided
 *      "AS-IS" and at no charge.
 *
 *      See net/ipx/ChangeLog.
 */

#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/init.h>
#include <linux/ipx.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/uio.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/termios.h>

#include <net/ipx.h>
#include <net/p8022.h>
#include <net/psnap.h>
#include <net/sock.h>
#include <net/datalink.h>
#include <net/tcp_states.h>
#include <net/net_namespace.h>

#include <asm/uaccess.h>

/* Configuration Variables */

static unsigned char ipxcfg_max_hops = 16;

static char ipxcfg_auto_select_primary;

static char ipxcfg_auto_create_interfaces;

int sysctl_ipx_pprop_broadcasting = 1;

/* Global Variables */

static struct datalink_proto *p8022_datalink;

static struct datalink_proto *pEII_datalink;

static struct datalink_proto *p8023_datalink;

static struct datalink_proto *pSNAP_datalink;


static const struct proto_ops ipx_dgram_ops;


LIST_HEAD(ipx_interfaces);

DEFINE_SPINLOCK(ipx_interfaces_lock);


struct ipx_interface *ipx_primary_net;

struct ipx_interface *ipx_internal_net;


struct ipx_interface *ipx_interfaces_head(void) { struct ipx_interface *rc = NULL; if (!list_empty(&ipx_interfaces)) rc = list_entry(ipx_interfaces.next, struct ipx_interface, node); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo42100.00%1100.00%
Total42100.00%1100.00%


static void ipxcfg_set_auto_select(char val) { ipxcfg_auto_select_primary = val; if (val && !ipx_primary_net) ipx_primary_net = ipx_interfaces_head(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2184.00%133.33%
linus torvaldslinus torvalds28.00%133.33%
arnaldo carvalho de meloarnaldo carvalho de melo28.00%133.33%
Total25100.00%3100.00%


static int ipxcfg_get_config_data(struct ipx_config_data __user *arg) { struct ipx_config_data vals; vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces; vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary; return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4493.62%466.67%
arnaldo carvalho de meloarnaldo carvalho de melo24.26%116.67%
al viroal viro12.13%116.67%
Total47100.00%6100.00%

/* * Note: Sockets may not be removed _during_ an interrupt or inet_bh * handler using this technique. They can be added although we do not * use this facility. */
static void ipx_remove_socket(struct sock *sk) { /* Determine interface with which socket is associated */ struct ipx_interface *intrfc = ipx_sk(sk)->intrfc; if (!intrfc) goto out; ipxitf_hold(intrfc); spin_lock_bh(&intrfc->if_sklist_lock); sk_del_node_init(sk); spin_unlock_bh(&intrfc->if_sklist_lock); ipxitf_put(intrfc); out: return; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3857.58%342.86%
arnaldo carvalho de meloarnaldo carvalho de melo2537.88%342.86%
linus torvaldslinus torvalds34.55%114.29%
Total66100.00%7100.00%


static void ipx_destroy_socket(struct sock *sk) { ipx_remove_socket(sk); skb_queue_purge(&sk->sk_receive_queue); sk_refcnt_debug_dec(sk); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2793.10%466.67%
arnaldo carvalho de meloarnaldo carvalho de melo13.45%116.67%
pavel emelianovpavel emelianov13.45%116.67%
Total29100.00%6100.00%

/* * The following code is used to support IPX Interfaces (IPXITF). An * IPX interface is defined by a physical device and a frame type. */ /* ipxitf_clear_primary_net has to be called with ipx_interfaces_lock held */
static void ipxitf_clear_primary_net(void) { ipx_primary_net = NULL; if (ipxcfg_auto_select_primary) ipx_primary_net = ipx_interfaces_head(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git1257.14%266.67%
arnaldo carvalho de meloarnaldo carvalho de melo942.86%133.33%
Total21100.00%3100.00%


static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev, __be16 datalink) { struct ipx_interface *i; list_for_each_entry(i, &ipx_interfaces, node) if (i->if_dev == dev && i->if_dlink_type == datalink) goto out; i = NULL; out: return i; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3054.55%450.00%
arnaldo carvalho de meloarnaldo carvalho de melo2036.36%225.00%
linus torvaldslinus torvalds47.27%112.50%
al viroal viro11.82%112.50%
Total55100.00%8100.00%


static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev, __be16 datalink) { struct ipx_interface *i; spin_lock_bh(&ipx_interfaces_lock); i = __ipxitf_find_using_phys(dev, datalink); if (i) ipxitf_hold(i); spin_unlock_bh(&ipx_interfaces_lock); return i; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5194.44%133.33%
arnaldo carvalho de meloarnaldo carvalho de melo23.70%133.33%
al viroal viro11.85%133.33%
Total54100.00%3100.00%


struct ipx_interface *ipxitf_find_using_net(__be32 net) { struct ipx_interface *i; spin_lock_bh(&ipx_interfaces_lock); if (net) { list_for_each_entry(i, &ipx_interfaces, node) if (i->if_netnum == net) goto hold; i = NULL; goto unlock; } i = ipx_primary_net; if (i) hold: ipxitf_hold(i); unlock: spin_unlock_bh(&ipx_interfaces_lock); return i; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5063.29%350.00%
arnaldo carvalho de meloarnaldo carvalho de melo2835.44%233.33%
al viroal viro11.27%116.67%
Total79100.00%6100.00%

/* Sockets are bound to a particular IPX interface. */
static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk) { ipxitf_hold(intrfc); spin_lock_bh(&intrfc->if_sklist_lock); ipx_sk(sk)->intrfc = intrfc; sk_add_node(sk, &intrfc->if_sklist); spin_unlock_bh(&intrfc->if_sklist_lock); ipxitf_put(intrfc); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5285.25%562.50%
arnaldo carvalho de meloarnaldo carvalho de melo69.84%225.00%
david s. millerdavid s. miller34.92%112.50%
Total61100.00%8100.00%

/* caller must hold intrfc->if_sklist_lock */
static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc, __be16 port) { struct sock *s; sk_for_each(s, &intrfc->if_sklist) if (ipx_sk(s)->port == port) goto found; s = NULL; found: return s; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2754.00%550.00%
arnaldo carvalho de meloarnaldo carvalho de melo1530.00%220.00%
linus torvaldslinus torvalds48.00%110.00%
david s. millerdavid s. miller36.00%110.00%
al viroal viro12.00%110.00%
Total50100.00%10100.00%

/* caller must hold a reference to intrfc */
static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, __be16 port) { struct sock *s; spin_lock_bh(&intrfc->if_sklist_lock); s = __ipxitf_find_socket(intrfc, port); if (s) sock_hold(s); spin_unlock_bh(&intrfc->if_sklist_lock); return s; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5696.55%250.00%
arnaldo carvalho de meloarnaldo carvalho de melo11.72%125.00%
al viroal viro11.72%125.00%
Total58100.00%4100.00%

#ifdef CONFIG_IPX_INTERN
static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, unsigned char *ipx_node, __be16 port) { struct sock *s; ipxitf_hold(intrfc); spin_lock_bh(&intrfc->if_sklist_lock); sk_for_each(s, &intrfc->if_sklist) { struct ipx_sock *ipxs = ipx_sk(s); if (ipxs->port == port && !memcmp(ipx_node, ipxs->node, IPX_NODE_LEN)) goto found; } s = NULL; found: spin_unlock_bh(&intrfc->if_sklist_lock); ipxitf_put(intrfc); return s; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7270.59%436.36%
arnaldo carvalho de meloarnaldo carvalho de melo1716.67%436.36%
david s. millerdavid s. miller1110.78%19.09%
linus torvaldslinus torvalds10.98%19.09%
al viroal viro10.98%19.09%
Total102100.00%11100.00%

#endif
static void __ipxitf_down(struct ipx_interface *intrfc) { struct sock *s; struct hlist_node *t; /* Delete all routes associated with this interface */ ipxrtr_del_routes(intrfc); spin_lock_bh(&intrfc->if_sklist_lock); /* error sockets */ sk_for_each_safe(s, t, &intrfc->if_sklist) { struct ipx_sock *ipxs = ipx_sk(s); s->sk_err = ENOLINK; s->sk_error_report(s); ipxs->intrfc = NULL; ipxs->port = 0; sock_set_flag(s, SOCK_ZAPPED); /* Indicates it is no longer bound */ sk_del_node_init(s); } INIT_HLIST_HEAD(&intrfc->if_sklist); spin_unlock_bh(&intrfc->if_sklist_lock); /* remove this interface from list */ list_del(&intrfc->node); /* remove this interface from *special* networks */ if (intrfc == ipx_primary_net) ipxitf_clear_primary_net(); if (intrfc == ipx_internal_net) ipx_internal_net = NULL; if (intrfc->if_dev) dev_put(intrfc->if_dev); kfree(intrfc); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git11271.34%642.86%
arnaldo carvalho de meloarnaldo carvalho de melo2817.83%535.71%
david s. millerdavid s. miller117.01%17.14%
thomas grafthomas graf53.18%17.14%
adrian bunkadrian bunk10.64%17.14%
Total157100.00%14100.00%


void ipxitf_down(struct ipx_interface *intrfc) { spin_lock_bh(&ipx_interfaces_lock); __ipxitf_down(intrfc); spin_unlock_bh(&ipx_interfaces_lock); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2696.30%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo13.70%150.00%
Total27100.00%2100.00%


static void __ipxitf_put(struct ipx_interface *intrfc) { if (atomic_dec_and_test(&intrfc->refcnt)) __ipxitf_down(intrfc); }

Contributors

PersonTokensPropCommitsCommitProp
adrian bunkadrian bunk26100.00%1100.00%
Total26100.00%1100.00%


static int ipxitf_device_event(struct notifier_block *notifier, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct ipx_interface *i, *tmp; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (event != NETDEV_DOWN && event != NETDEV_UP) goto out; spin_lock_bh(&ipx_interfaces_lock); list_for_each_entry_safe(i, tmp, &ipx_interfaces, node) if (i->if_dev == dev) { if (event == NETDEV_UP) ipxitf_hold(i); else __ipxitf_put(i); } spin_unlock_bh(&ipx_interfaces_lock); out: return NOTIFY_DONE; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6755.37%642.86%
linus torvaldslinus torvalds2319.01%214.29%
arnaldo carvalho de meloarnaldo carvalho de melo119.09%214.29%
eric w. biedermaneric w. biederman97.44%17.14%
hideaki yoshifujihideaki yoshifuji86.61%214.29%
jiri pirkojiri pirko32.48%17.14%
Total121100.00%14100.00%


static __exit void ipxitf_cleanup(void) { struct ipx_interface *i, *tmp; spin_lock_bh(&ipx_interfaces_lock); list_for_each_entry_safe(i, tmp, &ipx_interfaces, node) __ipxitf_put(i); spin_unlock_bh(&ipx_interfaces_lock); }

Contributors

PersonTokensPropCommitsCommitProp
stephen hemmingerstephen hemminger44100.00%1100.00%
Total44100.00%1100.00%


static void ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb) { if (sock_queue_rcv_skb(sock, skb) < 0) kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3196.88%375.00%
linus torvaldslinus torvalds13.12%125.00%
Total32100.00%4100.00%

/* * On input skb->sk is NULL. Nobody is charged for the memory. */ /* caller must hold a reference to intrfc */ #ifdef CONFIG_IPX_INTERN
static int ipxitf_demux_socket(struct ipx_interface *intrfc, struct sk_buff *skb, int copy) { struct ipxhdr *ipx = ipx_hdr(skb); int is_broadcast = !memcmp(ipx->ipx_dest.node, ipx_broadcast_node, IPX_NODE_LEN); struct sock *s; int rc; spin_lock_bh(&intrfc->if_sklist_lock); sk_for_each(s, &intrfc->if_sklist) { struct ipx_sock *ipxs = ipx_sk(s); if (ipxs->port == ipx->ipx_dest.sock && (is_broadcast || !memcmp(ipx->ipx_dest.node, ipxs->node, IPX_NODE_LEN))) { /* We found a socket to which to send */ struct sk_buff *skb1; if (copy) { skb1 = skb_clone(skb, GFP_ATOMIC); rc = -ENOMEM; if (!skb1) goto out; } else { skb1 = skb; copy = 1; /* skb may only be used once */ } ipxitf_def_skb_handler(s, skb1); /* On an external interface, one socket can listen */ if (intrfc != ipx_internal_net) break; } } /* skb was solely for us, and we did not make a copy, so free it. */ if (!copy) kfree_skb(skb); rc = 0; out: spin_unlock_bh(&intrfc->if_sklist_lock); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git16681.77%853.33%
arnaldo carvalho de meloarnaldo carvalho de melo157.39%426.67%
david s. millerdavid s. miller115.42%16.67%
linus torvaldslinus torvalds115.42%213.33%
Total203100.00%15100.00%

#else
static struct sock *ncp_connection_hack(struct ipx_interface *intrfc, struct ipxhdr *ipx) { /* The packet's target is a NCP connection handler. We want to hand it * to the correct socket directly within the kernel, so that the * mars_nwe packet distribution process does not have to do it. Here we * only care about NCP and BURST packets. * * You might call this a hack, but believe me, you do not want a * complete NCP layer in the kernel, and this is VERY fast as well. */ struct sock *sk = NULL; int connection = 0; u8 *ncphdr = (u8 *)(ipx + 1); if (*ncphdr == 0x22 && *(ncphdr + 1) == 0x22) /* NCP request */ connection = (((int) *(ncphdr + 5)) << 8) | (int) *(ncphdr + 3); else if (*ncphdr == 0x77 && *(ncphdr + 1) == 0x77) /* BURST packet */ connection = (((int) *(ncphdr + 9)) << 8) | (int) *(ncphdr + 8); if (connection) { /* Now we have to look for a special NCP connection handling * socket. Only these sockets have ipx_ncp_conn != 0, set by * SIOCIPXNCPCONN. */ spin_lock_bh(&intrfc->if_sklist_lock); sk_for_each(sk, &intrfc->if_sklist) if (ipx_sk(sk)->ipx_ncp_conn == connection) { sock_hold(sk); goto found; } sk = NULL; found: spin_unlock_bh(&intrfc->if_sklist_lock); } return sk; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git13870.77%550.00%
linus torvaldslinus torvalds3316.92%220.00%
arnaldo carvalho de meloarnaldo carvalho de melo2110.77%220.00%
david s. millerdavid s. miller31.54%110.00%
Total195100.00%10100.00%


static int ipxitf_demux_socket(struct ipx_interface *intrfc, struct sk_buff *skb, int copy) { struct ipxhdr *ipx = ipx_hdr(skb); struct sock *sock1 = NULL, *sock2 = NULL; struct sk_buff *skb1 = NULL, *skb2 = NULL; int rc; if (intrfc == ipx_primary_net && ntohs(ipx->ipx_dest.sock) == 0x451) sock1 = ncp_connection_hack(intrfc, ipx); if (!sock1) /* No special socket found, forward the packet the normal way */ sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock); /* * We need to check if there is a primary net and if * this is addressed to one of the *SPECIAL* sockets because * these need to be propagated to the primary net. * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and * 0x456(Diagnostic). */ if (ipx_primary_net && intrfc != ipx_primary_net) { const int dsock = ntohs(ipx->ipx_dest.sock); if (dsock == 0x452 || dsock == 0x453 || dsock == 0x456) /* The appropriate thing to do here is to dup the * packet and route to the primary net interface via * ipxitf_send; however, we'll cheat and just demux it * here. */ sock2 = ipxitf_find_socket(ipx_primary_net, ipx->ipx_dest.sock); } /* * If there is nothing to do return. The kfree will cancel any charging. */ rc = 0; if (!sock1 && !sock2) { if (!copy) kfree_skb(skb); goto out; } /* * This next segment of code is a little awkward, but it sets it up * so that the appropriate number of copies of the SKB are made and * that skb1 and skb2 point to it (them) so that it (they) can be * demuxed to sock1 and/or sock2. If we are unable to make enough * copies, we do as much as is possible. */ if (copy) skb1 = skb_clone(skb, GFP_ATOMIC); else skb1 = skb; rc = -ENOMEM; if (!skb1) goto out_put; /* Do we need 2 SKBs? */ if (sock1 && sock2) skb2 = skb_clone(skb1, GFP_ATOMIC); else skb2 = skb1; if (sock1) ipxitf_def_skb_handler(sock1, skb1); if (!skb2) goto out_put; if (sock2) ipxitf_def_skb_handler(sock2, skb2); rc = 0; out_put: if (sock1) sock_put(sock1); if (sock2) sock_put(sock2); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git17459.39%866.67%
linus torvaldslinus torvalds9933.79%216.67%
arnaldo carvalho de meloarnaldo carvalho de melo206.83%216.67%
Total293100.00%12100.00%

#endif /* CONFIG_IPX_INTERN */
static struct sk_buff *ipxitf_adjust_skbuff(struct ipx_interface *intrfc, struct sk_buff *skb) { struct sk_buff *skb2; int in_offset = (unsigned char *)ipx_hdr(skb) - skb->head; int out_offset = intrfc->if_ipx_offset; int len; /* Hopefully, most cases */ if (in_offset >= out_offset) return skb; /* Need new SKB */ len = skb->len + out_offset; skb2 = alloc_skb(len, GFP_ATOMIC); if (skb2) { skb_reserve(skb2, out_offset); skb_reset_network_header(skb2); skb_reset_transport_header(skb2); skb_put(skb2, skb->len); memcpy(ipx_hdr(skb2), ipx_hdr(skb), skb->len); memcpy(skb2->cb, skb->cb, sizeof(skb->cb)); } kfree_skb(skb); return skb2; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git11273.20%763.64%
arnaldo carvalho de meloarnaldo carvalho de melo2315.03%327.27%
linus torvaldslinus torvalds1811.76%19.09%
Total153100.00%11100.00%

/* caller must hold a reference to intrfc and the skb has to be unshared */
int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node) { struct ipxhdr *ipx = ipx_hdr(skb); struct net_device *dev = intrfc->if_dev; struct datalink_proto *dl = intrfc->if_dlink; char dest_node[IPX_NODE_LEN]; int send_to_wire = 1; int addr_len; ipx->ipx_tctrl = IPX_SKB_CB(skb)->ipx_tctrl; ipx->ipx_dest.net = IPX_SKB_CB(skb)->ipx_dest_net; ipx->ipx_source.net = IPX_SKB_CB(skb)->ipx_source_net; /* see if we need to include the netnum in the route list */ if (IPX_SKB_CB(skb)->last_hop.index >= 0) { __be32 *last_hop = (__be32 *)(((u8 *) skb->data) + sizeof(struct ipxhdr) + IPX_SKB_CB(skb)->last_hop.index * sizeof(__be32)); *last_hop = IPX_SKB_CB(skb)->last_hop.netnum; IPX_SKB_CB(skb)->last_hop.index = -1; } /* * We need to know how many skbuffs it will take to send out this * packet to avoid unnecessary copies. */ if (!dl || !dev || dev->flags & IFF_LOOPBACK) send_to_wire = 0; /* No non looped */ /* * See if this should be demuxed to sockets on this interface * * We want to ensure the original was eaten or that we only use * up clones. */ if (ipx->ipx_dest.net == intrfc->if_netnum) { /* * To our own node, loop and free the original. * The internal net will receive on all node address. */ if (intrfc == ipx_internal_net || !memcmp(intrfc->if_node, node, IPX_NODE_LEN)) { /* Don't charge sender */ skb_orphan(skb); /* Will charge receiver */ return ipxitf_demux_socket(intrfc, skb, 0); } /* Broadcast, loop and possibly keep to send on. */ if (!memcmp(ipx_broadcast_node, node, IPX_NODE_LEN)) { if (!send_to_wire) skb_orphan(skb); ipxitf_demux_socket(intrfc, skb, send_to_wire); if (!send_to_wire) goto out; } } /* * If the originating net is not equal to our net; this is routed * We are still charging the sender. Which is right - the driver * free will handle this fairly. */ if (ipx->ipx_source.net != intrfc->if_netnum) { /* * Unshare the buffer before modifying the count in * case it's a flood or tcpdump */ skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) goto out; if (++ipx->ipx_tctrl > ipxcfg_max_hops) send_to_wire = 0; } if (!send_to_wire) { kfree_skb(skb); goto out; } /* Determine the appropriate hardware address */ addr_len = dev->addr_len; if (!memcmp(ipx_broadcast_node, node, IPX_NODE_LEN)) memcpy(dest_node, dev->broadcast, addr_len); else memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len); /* Make any compensation for differing physical/data link size */ skb = ipxitf_adjust_skbuff(intrfc, skb); if (!skb) goto out; /* set up data link and physical headers */ skb->dev = dev; skb->protocol = htons(ETH_P_IPX); /* Send it out */ dl->request(dl, skb, dest_node); out: return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git29765.56%1460.87%
linus torvaldslinus torvalds14331.57%313.04%
arnaldo carvalho de meloarnaldo carvalho de melo61.32%28.70%
al viroal viro30.66%14.35%
hideaki yoshifujihideaki yoshifuji20.44%14.35%
steven colesteven cole10.22%14.35%
david s. millerdavid s. miller10.22%14.35%
Total453100.00%23100.00%


static int ipxitf_add_local_route(struct ipx_interface *intrfc) { return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2295.65%266.67%
arnaldo carvalho de meloarnaldo carvalho de melo14.35%133.33%
Total23100.00%3100.00%

static void ipxitf_discover_netnum(struct ipx_interface *intrfc, struct sk_buff *skb); static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb);
static int ipxitf_rcv(struct ipx_interface *intrfc, struct sk_buff *skb) { struct ipxhdr *ipx = ipx_hdr(skb); int rc = 0; ipxitf_hold(intrfc); /* See if we should update our network number */ if (!intrfc->if_netnum) /* net number of intrfc not known yet */ ipxitf_discover_netnum(intrfc, skb); IPX_SKB_CB(skb)->last_hop.index = -1; if (ipx->ipx_type == IPX_TYPE_PPROP) { rc = ipxitf_pprop(intrfc, skb); if (rc) goto out_free_skb; } /* local processing follows */ if (!IPX_SKB_CB(skb)->ipx_dest_net) IPX_SKB_CB(skb)->ipx_dest_net = intrfc->if_netnum; if (!IPX_SKB_CB(skb)->ipx_source_net) IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum; /* it doesn't make sense to route a pprop packet, there's no meaning * in the ipx_dest_net for such packets */ if (ipx->ipx_type != IPX_TYPE_PPROP && intrfc->if_netnum != IPX_SKB_CB(skb)->ipx_dest_net) { /* We only route point-to-point packets. */ if (skb->pkt_type == PACKET_HOST) { skb = skb_unshare(skb, GFP_ATOMIC); if (skb) rc = ipxrtr_route_skb(skb); goto out_intrfc; } goto out_free_skb; } /* see if we should keep it */ if (!memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) || !memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN)) { rc = ipxitf_demux_socket(intrfc, skb, 0); goto out_intrfc; } /* we couldn't pawn it off so unload it */ out_free_skb: kfree_skb(skb); out_intrfc: ipxitf_put(intrfc); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds22787.64%220.00%
pre-gitpre-git228.49%660.00%
arnaldo carvalho de meloarnaldo carvalho de melo103.86%220.00%
Total259100.00%10100.00%


static void ipxitf_discover_netnum(struct ipx_interface *intrfc, struct sk_buff *skb) { const struct ipx_cb *cb = IPX_SKB_CB(skb); /* see if this is an intra packet: source_net == dest_net */ if (cb->ipx_source_net == cb->ipx_dest_net && cb->ipx_source_net) { struct ipx_interface *i = ipxitf_find_using_net(cb->ipx_source_net); /* NB: NetWare servers lie about their hop count so we * dropped the test based on it. This is the best way * to determine this is a 0 hop count packet. */ if (!i) { intrfc->if_netnum = cb->ipx_source_net; ipxitf_add_local_route(intrfc); } else { printk(KERN_WARNING "IPX: Network number collision " "%lx\n %s %s and %s %s\n", (unsigned long) ntohl(cb->ipx_source_net), ipx_device_name(i), ipx_frame_name(i->if_dlink_type), ipx_device_name(intrfc), ipx_frame_name(intrfc->if_dlink_type)); ipxitf_put(i); } } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7155.91%866.67%
linus torvaldslinus torvalds5341.73%216.67%
arnaldo carvalho de meloarnaldo carvalho de melo21.57%18.33%
al viroal viro10.79%18.33%
Total127100.00%12100.00%

/** * ipxitf_pprop - Process packet propagation IPX packet type 0x14, used for * NetBIOS broadcasts * @intrfc: IPX interface receiving this packet * @skb: Received packet * * Checks if packet is valid: if its more than %IPX_MAX_PPROP_HOPS hops or if it * is smaller than a IPX header + the room for %IPX_MAX_PPROP_HOPS hops we drop * it, not even processing it locally, if it has exact %IPX_MAX_PPROP_HOPS we * don't broadcast it, but process it locally. See chapter 5 of Novell's "IPX * RIP and SAP Router Specification", Part Number 107-000029-001. * * If it is valid, check if we have pprop broadcasting enabled by the user, * if not, just return zero for local processing. * * If it is enabled check the packet and don't broadcast it if we have already * seen this packet. * * Broadcast: send it to the interfaces that aren't on the packet visited nets * array, just after the IPX header. * * Returns -EINVAL for invalid packets, so that the calling function drops * the packet without local processing. 0 if packet is to be locally processed. */
static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) { struct ipxhdr *ipx = ipx_hdr(skb); int i, rc = -EINVAL; struct ipx_interface *ifcs;