Remove SPX and the last typedefs in IPX, create ipx_hdr

parent d52a86be
......@@ -24,15 +24,13 @@ struct sockaddr_ipx
#define IPX_DLTITF 0
#define IPX_CRTITF 1
typedef struct ipx_route_definition
{
struct ipx_route_definition {
__u32 ipx_network;
__u32 ipx_router_network;
unsigned char ipx_router_node[IPX_NODE_LEN];
} ipx_route_definition;
};
typedef struct ipx_interface_definition
{
struct ipx_interface_definition {
__u32 ipx_network;
unsigned char ipx_device[16];
unsigned char ipx_dlink_type;
......@@ -47,13 +45,12 @@ typedef struct ipx_interface_definition
#define IPX_PRIMARY 1
#define IPX_INTERNAL 2
unsigned char ipx_node[IPX_NODE_LEN];
} ipx_interface_definition;
};
typedef struct ipx_config_data
{
struct ipx_config_data {
unsigned char ipxcfg_auto_select_primary;
unsigned char ipxcfg_auto_create_interfaces;
} ipx_config_data;
};
/*
* OLD Route Definition for backward compatibility.
......@@ -77,13 +74,4 @@ struct ipx_route_def
#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE+1)
#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE+2)
#define SIOCIPXNCPCONN (SIOCPROTOPRIVATE+3)
#ifdef __KERNEL__
#include <linux/skbuff.h>
extern int ipxrtr_route_skb(struct sk_buff *);
extern int ipx_if_offset(unsigned long ipx_net_number);
extern void ipx_remove_socket(struct sock *sk);
#endif /* def __KERNEL__ */
#endif /* def _IPX_H_ */
......@@ -182,7 +182,6 @@ struct sk_buff {
struct icmphdr *icmph;
struct igmphdr *igmph;
struct iphdr *ipiph;
struct spxhdr *spxh;
unsigned char *raw;
} h;
......@@ -190,7 +189,6 @@ struct sk_buff {
struct iphdr *iph;
struct ipv6hdr *ipv6h;
struct arphdr *arph;
struct ipxhdr *ipxh;
unsigned char *raw;
} nh;
......
......@@ -14,12 +14,11 @@
#include <net/datalink.h>
#include <linux/ipx.h>
typedef struct
{
struct ipx_address {
__u32 net;
__u8 node[IPX_NODE_LEN];
__u16 sock;
} ipx_address;
};
#define ipx_broadcast_node "\377\377\377\377\377\377"
#define ipx_this_node "\0\0\0\0\0\0"
......@@ -39,11 +38,16 @@ struct ipxhdr
#define IPX_TYPE_SPX 0x05 /* SPX protocol */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */
ipx_address ipx_dest __attribute__ ((packed));
ipx_address ipx_source __attribute__ ((packed));
struct ipx_address ipx_dest __attribute__ ((packed));
struct ipx_address ipx_source __attribute__ ((packed));
};
typedef struct ipx_interface {
static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb)
{
return (struct ipxhdr *)skb->h.raw;
}
struct ipx_interface {
/* IPX address */
__u32 if_netnum;
unsigned char if_node[IPX_NODE_LEN];
......@@ -65,16 +69,16 @@ typedef struct ipx_interface {
unsigned char if_primary;
struct ipx_interface *if_next;
} ipx_interface;
};
typedef struct ipx_route {
struct ipx_route {
__u32 ir_net;
ipx_interface *ir_intrfc;
struct ipx_interface *ir_intrfc;
unsigned char ir_routed;
unsigned char ir_router_node[IPX_NODE_LEN];
struct ipx_route *ir_next;
struct ipx_route *ir_next;
atomic_t refcnt;
} ipx_route;
};
#ifdef __KERNEL__
struct ipx_cb {
......@@ -88,8 +92,8 @@ struct ipx_cb {
};
struct ipx_opt {
ipx_address dest_addr;
ipx_interface *intrfc;
struct ipx_address dest_addr;
struct ipx_interface *intrfc;
unsigned short port;
#ifdef CONFIG_IPX_INTERN
unsigned char node[IPX_NODE_LEN];
......@@ -106,7 +110,4 @@ struct ipx_opt {
#define IPX_MIN_EPHEMERAL_SOCKET 0x4000
#define IPX_MAX_EPHEMERAL_SOCKET 0x7fff
extern int ipx_register_spx(struct proto_ops **, struct net_proto_family *);
extern int ipx_unregister_spx(void);
#endif /* def _NET_INET_IPX_H_ */
#ifndef __NET_SPX_H
#define __NET_SPX_H
#include <net/ipx.h>
struct spxhdr
{ __u8 cctl;
__u8 dtype;
#define SPX_DTYPE_ECONN 0xFE /* Finished */
#define SPX_DTYPE_ECACK 0xFF /* Ok */
__u16 sconn; /* Connection ID */
__u16 dconn; /* Connection ID */
__u16 sequence;
__u16 ackseq;
__u16 allocseq;
};
struct ipxspxhdr
{ struct ipxhdr ipx;
struct spxhdr spx;
};
#define SPX_SYS_PKT_LEN (sizeof(struct ipxspxhdr))
#ifdef __KERNEL__
struct spx_opt
{ int state;
int sndbuf;
int retries; /* Number of WD retries */
int retransmits; /* Number of retransmits */
int max_retries;
int wd_interval;
void *owner;
__u16 dest_connid; /* Net order */
__u16 source_connid; /* Net order */
__u16 sequence; /* Host order - our current pkt # */
__u16 alloc; /* Host order - max seq we can rcv now */
__u16 rmt_ack; /* Host order - last pkt ACKd by remote */
__u16 rmt_seq;
__u16 acknowledge;
__u16 rmt_alloc; /* Host order - max seq remote can handle now */
ipx_address dest_addr;
ipx_address source_addr;
struct timer_list watchdog; /* Idle watch */
struct timer_list retransmit; /* Retransmit timer */
struct sk_buff_head rcv_queue;
struct sk_buff_head transmit_queue;
struct sk_buff_head retransmit_queue;
};
#define spx_sk(__sk) ((struct spx_opt *)(((struct sock *)(__sk)) + 1))
/* Packet connectino control defines */
#define CCTL_SPXII_XHD 0x01 /* SPX2 extended header */
#define CCTL_SPX_UNKNOWN 0x02 /* Unknown (unused ??) */
#define CCTL_SPXII_NEG 0x04 /* Negotiate size */
#define CCTL_SPXII 0x08 /* Set for SPX2 */
#define CCTL_EOM 0x10 /* End of message marker */
#define CCTL_URG 0x20 /* Urgent marker in SPP (not used in SPX?) */
#define CCTL_ACK 0x40 /* Send me an ACK */
#define CCTL_CTL 0x80 /* Control message */
#define CCTL_SYS CCTL_CTL /* Spec uses CCTL_SYS */
/* Connection state defines */
#define SPX_CLOSED 7
#define SPX_CONNECTING 8
#define SPX_CONNECTED 9
/* Packet transmit types - Internal */
#define DATA 0 /* Data */
#define ACK 1 /* Data ACK */
#define WDACK 2 /* WD ACK */
#define CONACK 3 /* Connection Request ACK */
#define CONREQ 4 /* Connection Request */
#define WDREQ 5 /* WD Request */
#define DISCON 6 /* Informed Disconnect */
#define DISACK 7 /* Informed Disconnect ACK */
#define RETRAN 8 /* Int. Retransmit of packet */
#define TQUEUE 9 /* Int. Transmit of a queued packet */
/*
* These are good canidates for IOcontrol calls
*/
/* Watchdog defines */
#define VERIFY_TIMEOUT 3 * HZ
#define ABORT_TIMEOUT 30 * HZ
/* Packet retransmit defines */
#define RETRY_COUNT 10
#define RETRY_TIME 1 * HZ
#define MAX_RETRY_DELAY 5 * HZ
#endif /* __KERNEL__ */
#endif /* def __NET_SPX_H */
......@@ -23,25 +23,3 @@ CONFIG_IPX_INTERN
If you don't know what you are doing, say N.
CONFIG_SPX
* Orphaned entry retained 20 April 2001 by Petr Vandrovec *
* If you read this note from the configurator, please contact *
* the Configure.help maintainers. *
The Sequenced Packet eXchange protocol is a transport layer protocol
built on top of IPX. It is used in Novell NetWare systems for
client-server applications and is similar to TCP (which runs on top
of IP).
Note that Novell NetWare file sharing does not use SPX; it uses a
protocol called NCP, for which separate Linux support is available
("NCP file system support" below for the client side, and the user
space programs lwared or mars_nwe for the server side).
Say Y here if you have use for SPX; read the IPX-HOWTO at
<http://www.linuxdoc.org/docs.html#howto> for details.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called af_spx.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
......@@ -3,6 +3,3 @@
#
bool ' IPX: Full internal IPX network' CONFIG_IPX_INTERN
#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
# dep_tristate ' IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
#fi
......@@ -8,7 +8,6 @@ obj-$(CONFIG_IPX) += ipx.o
ipx-y := af_ipx.o
ipx-$(CONFIG_SYSCTL) += sysctl_net_ipx.o
ipx-$(CONFIG_SPX) += af_spx.o
ipx-objs := $(ipx-y)
include $(TOPDIR)/Rules.make
......@@ -76,6 +76,7 @@
* Revision 048: Use sk->protinfo to store the pointer to IPX private
* area, remove af_ipx from sk->protinfo and move ipx_opt
* to include/net/ipx.h, use IPX_SK like DecNET, etc
* Revision 049: SPX support dropped, see comment in ipx_create
*
* Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
* pair. Also, now usage count is managed this way
......@@ -144,17 +145,14 @@ static struct datalink_proto *pSNAP_datalink;
static struct proto_ops ipx_dgram_ops;
static struct net_proto_family *spx_family_ops;
static DECLARE_RWSEM(spx_family_ops_lock);
static ipx_route *ipx_routes;
static struct ipx_route *ipx_routes;
static rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED;
static ipx_interface *ipx_interfaces;
static struct ipx_interface *ipx_interfaces;
static spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;
static ipx_interface *ipx_primary_net;
static ipx_interface *ipx_internal_net;
static struct ipx_interface *ipx_primary_net;
static struct ipx_interface *ipx_internal_net;
#undef IPX_REFCNT_DEBUG
#ifdef IPX_REFCNT_DEBUG
......@@ -180,9 +178,9 @@ static void ipxcfg_set_auto_select(char val)
ipx_primary_net = ipx_interfaces;
}
static int ipxcfg_get_config_data(ipx_config_data *arg)
static int ipxcfg_get_config_data(struct ipx_config_data *arg)
{
ipx_config_data vals;
struct ipx_config_data vals;
vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces;
vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary;
......@@ -192,22 +190,22 @@ static int ipxcfg_get_config_data(ipx_config_data *arg)
/* Handlers for the socket list. */
static inline void ipxitf_hold(ipx_interface *intrfc)
static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
{
atomic_inc(&intrfc->refcnt);
}
static void ipxitf_down(ipx_interface *intrfc);
static void ipxitf_down(struct ipx_interface *intrfc);
static inline void ipxitf_put(ipx_interface *intrfc)
static __inline__ void ipxitf_put(struct ipx_interface *intrfc)
{
if (atomic_dec_and_test(&intrfc->refcnt))
ipxitf_down(intrfc);
}
static void __ipxitf_down(ipx_interface *intrfc);
static void __ipxitf_down(struct ipx_interface *intrfc);
static inline void __ipxitf_put(ipx_interface *intrfc)
static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
{
if (atomic_dec_and_test(&intrfc->refcnt))
__ipxitf_down(intrfc);
......@@ -218,11 +216,11 @@ static inline void __ipxitf_put(ipx_interface *intrfc)
* use this facility.
*/
void ipx_remove_socket(struct sock *sk)
static void ipx_remove_socket(struct sock *sk)
{
struct sock *s;
/* Determine interface with which socket is associated */
ipx_interface *intrfc = ipx_sk(sk)->intrfc;
struct ipx_interface *intrfc = ipx_sk(sk)->intrfc;
if (!intrfc)
goto out;
......@@ -268,7 +266,7 @@ static void ipx_destroy_socket(struct sock *sk)
* The following code is used to support IPX Interfaces (IPXITF). An
* IPX interface is defined by a physical device and a frame type.
*/
static ipx_route * ipxrtr_lookup(__u32);
static struct ipx_route *ipxrtr_lookup(__u32 net);
/* ipxitf_clear_primary_net has to be called with ipx_interfaces_lock held */
......@@ -277,10 +275,10 @@ static void ipxitf_clear_primary_net(void)
ipx_primary_net = ipxcfg_auto_select_primary ? ipx_interfaces : NULL;
}
static ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
unsigned short datalink)
static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
unsigned short datalink)
{
ipx_interface *i = ipx_interfaces;
struct ipx_interface *i = ipx_interfaces;
while (i && (i->if_dev != dev || i->if_dlink_type != datalink))
i = i->if_next;
......@@ -288,10 +286,10 @@ static ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
return i;
}
static ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
unsigned short datalink)
static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
unsigned short datalink)
{
ipx_interface *i;
struct ipx_interface *i;
spin_lock_bh(&ipx_interfaces_lock);
i = __ipxitf_find_using_phys(dev, datalink);
......@@ -301,9 +299,9 @@ static ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
return i;
}
static ipx_interface *ipxitf_find_using_net(__u32 net)
static struct ipx_interface *ipxitf_find_using_net(__u32 net)
{
ipx_interface *i;
struct ipx_interface *i;
spin_lock_bh(&ipx_interfaces_lock);
if (net)
......@@ -320,7 +318,7 @@ static ipx_interface *ipxitf_find_using_net(__u32 net)
}
/* Sockets are bound to a particular IPX interface. */
static void ipxitf_insert_socket(ipx_interface *intrfc, struct sock *sk)
static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk)
{
ipxitf_hold(intrfc);
sock_hold(sk);
......@@ -340,7 +338,7 @@ static void ipxitf_insert_socket(ipx_interface *intrfc, struct sock *sk)
}
/* caller must hold intrfc->if_sklist_lock */
static struct sock *__ipxitf_find_socket(ipx_interface *intrfc,
static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc,
unsigned short port)
{
struct sock *s = intrfc->if_sklist;
......@@ -352,7 +350,7 @@ static struct sock *__ipxitf_find_socket(ipx_interface *intrfc,
}
/* caller must hold a reference to intrfc */
static struct sock *ipxitf_find_socket(ipx_interface *intrfc,
static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc,
unsigned short port)
{
struct sock *s;
......@@ -367,8 +365,9 @@ static struct sock *ipxitf_find_socket(ipx_interface *intrfc,
}
#ifdef CONFIG_IPX_INTERN
static struct sock *ipxitf_find_internal_socket(ipx_interface *intrfc,
unsigned char *node, unsigned short port)
static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc,
unsigned char *node,
unsigned short port)
{
struct sock *s;
......@@ -391,9 +390,9 @@ static struct sock *ipxitf_find_internal_socket(ipx_interface *intrfc,
}
#endif
static void ipxrtr_del_routes(ipx_interface *);
static void ipxrtr_del_routes(struct ipx_interface *intrfc);
static void __ipxitf_down(ipx_interface *intrfc)
static void __ipxitf_down(struct ipx_interface *intrfc)
{
struct sock *s, *t;
......@@ -421,7 +420,7 @@ static void __ipxitf_down(ipx_interface *intrfc)
if (intrfc == ipx_interfaces)
ipx_interfaces = intrfc->if_next;
else {
ipx_interface *i = ipx_interfaces;
struct ipx_interface *i = ipx_interfaces;
while (i && i->if_next != intrfc)
i = i->if_next;
if (i && i->if_next == intrfc)
......@@ -440,7 +439,7 @@ static void __ipxitf_down(ipx_interface *intrfc)
MOD_DEC_USE_COUNT;
}
static void ipxitf_down(ipx_interface *intrfc)
static void ipxitf_down(struct ipx_interface *intrfc)
{
spin_lock_bh(&ipx_interfaces_lock);
__ipxitf_down(intrfc);
......@@ -451,7 +450,7 @@ static int ipxitf_device_event(struct notifier_block *notifier,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
ipx_interface *i, *tmp;
struct ipx_interface *i, *tmp;
if (event != NETDEV_DOWN && event != NETDEV_UP)
goto out;
......@@ -484,10 +483,10 @@ static void ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb)
/* caller must hold a reference to intrfc */
#ifdef CONFIG_IPX_INTERN
static int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb,
int copy)
static int ipxitf_demux_socket(struct ipx_interface *intrfc,
struct sk_buff *skb, int copy)
{
struct ipxhdr *ipx = skb->nh.ipxh;
struct ipxhdr *ipx = ipx_hdr(skb);
int is_broadcast = !memcmp(ipx->ipx_dest.node, ipx_broadcast_node,
IPX_NODE_LEN);
struct sock *s;
......@@ -532,7 +531,7 @@ out: spin_unlock_bh(&intrfc->if_sklist_lock);
return ret;
}
#else
static struct sock *ncp_connection_hack(ipx_interface *intrfc,
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
......@@ -566,10 +565,10 @@ static struct sock *ncp_connection_hack(ipx_interface *intrfc,
return sk;
}
static int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb,
int copy)
static int ipxitf_demux_socket(struct ipx_interface *intrfc,
struct sk_buff *skb, int copy)
{
struct ipxhdr *ipx = skb->nh.ipxh;
struct ipxhdr *ipx = ipx_hdr(skb);
struct sock *sock1 = NULL, *sock2 = NULL;
struct sk_buff *skb1 = NULL, *skb2 = NULL;
int ret;
......@@ -651,11 +650,11 @@ out: if (sock1)
}
#endif /* CONFIG_IPX_INTERN */
static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc,
static struct sk_buff *ipxitf_adjust_skbuff(struct ipx_interface *intrfc,
struct sk_buff *skb)
{
struct sk_buff *skb2;
int in_offset = skb->h.raw - skb->head;
int in_offset = (unsigned char *)ipx_hdr(skb) - skb->head;
int out_offset = intrfc->if_ipx_offset;
int len;
......@@ -669,7 +668,7 @@ static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc,
if (skb2) {
skb_reserve(skb2, out_offset);
skb2->nh.raw = skb2->h.raw = skb_put(skb2, skb->len);
memcpy(skb2->h.raw, skb->h.raw, skb->len);
memcpy(ipx_hdr(skb2), ipx_hdr(skb), skb->len);
memcpy(skb2->cb, skb->cb, sizeof(skb->cb));
}
kfree_skb(skb);
......@@ -678,9 +677,10 @@ static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc,
/* caller must hold a reference to intrfc and the skb has to be unshared */
static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
static int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb,
char *node)
{
struct ipxhdr *ipx = skb->nh.ipxh;
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];
......@@ -784,21 +784,24 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
out: return 0;
}
static int ipxrtr_add_route(__u32, ipx_interface *, unsigned char *);
static int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
unsigned char *);
static int ipxitf_add_local_route(ipx_interface *intrfc)
static int ipxitf_add_local_route(struct ipx_interface *intrfc)
{
return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL);
}
static const char * ipx_frame_name(unsigned short);
static const char * ipx_device_name(ipx_interface *);
static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb);
static int ipxitf_pprop(ipx_interface *intrfc, struct sk_buff *skb);
static const char *ipx_frame_name(unsigned short);
static const char *ipx_device_name(struct ipx_interface *);
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 ipxrtr_route_skb(struct sk_buff *skb);
static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
static int ipxitf_rcv(struct ipx_interface *intrfc, struct sk_buff *skb)
{
struct ipxhdr *ipx = skb->nh.ipxh;
struct ipxhdr *ipx = ipx_hdr(skb);
int ret = 0;
ipxitf_hold(intrfc);
......@@ -850,13 +853,15 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
return ret;
}
static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb)
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) {
ipx_interface *i = ipxitf_find_using_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. */
......@@ -900,11 +905,11 @@ static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb)
* 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(ipx_interface *intrfc, struct sk_buff *skb)
static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb)
{
struct ipxhdr *ipx = skb->nh.ipxh;
struct ipxhdr *ipx = ipx_hdr(skb);
int i, ret = -EINVAL;
ipx_interface *ifcs;
struct ipx_interface *ifcs;
char *c;
u32 *l;
......@@ -968,14 +973,14 @@ static int ipxitf_pprop(ipx_interface *intrfc, struct sk_buff *skb)
out: return ret;
}
static void ipxitf_insert(ipx_interface *intrfc)
static void ipxitf_insert(struct ipx_interface *intrfc)
{
intrfc->if_next = NULL;
spin_lock_bh(&ipx_interfaces_lock);
if (!ipx_interfaces)
ipx_interfaces = intrfc;
else {
ipx_interface *i = ipx_interfaces;
struct ipx_interface *i = ipx_interfaces;
while (i->if_next)
i = i->if_next;
i->if_next = intrfc;
......@@ -986,12 +991,13 @@ static void ipxitf_insert(ipx_interface *intrfc)
ipx_primary_net = intrfc;
}
static ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum,
unsigned short dlink_type,
struct datalink_proto *dlink,
unsigned char internal, int ipx_offset)
static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum,
unsigned short dlink_type,
struct datalink_proto *dlink,
unsigned char internal,
int ipx_offset)
{
ipx_interface *intrfc = kmalloc(sizeof(*intrfc), GFP_ATOMIC);
struct ipx_interface *intrfc = kmalloc(sizeof(*intrfc), GFP_ATOMIC);
if (intrfc) {
intrfc->if_dev = dev;
......@@ -1010,9 +1016,9 @@ static ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum,
return intrfc;
}
static int ipxitf_create_internal(ipx_interface_definition *idef)
static int ipxitf_create_internal(struct ipx_interface_definition *idef)
{
ipx_interface *intrfc;
struct ipx_interface *intrfc;
int ret = -EEXIST;
/* Only one primary network allowed */
......@@ -1061,12 +1067,12 @@ static int ipx_map_frame_type(unsigned char type)
return ret;
}
static int ipxitf_create(ipx_interface_definition *idef)
static int ipxitf_create(struct ipx_interface_definition *idef)
{
struct net_device *dev;
unsigned short dlink_type = 0;
struct datalink_proto *datalink = NULL;
ipx_interface *intrfc;
struct ipx_interface *intrfc;
int err;
if (idef->ipx_special == IPX_INTERNAL) {
......@@ -1173,11 +1179,11 @@ static int ipxitf_create(ipx_interface_definition *idef)
out: return err;
}
static int ipxitf_delete(ipx_interface_definition *idef)
static int ipxitf_delete(struct ipx_interface_definition *idef)
{
struct net_device *dev = NULL;
unsigned short dlink_type = 0;
ipx_interface *intrfc;
struct ipx_interface *intrfc;
int ret = 0;
spin_lock_bh(&ipx_interfaces_lock);
......@@ -1211,10 +1217,10 @@ out: spin_unlock_bh(&ipx_interfaces_lock);
return ret;
}
static ipx_interface *ipxitf_auto_create(struct net_device *dev,
unsigned short dlink_type)
static struct ipx_interface *ipxitf_auto_create(struct net_device *dev,
unsigned short dlink_type)
{
ipx_interface *intrfc = NULL;
struct ipx_interface *intrfc = NULL;
struct datalink_proto *datalink;
if (!dev)
......@@ -1269,7 +1275,7 @@ static int ipxitf_ioctl(unsigned int cmd, void *arg)
switch (cmd) {
case SIOCSIFADDR: {
struct sockaddr_ipx *sipx;
ipx_interface_definition f;
struct ipx_interface_definition f;
if (copy_from_user(&ifr, arg, sizeof(ifr)))
return -EFAULT;
......@@ -1294,7 +1300,7 @@ static int ipxitf_ioctl(unsigned int cmd, void *arg)
case SIOCGIFADDR: {
int err = 0;
struct sockaddr_ipx *sipx;
ipx_interface *ipxif;
struct ipx_interface *ipxif;
struct net_device *dev;
if (copy_from_user(&ifr, arg, sizeof(ifr)))
......@@ -1341,20 +1347,20 @@ static int ipxitf_ioctl(unsigned int cmd, void *arg)
/* Routing tables for the IPX socket layer. */
static inline void ipxrtr_hold(ipx_route *rt)
static __inline__ void ipxrtr_hold(struct ipx_route *rt)
{
atomic_inc(&rt->refcnt);
}
static inline void ipxrtr_put(ipx_route *rt)
static __inline__ void ipxrtr_put(struct ipx_route *rt)
{
if (atomic_dec_and_test(&rt->refcnt))
kfree(rt);
}
static ipx_route *ipxrtr_lookup(__u32 net)
static struct ipx_route *ipxrtr_lookup(__u32 net)
{
ipx_route *r;
struct ipx_route *r;
read_lock_bh(&ipx_routes_lock);
for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next)
......@@ -1368,16 +1374,16 @@ static ipx_route *ipxrtr_lookup(__u32 net)
/* caller must hold a reference to intrfc */
static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc,
unsigned char *node)
static int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
unsigned char *node)
{
ipx_route *rt;
struct ipx_route *rt;
int ret;
/* Get a route structure; either existing or create */
rt = ipxrtr_lookup(network);
if (!rt) {
rt = kmalloc(sizeof(ipx_route), GFP_ATOMIC);
rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
ret = -EAGAIN;
if (!rt)
goto out;
......@@ -1410,9 +1416,9 @@ static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc,
out: return ret;
}
static void ipxrtr_del_routes(ipx_interface *intrfc)
static void ipxrtr_del_routes(struct ipx_interface *intrfc)
{
ipx_route **r, *tmp;
struct ipx_route **r, *tmp;
write_lock_bh(&ipx_routes_lock);
for (r = &ipx_routes; (tmp = *r) != NULL;) {
......@@ -1425,9 +1431,9 @@ static void ipxrtr_del_routes(ipx_interface *intrfc)
write_unlock_bh(&ipx_routes_lock);
}
static int ipxrtr_create(ipx_route_definition *rd)
static int ipxrtr_create(struct ipx_route_definition *rd)
{
ipx_interface *intrfc;
struct ipx_interface *intrfc;
int ret = -ENETUNREACH;
/* Find the appropriate interface */
......@@ -1441,8 +1447,8 @@ out: return ret;
static int ipxrtr_delete(long net)
{
ipx_route **r;
ipx_route *tmp;
struct ipx_route **r;
struct ipx_route *tmp;
int err;
write_lock_bh(&ipx_routes_lock);
......@@ -1513,11 +1519,11 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
{
struct sk_buff *skb;
struct ipx_opt *ipxs = ipx_sk(sk);
ipx_interface *intrfc;
struct ipx_interface *intrfc;
struct ipxhdr *ipx;
int size;
int ipx_offset;
ipx_route *rt = NULL;
struct ipx_route *rt = NULL;
int err;
/* Find the appropriate interface on which to send packet */
......@@ -1544,11 +1550,11 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
skb->sk = sk;
/* Fill in IPX header */
ipx = (struct ipxhdr *)skb_put(skb, sizeof(struct ipxhdr));
skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxhdr));
ipx = ipx_hdr(skb);
ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr));
IPX_SKB_CB(skb)->ipx_tctrl = 0;
ipx->ipx_type = usipx->sipx_type;
skb->h.raw = (void *)skb->nh.ipxh = ipx;
IPX_SKB_CB(skb)->last_hop.index = -1;
#ifdef CONFIG_IPX_INTERN
......@@ -1596,8 +1602,8 @@ out: return err;
* modify the packet */
int ipxrtr_route_skb(struct sk_buff *skb)
{
struct ipxhdr *ipx = skb->nh.ipxh;
ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net);
struct ipxhdr *ipx = ipx_hdr(skb);
struct ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net);
if (!r) { /* no known route */
kfree_skb(skb);
......@@ -1666,7 +1672,7 @@ static const char *ipx_frame_name(unsigned short frame)
return ret;
}
static const char *ipx_device_name(ipx_interface *intrfc)
static const char *ipx_device_name(struct ipx_interface *intrfc)
{
return intrfc->if_internal ? "Internal" :
intrfc->if_dev ? intrfc->if_dev->name : "Unknown";
......@@ -1676,7 +1682,7 @@ static const char *ipx_device_name(ipx_interface *intrfc)
static int ipx_interface_get_info(char *buffer, char **start, off_t offset,
int length)
{
ipx_interface *i;
struct ipx_interface *i;
off_t begin = 0, pos = 0;
int len = 0;
......@@ -1728,7 +1734,7 @@ static int ipx_interface_get_info(char *buffer, char **start, off_t offset,
static int ipx_get_info(char *buffer, char **start, off_t offset, int length)
{
struct sock *s;
ipx_interface *i;
struct ipx_interface *i;
off_t begin = 0, pos = 0;
int len = 0;
......@@ -1808,7 +1814,7 @@ static int ipx_get_info(char *buffer, char **start, off_t offset, int length)
static int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length)
{
ipx_route *rt;
struct ipx_route *rt;
off_t begin = 0, pos = 0;
int len = 0;
......@@ -1927,17 +1933,11 @@ static int ipx_create(struct socket *sock, int protocol)
case SOCK_SEQPACKET:
/*
* From this point on SPX sockets are handled
* by af_spx.c and the methods replaced.
* SPX support is not anymore in the kernel sources. If
* you want to ressurrect it, completing it and making
* it understand shared skbs, be fully multithreaded,
* etc, grab the sources in an early 2.5 kernel tree.
*/
down_read(&spx_family_ops_lock);
if (spx_family_ops) {
ret = spx_family_ops->create(sock, protocol);
up_read(&spx_family_ops_lock);
goto decmod;
}
up_read(&spx_family_ops_lock);
/* Fall through if SPX is not loaded */
case SOCK_STREAM: /* Allow higher levels to piggyback */
default:
goto decmod;
......@@ -1978,7 +1978,7 @@ out: return 0;
/* caller must hold a reference to intrfc */
static unsigned short ipx_first_free_socketnum(ipx_interface *intrfc)
static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc)
{
unsigned short socketNum = intrfc->if_sknum;
......@@ -2003,7 +2003,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
struct ipx_opt *ipxs = ipx_sk(sk);
ipx_interface *intrfc;
struct ipx_interface *intrfc;
struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;
int ret = -EINVAL;
......@@ -2101,7 +2101,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
struct ipx_opt *ipxs = ipx_sk(sk);
struct sockaddr_ipx *addr;
int ret = -EINVAL;
ipx_route *rt;
struct ipx_route *rt;
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
......@@ -2158,7 +2158,7 @@ out: return ret;
static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
int *uaddr_len, int peer)
{
ipx_address *addr;
struct ipx_address *addr;
struct sockaddr_ipx sipx;
struct sock *sk = sock->sk;
struct ipx_opt *ipxs = ipx_sk(sk);
......@@ -2204,7 +2204,7 @@ out: return ret;
int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
/* NULL here for pt means the packet was looped back */
ipx_interface *intrfc;
struct ipx_interface *intrfc;
struct ipxhdr *ipx;
u16 ipx_pktsize;
int ret = 0;
......@@ -2216,7 +2216,7 @@ int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
goto out;
ipx = skb->nh.ipxh;
ipx = ipx_hdr(skb);
ipx_pktsize = ntohs(ipx->ipx_pktsize);
/* Too small or invalid header? */
......@@ -2352,7 +2352,7 @@ static int ipx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
if (!skb)
goto out;
ipx = skb->nh.ipxh;
ipx = ipx_hdr(skb);
copied = ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr);
if (copied > size) {
copied = size;
......@@ -2461,64 +2461,33 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return 0;
}
/*
* SPX interface support
*/
int ipx_register_spx(struct proto_ops **p, struct net_proto_family *spx)
{
int err;
err = -EBUSY;
down_write(&spx_family_ops_lock);
if (!spx_family_ops) {
MOD_INC_USE_COUNT;
*p = &ipx_dgram_ops;
spx_family_ops = spx;
}
up_write(&spx_family_ops_lock);
return 0;
}
int ipx_unregister_spx(void)
{
down_write(&spx_family_ops_lock);
if (spx_family_ops) {
spx_family_ops = NULL;
MOD_DEC_USE_COUNT;
}
up_write(&spx_family_ops_lock);
return 0;
}
/*
* Socket family declarations
*/
static struct net_proto_family ipx_family_ops = {
.family = PF_IPX,
.create = ipx_create,
.family = PF_IPX,
.create = ipx_create,
};
static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
.family = PF_IPX,
.release = ipx_release,
.bind = ipx_bind,
.connect = ipx_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = ipx_getname,
.poll = datagram_poll,
.ioctl = ipx_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown, /* FIXME: have to support shutdown */
.setsockopt = ipx_setsockopt,
.getsockopt = ipx_getsockopt,
.sendmsg = ipx_sendmsg,
.recvmsg = ipx_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
.family = PF_IPX,
.release = ipx_release,
.bind = ipx_bind,
.connect = ipx_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = ipx_getname,
.poll = datagram_poll,
.ioctl = ipx_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown, /* FIXME: support shutdown */
.setsockopt = ipx_setsockopt,
.getsockopt = ipx_getsockopt,
.sendmsg = ipx_sendmsg,
.recvmsg = ipx_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
#include <linux/smp_lock.h>
......@@ -2540,7 +2509,6 @@ static struct notifier_block ipx_dev_notifier = {
.notifier_call =ipxitf_device_event,
};
extern struct datalink_proto *make_EII_client(void);
extern struct datalink_proto *make_8023_client(void);
extern void destroy_EII_client(struct datalink_proto *);
......@@ -2549,9 +2517,13 @@ extern void destroy_8023_client(struct datalink_proto *);
static unsigned char ipx_8022_type = 0xE0;
static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
static char ipx_banner[] __initdata =
KERN_INFO "NET4: Linux IPX 0.48 for NET4.0\n"
KERN_INFO "NET4: Linux IPX 0.49 for NET4.0\n"
KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \
KERN_INFO "IPX Portions Copyright (c) 2000, 2001 Conectiva, Inc.\n";
static char ipx_EII_err_msg[] __initdata =
KERN_CRIT "IPX: Unable to register with Ethernet II\n";
static char ipx_8023_err_msg[] __initdata =
KERN_CRIT "IPX: Unable to register with 802.3\n";
static char ipx_llc_err_msg[] __initdata =
KERN_CRIT "IPX: Unable to register with 802.2\n";
static char ipx_snap_err_msg[] __initdata =
......@@ -2562,10 +2534,16 @@ static int __init ipx_init(void)
sock_register(&ipx_family_ops);
pEII_datalink = make_EII_client();
dev_add_pack(&ipx_dix_packet_type);
if (pEII_datalink)
dev_add_pack(&ipx_dix_packet_type);
else
printk(ipx_EII_err_msg);
p8023_datalink = make_8023_client();
dev_add_pack(&ipx_8023_packet_type);
if (p8023_datalink)
dev_add_pack(&ipx_8023_packet_type);
else
printk(ipx_8023_err_msg);
p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv);
if (!p8022_datalink)
......@@ -2588,26 +2566,6 @@ static int __init ipx_init(void)
module_init(ipx_init);
/* Higher layers need this info to prep tx pkts */
int ipx_if_offset(unsigned long ipx_net_number)
{
ipx_route *rt = ipxrtr_lookup(ipx_net_number);
int ret = -ENETUNREACH;
if (!rt)
goto out;
ret = rt->ir_intrfc->if_ipx_offset;
ipxrtr_put(rt);
out: return ret;
}
/* Export symbols for higher layers */
EXPORT_SYMBOL(ipxrtr_route_skb);
EXPORT_SYMBOL(ipx_if_offset);
EXPORT_SYMBOL(ipx_remove_socket);
EXPORT_SYMBOL(ipx_register_spx);
EXPORT_SYMBOL(ipx_unregister_spx);
/* Note on MOD_{INC,DEC}_USE_COUNT:
*
* Use counts are incremented/decremented when
......
/*
* This module implements the (SPP-derived) Sequenced Packet eXchange
* (SPX) protocol for Linux 2.1.X as specified in
* NetWare SPX Services Specification, Semantics and API
* Revision: 1.00
* Revision Date: February 9, 1993
*
* Developers:
* Jay Schulist <jschlst@samba.org>
* Jim Freeman <jfree@caldera.com>
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* Changes:
* Alan Cox : Fixed an skb_unshare check for NULL
* that crashed it under load. Renamed and
* made static the ipx ops. Removed the hack
* ipx methods interface. Dropped AF_SPX - its
* the wrong abstraction.
* Eduardo Trapani : Added a check for the return value of
* ipx_if_offset that crashed sock_alloc_send_skb.
* Added spx_datagram_poll() so that select()
* works now on SPX sockets. Added updating
* of the alloc count to follow rmt_seq.
* Arnaldo C. Melo : Use a private slabcache for the old tp_pinfo
* struct sock member, use spx_sk and ipx_sk
* Arnaldo C. Melo : Big CodingStyle cleanup, fixes some lock leaks,
* removes a leftover of the slabcache patch.
*
* 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 (at your option) any later version.
*
* None of the authors or maintainers or their employers admit
* liability nor provide warranty for any of this software.
* This material is provided "as is" and at no charge.
*/
#include <linux/module.h>
#include <net/ipx.h>
#include <net/spx.h>
#include <net/tcp.h>
#include <net/sock.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#include <linux/uio.h>
#include <linux/unistd.h>
#include <linux/poll.h>
static struct proto_ops *ipx_ops;
static struct proto_ops spx_ops;
static __u16 connids;
/* Functions needed for SPX connection start up */
static int spx_transmit(struct sock *sk,struct sk_buff *skb,int type,int len);
static void spx_retransmit(unsigned long data);
static void spx_watchdog(unsigned long data);
void spx_rcv(struct sock *sk, int bytes);
extern void ipx_remove_socket(struct sock *sk);
/* Datagram poll: the same code as datagram_poll() in net/core
but the right spx buffers are looked at and
there is no question on the type of the socket
*/
static unsigned int spx_datagram_poll(struct file * file, struct socket *sock,
poll_table *wait)
{
struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk);
unsigned int mask;
poll_wait(file, sk->sleep, wait);
mask = 0;
/* exceptional events? */
if (sk->err || !skb_queue_empty(&sk->error_queue))
mask |= POLLERR;
if (sk->shutdown & RCV_SHUTDOWN)
mask |= POLLHUP;
/* readable? */
if (!skb_queue_empty(&pdata->rcv_queue))
mask |= POLLIN | POLLRDNORM;
/* Need to check for termination and startup */
if (sk->state==TCP_CLOSE)
mask |= POLLHUP;
/* connection hasn't started yet? */
if (sk->state == TCP_SYN_SENT)
goto out;
/* writable? */
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
out: return mask;
}
/* Create the SPX specific data */
static int spx_sock_init(struct sock *sk)
{
struct spx_opt *pdata = spx_sk(sk);
pdata->state = SPX_CLOSED;
pdata->sequence = 0;
pdata->acknowledge = 0;
pdata->source_connid = htons(connids);
pdata->rmt_seq = 0;
connids++;
pdata->owner = (void *)sk;
pdata->sndbuf = sk->sndbuf;
pdata->watchdog.function = spx_watchdog;
pdata->watchdog.data = (unsigned long)sk;
pdata->wd_interval = VERIFY_TIMEOUT;
pdata->retransmit.function = spx_retransmit;
pdata->retransmit.data = (unsigned long)sk;
pdata->retransmits = 0;
pdata->retries = 0;
pdata->max_retries = RETRY_COUNT;
skb_queue_head_init(&pdata->rcv_queue);
skb_queue_head_init(&pdata->transmit_queue);
skb_queue_head_init(&pdata->retransmit_queue);
return 0;
}
static int spx_create(struct socket *sock, int protocol)
{
struct sock *sk;
int rc = -ENOMEM;
MOD_INC_USE_COUNT;
/* Called on connection receive so cannot be GFP_KERNEL */
sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1);
if (!sk)
goto decmod;
rc = -ESOCKTNOSUPPORT;
switch (sock->type) {
case SOCK_SEQPACKET:
sock->ops = &spx_ops;
break;
default:
sk_free(sk);
goto out;
}
rc = 0;
sock_init_data(sock, sk);
spx_sock_init(sk);
sk->data_ready = spx_rcv;
sk->destruct = NULL;
sk->no_check = 1;
out: return rc;
decmod: MOD_DEC_USE_COUNT;
goto out;
}
void spx_close_socket(struct sock *sk)
{
struct spx_opt *pdata = spx_sk(sk);
pdata->state = SPX_CLOSED;
sk->state = TCP_CLOSE;
del_timer(&pdata->retransmit);
del_timer(&pdata->watchdog);
}
void spx_destroy_socket(struct sock *sk)
{
struct spx_opt *pdata = spx_sk(sk);
ipx_remove_socket(sk);
skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&pdata->transmit_queue);
skb_queue_purge(&pdata->retransmit_queue);
skb_queue_purge(&pdata->rcv_queue);
sk_free(sk);
MOD_DEC_USE_COUNT;
}
/* Release an SPX socket */
static int spx_release(struct socket *sock)
{
struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk);
if (!sk)
goto out;
if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
if (pdata->state != SPX_CLOSED) {
spx_transmit(sk, NULL, DISCON, 0);
spx_close_socket(sk);
}
sock->sk = NULL;
sk->socket = NULL;
spx_destroy_socket(sk);
out: return 0;
}
/* Move a socket into listening state. */
static int spx_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
int rc = -EINVAL;
if (sock->state != SS_UNCONNECTED)
goto out;
rc = -EOPNOTSUPP;
if (sock->type != SOCK_SEQPACKET)
goto out;
rc = -EAGAIN;
if (sk->zapped)
goto out;
rc = 0;
sk->max_ack_backlog = backlog;
if (sk->state != TCP_LISTEN) {
sk->ack_backlog = 0;
sk->state = TCP_LISTEN;
}
sk->socket->flags |= __SO_ACCEPTCON;
out: return rc;
}
/* Accept a pending SPX connection */
static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk = sock->sk;
struct sock *newsk;
struct sk_buff *skb;
int rc = -EINVAL;
if (!sk || sk->state != TCP_LISTEN ||
sock->state != SS_UNCONNECTED || !(sock->flags & __SO_ACCEPTCON))
goto out;
rc = -EOPNOTSUPP;
if (sock->type != SOCK_SEQPACKET)
goto out;
cli();
do {
skb = skb_dequeue(&sk->receive_queue);
if (!skb) {
rc = -EWOULDBLOCK;
if (flags & O_NONBLOCK)
goto out_unlock;
interruptible_sleep_on(sk->sleep);
rc = -ERESTARTSYS;
if (signal_pending(current))
goto out_unlock;
}
} while (!skb);
newsk = skb->sk;
newsk->pair = NULL;
sti();
rc = spx_transmit(newsk, skb, CONACK, 0); /* Connection ACK */
if (rc)
goto out;
/* Now attach up the new socket */
sock->sk = NULL;
sk->ack_backlog--;
newsock->sk = newsk;
newsk->state = TCP_ESTABLISHED;
ipx_sk(newsk)->dest_addr = spx_sk(newsk)->dest_addr;
out: return rc;
out_unlock:
sti();
goto out;
}
/* Build a connection to an SPX socket */
static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk);
struct sockaddr_ipx src;
struct sk_buff *skb;
int size = sizeof(src);
int rc = ipx_ops->getname(sock, (struct sockaddr *)&src, &size, 0);
if (rc)
goto out;
pdata->source_addr.net = src.sipx_network;
memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
pdata->source_addr.sock = (unsigned short)src.sipx_port;
rc = ipx_ops->connect(sock, uaddr, addr_len, flags);
if (rc)
goto out;
pdata->dest_addr = ipx_sk(sk)->dest_addr;
pdata->state = SPX_CONNECTING;
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
/* Send Connection request */
rc = spx_transmit(sk, NULL, CONREQ, 0);
if (rc)
goto out;
cli();
do {
skb = skb_dequeue(&sk->receive_queue);
if (!skb) {
rc = -EWOULDBLOCK;
if (flags & O_NONBLOCK)
goto unlock;
interruptible_sleep_on(sk->sleep);
rc = -ERESTARTSYS;
if (signal_pending(current))
goto unlock;
}
} while (!skb);
rc = -ETIMEDOUT;
if (pdata->state == SPX_CLOSED) {
del_timer(&pdata->watchdog);
goto unlock;
}
rc = 0;
sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
kfree_skb(skb);
unlock: sti();
out: return rc;
}
/*
* Calculate the timeout for a packet. Thankfully SPX has a large
* fudge factor (3/4 secs) and does not pay much attention to RTT.
* As we simply have a default retry time of 1*HZ and a max retry
* time of 5*HZ. Between those values we increase the timeout based
* on the number of retransmit tries.
*
* FixMe: This is quite fake, but will work for now. (JS)
*/
static inline unsigned long spx_calc_rtt(int tries)
{
int rc;
if (tries < 1)
rc = RETRY_TIME;
else if (tries > 5)
rc = MAX_RETRY_DELAY;
else
rc = tries * HZ;
return rc;
}
static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
{
int rc = -ENOBUFS;
skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb)
goto out;
rc = 0;
switch (type) {
case CONREQ:
case DATA:
if (!skb_queue_empty(&pdata->retransmit_queue)) {
skb_queue_tail(&pdata->transmit_queue, skb);
goto out;
}
case TQUEUE: {
struct sk_buff *skb2;
pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
add_timer(&pdata->retransmit);
skb2 = skb_clone(skb, GFP_NOIO);
if (!skb2) {
rc = -ENOBUFS;
goto out;
}
skb_queue_tail(&pdata->retransmit_queue, skb2);
/* Fall thru */
}
case ACK:
case CONACK:
case WDREQ:
case WDACK:
case DISCON:
case DISACK:
case RETRAN:
default: /* Send data */
rc = ipxrtr_route_skb(skb);
if (rc)
kfree_skb(skb);
}
out: return rc;
}
/* SPX packet transmit engine */
static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
{
struct spx_opt *pdata = spx_sk(sk);
struct ipxspxhdr *ipxh;
unsigned long flags;
int rc;
if (!skb) {
int offset = ipx_if_offset(pdata->dest_addr.net);
int size = offset + sizeof(struct ipxspxhdr);
rc = -ENETUNREACH;
if (offset < 0)
goto out;
save_flags(flags);
cli();
skb = sock_alloc_send_skb(sk, size, 0, &err);
rc = -ENOMEM;
if (!skb) {
restore_flags(flags);
goto out;
}
skb_reserve(skb, offset);
skb->h.raw = skb->nh.raw =
skb_put(skb, sizeof(struct ipxspxhdr));
restore_flags(flags);
}
/* IPX header */
ipxh = (struct ipxspxhdr *)skb->nh.raw;
ipxh->ipx.ipx_checksum = 0xFFFF;
ipxh->ipx.ipx_pktsize = htons(SPX_SYS_PKT_LEN);
ipxh->ipx.ipx_tctrl = 0;
ipxh->ipx.ipx_type = IPX_TYPE_SPX;
ipxh->ipx.ipx_dest = pdata->dest_addr;
ipxh->ipx.ipx_source = pdata->source_addr;
/* SPX header */
ipxh->spx.dtype = 0;
ipxh->spx.sequence = htons(pdata->sequence);
ipxh->spx.ackseq = htons(pdata->rmt_seq);
ipxh->spx.sconn = pdata->source_connid;
ipxh->spx.dconn = pdata->dest_connid;
ipxh->spx.allocseq = htons(pdata->alloc);
/* Reset/Set WD timer */
mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
switch (type) {
case DATA: /* Data */
ipxh->ipx.ipx_pktsize = htons(SPX_SYS_PKT_LEN + len);
ipxh->spx.cctl = (CCTL_ACK | CCTL_EOM);
pdata->sequence++;
break;
case ACK: /* ACK */
pdata->rmt_seq++;
case WDACK: /* WD ACK */
case CONACK: /* Connection ACK */
ipxh->spx.cctl = CCTL_SYS;
ipxh->spx.ackseq = htons(pdata->rmt_seq);
break;
case CONREQ: /* Connection Request */
del_timer(&pdata->watchdog);
case WDREQ: /* WD Request */
pdata->source_connid = htons(connids++);
pdata->dest_connid = 0xFFFF;
pdata->alloc = 3 + pdata->rmt_seq;
ipxh->spx.cctl = CCTL_ACK | CCTL_SYS;
ipxh->spx.sconn = pdata->source_connid;
ipxh->spx.dconn = pdata->dest_connid;
ipxh->spx.allocseq = htons(pdata->alloc);
break;
case DISCON: /* Informed Disconnect */
ipxh->spx.cctl = CCTL_ACK;
ipxh->spx.dtype = SPX_DTYPE_ECONN;
break;
case DISACK: /* Informed Disconnect ACK */
ipxh->spx.cctl = 0;
ipxh->spx.dtype = SPX_DTYPE_ECACK;
ipxh->spx.sequence = 0;
ipxh->spx.ackseq = htons(pdata->rmt_seq++);
break;
default:
rc = -EOPNOTSUPP;
goto out;
}
/* Send data */
rc = spx_route_skb(pdata, skb, type);
out: return rc;
}
/* Check the state of the connection and send a WD request if needed. */
static void spx_watchdog(unsigned long data)
{
struct sock *sk = (struct sock*)data;
struct spx_opt *pdata = spx_sk(sk);
del_timer(&pdata->watchdog);
if (pdata->state == SPX_CLOSED)
goto out;
if (pdata->retries > pdata->max_retries) {
spx_close_socket(sk); /* Unilateral Abort */
goto out;
}
/* Send WD request */
spx_transmit(sk, NULL, WDREQ, 0);
pdata->retries++;
out:;
}
static void spx_retransmit(unsigned long data)
{
struct sock *sk = (struct sock*)data;
struct spx_opt *pdata = spx_sk(sk);
struct sk_buff *skb;
unsigned long flags;
del_timer(&pdata->retransmit);
if (pdata->state == SPX_CLOSED)
goto out;
if (pdata->retransmits > RETRY_COUNT) {
spx_close_socket(sk); /* Unilateral Abort */
goto out;
}
/* Need to leave skb on the queue, aye the fear */
save_flags(flags);
cli();
skb = skb_peek(&pdata->retransmit_queue);
if (skb_cloned(skb))
skb = skb_copy(skb, GFP_ATOMIC);
else
skb = skb_clone(skb, GFP_ATOMIC);
restore_flags(flags);
pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
add_timer(&pdata->retransmit);
spx_route_skb(pdata, skb, RETRAN);
pdata->retransmits++;
out:;
}
/* Check packet for retransmission, ConReqAck aware */
static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type)
{
struct ipxspxhdr *ipxh;
int rc = -ENOENT;
struct sk_buff *skb = skb_dequeue(&pdata->retransmit_queue);
if (!skb)
goto out;
rc = 0;
/* Check Data/ACK seq */
switch (type) {
case ACK: /* Check Sequence, Should == 1 */
ipxh = (struct ipxspxhdr *)skb->nh.raw;
if (!(ntohs(ipxh->spx.sequence) - htons(ackseq)))
break;
case CONACK:
del_timer(&pdata->retransmit);
pdata->retransmits = 0;
kfree_skb(skb);
if (skb_queue_empty(&pdata->retransmit_queue)) {
skb = skb_dequeue(&pdata->transmit_queue);
if (skb)
spx_route_skb(pdata, skb, TQUEUE);
}
goto out;
}
skb_queue_head(&pdata->retransmit_queue, skb);
rc = -1;
out: return rc;
}
/* SPX packet receive engine */
void spx_rcv(struct sock *sk, int bytes)
{
struct ipxspxhdr *ipxh;
struct spx_opt *pdata = spx_sk(sk);
struct sk_buff *skb = skb_dequeue(&sk->receive_queue);
if (!skb)
goto out;
ipxh = (struct ipxspxhdr *)skb->nh.raw;
/* Can't receive on a closed connection */
if ((pdata->state == SPX_CLOSED && ipxh->spx.sequence) ||
ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN ||
ipxh->ipx.ipx_type != IPX_TYPE_SPX ||
ntohs(ipxh->spx.ackseq) > pdata->sequence)
goto toss_skb;
/* Reset WD timer on any received packet */
del_timer(&pdata->watchdog);
pdata->retries = 0;
pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
add_timer(&pdata->watchdog);
switch (ipxh->spx.cctl) {
case (CCTL_SYS | CCTL_ACK):
if (!ipxh->spx.sequence && /* ConReq */
!ipxh->spx.ackseq &&
ipxh->spx.dconn == 0xFFFF) {
pdata->state = SPX_CONNECTED;
pdata->dest_addr = ipxh->ipx.ipx_source;
pdata->source_addr = ipxh->ipx.ipx_dest;
pdata->dest_connid = ipxh->spx.sconn;
pdata->alloc = 3 + ntohs(ipxh->spx.sequence);
skb_queue_tail(&sk->receive_queue, skb);
wake_up_interruptible(sk->sleep);
} else /* WD Request */
spx_transmit(sk, skb, WDACK, 0);
goto out;
case CCTL_SYS: /* ACK */
if (!ipxh->spx.dtype && /* ConReq ACK */
ipxh->spx.sconn != 0xFFFF &&
ipxh->spx.dconn != 0xFFFF &&
!ipxh->spx.sequence &&
!ipxh->spx.ackseq &&
pdata->state != SPX_CONNECTED) {
pdata->state = SPX_CONNECTED;
pdata->dest_connid = ipxh->spx.sconn;
if (spx_retransmit_chk(pdata, 0, CONACK) < 0)
goto toss_skb;
skb_queue_tail(&sk->receive_queue, skb);
wake_up_interruptible(sk->sleep);
goto out;
}
spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);
goto toss_skb;
case CCTL_ACK:
/* Informed Disconnect */
if (ipxh->spx.dtype == SPX_DTYPE_ECONN) {
spx_transmit(sk, skb, DISACK, 0);
spx_close_socket(sk);
goto out;
}
/* Fall through */
default:
if (ntohs(ipxh->spx.sequence) == pdata->rmt_seq) {
pdata->rmt_seq = ntohs(ipxh->spx.sequence);
pdata->rmt_ack = ntohs(ipxh->spx.ackseq);
pdata->alloc = pdata->rmt_seq + 3;
if (pdata->rmt_ack > 0 || !pdata->rmt_ack)
spx_retransmit_chk(pdata,
pdata->rmt_ack, ACK);
skb_queue_tail(&pdata->rcv_queue, skb);
wake_up_interruptible(sk->sleep);
if (ipxh->spx.cctl&CCTL_ACK)
spx_transmit(sk, NULL, ACK, 0);
goto out;
}
if (ipxh->spx.dtype == SPX_DTYPE_ECACK) {
if (pdata->state != SPX_CLOSED)
spx_close_socket(sk);
goto toss_skb;
}
}
toss_skb: /* Catch All */
kfree_skb(skb);
out:;
}
/* Get message/packet data from user-land */
static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
int flags = msg->msg_flags;
struct sk_buff *skb;
int offset, size, rc = -EMSGSIZE;
if (len > 534)
goto out;
rc = -ENOTCONN; /* Socket not bound */
if (sk->zapped)
goto out;
rc = -EINVAL;
if (flags & ~MSG_DONTWAIT)
goto out;
offset = ipx_if_offset(spx_sk(sk)->dest_addr.net);
size = offset + sizeof(struct ipxspxhdr) + len;
cli();
skb = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &rc);
sti();
if (!skb)
goto out;
skb->sk = sk;
skb_reserve(skb, offset);
skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
rc = -EFAULT;
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
kfree_skb(skb);
goto out;
}
rc = len;
if (!spx_transmit(sk, skb, DATA, len))
rc = -EAGAIN;
out: return rc;
}
/* Send message/packet data to user-land */
static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int flags, struct scm_cookie *scm)
{
struct sk_buff *skb;
struct ipxspxhdr *ispxh;
struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk);
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
int copied, rc = -ENOTCONN;
if (sk->zapped) /* Socket not bound */
goto out;
lock_sock(sk);
restart:
while (skb_queue_empty(&pdata->rcv_queue)) { /* No data */
/* Socket errors? */
rc = sock_error(sk);
if (rc)
goto out_release_sock;
/* Socket shut down? */
rc = -ESHUTDOWN;
if (sk->shutdown & RCV_SHUTDOWN)
goto out_release_sock;
/* handle signals */
rc = -ERESTARTSYS;
if (signal_pending(current))
goto out_release_sock;
/* User doesn't want to wait */
rc = -EAGAIN;
if (flags & MSG_DONTWAIT)
goto out_release_sock;
release_sock(sk);
save_flags(flags);
cli();
if (!skb_peek(&pdata->rcv_queue))
interruptible_sleep_on(sk->sleep);
restore_flags(flags);
lock_sock(sk);
}
skb = skb_dequeue(&pdata->rcv_queue);
if (!skb)
goto restart;
ispxh = (struct ipxspxhdr *)skb->nh.raw;
copied = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
if (copied > size) {
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
rc = -EFAULT;
if (memcpy_toiovec(msg->msg_iov, skb->nh.raw + SPX_SYS_PKT_LEN, copied))
goto out_kfree_skb;
msg->msg_namelen = sizeof(*sipx);
if (sipx) {
sipx->sipx_family = AF_IPX;
sipx->sipx_port = ispxh->ipx.ipx_source.sock;
memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
sipx->sipx_network = ispxh->ipx.ipx_source.net;
sipx->sipx_type = ispxh->ipx.ipx_type;
}
rc = copied;
out_kfree_skb:
kfree_skb(skb);
out_release_sock:
release_sock(sk);
out: return rc;
}
/*
* Functions which just wrap their IPX cousins
*/
static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
return ipx_ops->bind(sock, uaddr, addr_len);
}
static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
int *usockaddr_len, int peer)
{
return ipx_ops->getname(sock, uaddr, usockaddr_len, peer);
}
static int spx_ioctl (struct socket *sock, unsigned int cmd,
unsigned long arg)
{
return ipx_ops->ioctl(sock, cmd, arg);
}
static int spx_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
return ipx_ops->setsockopt(sock, level, optname, optval, optlen);
}
static int spx_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
return ipx_ops->getsockopt(sock, level, optname, optval, optlen);
}
static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
.family = PF_IPX,
.release = spx_release,
.bind = spx_bind,
.connect = spx_connect,
.socketpair = sock_no_socketpair,
.accept = spx_accept,
.getname = spx_getname,
.poll = spx_datagram_poll,
.ioctl = spx_ioctl,
.listen = spx_listen,
.shutdown = sock_no_shutdown,
.setsockopt = spx_setsockopt,
.getsockopt = spx_getsockopt,
.sendmsg = spx_sendmsg,
.recvmsg = spx_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP(spx, PF_IPX);
static struct net_proto_family spx_family_ops = {
.family = PF_IPX,
.create = spx_create,
};
static char banner[] __initdata =
KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.03\n";
static int __init spx_proto_init(void)
{
connids = (__u16)jiffies; /* initalize random */
/* allocate our sock slab cache */
spx_family_ops.sk_cachep = kmem_cache_create("spx_sock",
spx_family_ops.sk_size,
0, SLAB_HWCACHE_ALIGN,
0, 0);
if (!spx_family_ops.sk_cachep)
printk(KERN_CRIT __FUNCTION__
": Cannot create spx_sock SLAB cache!\n");
if (ipx_register_spx(&ipx_ops, &spx_family_ops))
printk(KERN_ERR "SPX: unable to register with IPX.\n");
/* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
printk(banner);
return 0;
}
static void __exit spx_proto_finito(void)
{
ipx_unregister_spx();
}
module_init(spx_proto_init);
module_exit(spx_proto_finito);
MODULE_LICENSE("GPL");
......@@ -17,21 +17,36 @@
/* From af_ipx.c */
extern int sysctl_ipx_pprop_broadcasting;
ctl_table ipx_table[] = {
{ NET_IPX_PPROP_BROADCASTING, "ipx_pprop_broadcasting",
&sysctl_ipx_pprop_broadcasting, sizeof(int), 0644, NULL,
&proc_dointvec },
{ 0 }
static struct ctl_table ipx_table[] = {
{
.ctl_name = NET_IPX_PPROP_BROADCASTING,
.procname = "ipx_pprop_broadcasting",
.data = &sysctl_ipx_pprop_broadcasting,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{ 0 },
};
static ctl_table ipx_dir_table[] = {
{ NET_IPX, "ipx", NULL, 0, 0555, ipx_table },
{ 0 }
static struct ctl_table ipx_dir_table[] = {
{
.ctl_name = NET_IPX,
.procname = "ipx",
.mode = 0555,
.child = ipx_table,
},
{ 0 },
};
static ctl_table ipx_root_table[] = {
{ CTL_NET, "net", NULL, 0, 0555, ipx_dir_table },
{ 0 }
static struct ctl_table ipx_root_table[] = {
{
.ctl_name = CTL_NET,
.procname = "net",
.mode = 0555,
.child = ipx_dir_table,
},
{ 0 },
};
static struct ctl_table_header *ipx_table_header;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment