cregit-Linux how code gets into the kernel

Release 4.11 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 <linux/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 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
Linus Torvalds (pre-git)2184.00%133.33%
Linus Torvalds28.00%133.33%
Arnaldo 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
Linus Torvalds (pre-git)4493.62%466.67%
Arnaldo Carvalho de Melo24.26%116.67%
Al 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
Linus Torvalds (pre-git)3857.58%342.86%
Arnaldo Carvalho de Melo2537.88%342.86%
Linus 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
Linus Torvalds (pre-git)2793.10%466.67%
Pavel Emelyanov13.45%116.67%
Arnaldo Carvalho de Melo13.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
Linus Torvalds (pre-git)1257.14%266.67%
Arnaldo 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
Linus Torvalds (pre-git)3054.55%450.00%
Arnaldo Carvalho de Melo2036.36%225.00%
Linus Torvalds47.27%112.50%
Al 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
Linus Torvalds (pre-git)5194.44%133.33%
Arnaldo Carvalho de Melo23.70%133.33%
Al 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
Linus Torvalds (pre-git)5063.29%350.00%
Arnaldo Carvalho de Melo2835.44%233.33%
Al 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
Linus Torvalds (pre-git)5285.25%562.50%
Arnaldo Carvalho de Melo69.84%225.00%
David 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
Linus Torvalds (pre-git)2754.00%550.00%
Arnaldo Carvalho de Melo1530.00%220.00%
Linus Torvalds48.00%110.00%
David S. Miller36.00%110.00%
Al 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
Linus Torvalds (pre-git)5696.55%250.00%
Arnaldo Carvalho de Melo11.72%125.00%
Al 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
Linus Torvalds (pre-git)7270.59%436.36%
Arnaldo Carvalho de Melo1716.67%436.36%
David S. Miller1110.78%19.09%
Al Viro10.98%19.09%
Linus Torvalds10.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
Linus Torvalds (pre-git)11271.34%642.86%
Arnaldo Carvalho de Melo2817.83%535.71%
David S. Miller117.01%17.14%
Thomas Graf53.18%17.14%
Adrian 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
Linus Torvalds (pre-git)2696.30%150.00%
Arnaldo 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 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
Linus Torvalds (pre-git)6755.37%642.86%
Linus Torvalds2319.01%214.29%
Arnaldo Carvalho de Melo119.09%214.29%
Eric W. Biedermann97.44%17.14%
Hideaki Yoshifuji / 吉藤英明86.61%214.29%
Jiri 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 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
Linus Torvalds (pre-git)3196.88%375.00%
Linus 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
Linus Torvalds (pre-git)16681.77%853.33%
Arnaldo Carvalho de Melo157.39%426.67%
David S. Miller115.42%16.67%
Linus 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
Linus Torvalds (pre-git)13870.77%550.00%
Linus Torvalds3316.92%220.00%
Arnaldo Carvalho de Melo2110.77%220.00%
David 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
Linus Torvalds (pre-git)17459.39%866.67%
Linus Torvalds9933.79%216.67%
Arnaldo 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
Linus Torvalds (pre-git)11273.20%763.64%
Arnaldo Carvalho de Melo2315.03%327.27%
Linus 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
Linus Torvalds (pre-git)29765.56%1460.87%
Linus Torvalds14331.57%313.04%
Arnaldo Carvalho de Melo61.32%28.70%
Al Viro30.66%14.35%
Hideaki Yoshifuji / 吉藤英明20.44%14.35%
David S. Miller10.22%14.35%
Steven Cole10.22%14.35%
Total453100.00%23100.00%


static int ipxitf_add_local_route(struct ipx_interface *intrfc) { return ipxrtr_add_route(