*/
#include <linux/config.h>
+#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/string.h>
-#include <linux/tcp.h>
#include <linux/types.h>
#include <linux/termios.h>
#include <net/p8022.h>
#include <net/psnap.h>
#include <net/sock.h>
+#include <net/tcp_states.h>
#include <asm/uaccess.h>
static struct datalink_proto *p8023_datalink;
static struct datalink_proto *pSNAP_datalink;
-static struct proto_ops ipx_dgram_ops;
+static const struct proto_ops ipx_dgram_ops;
LIST_HEAD(ipx_interfaces);
-spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(ipx_interfaces_lock);
struct ipx_interface *ipx_primary_net;
struct ipx_interface *ipx_internal_net;
spin_lock_bh(&intrfc->if_sklist_lock);
sk_for_each(s, node, &intrfc->if_sklist) {
- struct ipx_opt *ipxs = ipx_sk(s);
+ struct ipx_sock *ipxs = ipx_sk(s);
if (ipxs->port == port &&
!memcmp(ipx_node, ipxs->node, IPX_NODE_LEN))
}
#endif
-void __ipxitf_down(struct ipx_interface *intrfc)
+static void __ipxitf_down(struct ipx_interface *intrfc)
{
struct sock *s;
struct hlist_node *node, *t;
spin_lock_bh(&intrfc->if_sklist_lock);
/* error sockets */
sk_for_each_safe(s, node, t, &intrfc->if_sklist) {
- struct ipx_opt *ipxs = ipx_sk(s);
+ struct ipx_sock *ipxs = ipx_sk(s);
s->sk_err = ENOLINK;
s->sk_error_report(s);
ipxs->intrfc = NULL;
ipxs->port = 0;
- s->sk_zapped = 1; /* Indicates it is no longer bound */
+ 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(&ipx_interfaces_lock);
}
+static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
+{
+ if (atomic_dec_and_test(&intrfc->refcnt))
+ __ipxitf_down(intrfc);
+}
+
static int ipxitf_device_event(struct notifier_block *notifier,
unsigned long event, void *ptr)
{
spin_lock_bh(&intrfc->if_sklist_lock);
sk_for_each(s, node, &intrfc->if_sklist) {
- struct ipx_opt *ipxs = ipx_sk(s);
+ struct ipx_sock *ipxs = ipx_sk(s);
if (ipxs->port == ipx->ipx_dest.sock &&
(is_broadcast || !memcmp(ipx->ipx_dest.node,
return rc;
}
-static int ipx_map_frame_type(unsigned char type)
+static __be16 ipx_map_frame_type(unsigned char type)
{
- int rc = 0;
+ __be16 rc = 0;
switch (type) {
case IPX_FRAME_ETHERII: rc = htons(ETH_P_IPX); break;
return rc;
}
+static struct proto ipx_proto = {
+ .name = "IPX",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct ipx_sock),
+};
+
static int ipx_create(struct socket *sock, int protocol)
{
int rc = -ESOCKTNOSUPPORT;
- struct ipx_opt *ipx = NULL;
struct sock *sk;
- switch (sock->type) {
- case SOCK_DGRAM:
- sk = sk_alloc(PF_IPX, GFP_KERNEL, 1, NULL);
- rc = -ENOMEM;
- if (!sk)
- goto out;
- ipx = sk->sk_protinfo = kmalloc(sizeof(*ipx), GFP_KERNEL);
- if (!ipx)
- goto outsk;
- memset(ipx, 0, sizeof(*ipx));
- sock->ops = &ipx_dgram_ops;
- break;
- case SOCK_SEQPACKET:
- /*
- * 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.
- */
- case SOCK_STREAM: /* Allow higher levels to piggyback */
- default:
+ /*
+ * 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.
+ */
+ if (sock->type != SOCK_DGRAM)
+ goto out;
+
+ rc = -ENOMEM;
+ sk = sk_alloc(PF_IPX, GFP_KERNEL, &ipx_proto, 1);
+ if (!sk)
goto out;
- }
#ifdef IPX_REFCNT_DEBUG
atomic_inc(&ipx_sock_nr);
printk(KERN_DEBUG "IPX socket %p created, now we have %d alive\n", sk,
atomic_read(&ipx_sock_nr));
#endif
sock_init_data(sock, sk);
- sk_set_owner(sk, THIS_MODULE);
sk->sk_no_check = 1; /* Checksum off by default */
+ sock->ops = &ipx_dgram_ops;
rc = 0;
out:
return rc;
-outsk:
- sk_free(sk);
- goto out;
}
static int ipx_release(struct socket *sock)
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);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct ipx_interface *intrfc;
struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;
int rc = -EINVAL;
- if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_ipx))
+ if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_ipx))
goto out;
intrfc = ipxitf_find_using_net(addr->sipx_network);
#endif /* CONFIG_IPX_INTERN */
ipxitf_insert_socket(intrfc, sk);
- sk->sk_zapped = 0;
+ sock_reset_flag(sk, SOCK_ZAPPED);
rc = 0;
out_put:
int addr_len, int flags)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct sockaddr_ipx *addr;
int rc = -EINVAL;
struct ipx_route *rt;
struct ipx_address *addr;
struct sockaddr_ipx sipx;
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
int rc;
*uaddr_len = sizeof(struct sockaddr_ipx);
return rc;
}
-int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
/* NULL here for pt means the packet was looped back */
struct ipx_interface *intrfc;
ipx_pktsize = ntohs(ipx->ipx_pktsize);
/* Too small or invalid header? */
- if (ipx_pktsize < sizeof(struct ipxhdr) || ipx_pktsize > skb->len)
+ if (ipx_pktsize < sizeof(struct ipxhdr)
+ || !pskb_may_pull(skb, ipx_pktsize))
goto drop;
if (ipx->ipx_checksum != IPX_NO_CHECKSUM &&
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct sockaddr_ipx *usipx = (struct sockaddr_ipx *)msg->msg_name;
struct sockaddr_ipx local_sipx;
int rc = -EINVAL;
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
struct ipxhdr *ipx = NULL;
struct sk_buff *skb;
}
rc = -ENOTCONN;
- if (sk->sk_zapped)
+ if (sock_flag(sk, SOCK_ZAPPED))
goto out;
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
copied);
if (rc)
goto out_free;
- if (skb->stamp.tv_sec)
- sk->sk_stamp = skb->stamp;
+ if (skb->tstamp.off_sec)
+ skb_get_timestamp(skb, &sk->sk_stamp);
msg->msg_namelen = sizeof(*sipx);
rc = -EINVAL;
break;
default:
- rc = dev_ioctl(cmd, argp);
+ rc = -ENOIOCTLCMD;
break;
}
return rc;
}
+
+#ifdef CONFIG_COMPAT
+static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ /*
+ * These 4 commands use same structure on 32bit and 64bit. Rest of IPX
+ * commands is handled by generic ioctl code. As these commands are
+ * SIOCPROTOPRIVATE..SIOCPROTOPRIVATE+3, they cannot be handled by generic
+ * code.
+ */
+ switch (cmd) {
+ case SIOCAIPXITFCRT:
+ case SIOCAIPXPRISLT:
+ case SIOCIPXCFGDATA:
+ case SIOCIPXNCPCONN:
+ return ipx_ioctl(sock, cmd, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#endif
+
+
/*
* Socket family declarations
*/
.owner = THIS_MODULE,
};
-static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
+static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
.family = PF_IPX,
.owner = THIS_MODULE,
.release = ipx_release,
.getname = ipx_getname,
.poll = datagram_poll,
.ioctl = ipx_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ipx_compat_ioctl,
+#endif
.listen = sock_no_listen,
.shutdown = sock_no_shutdown, /* FIXME: support shutdown */
.setsockopt = ipx_setsockopt,
};
extern struct datalink_proto *make_EII_client(void);
-extern struct datalink_proto *make_8023_client(void);
extern void destroy_EII_client(struct datalink_proto *);
-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 int __init ipx_init(void)
{
+ int rc = proto_register(&ipx_proto, 1);
+
+ if (rc != 0)
+ goto out;
+
sock_register(&ipx_family_ops);
pEII_datalink = make_EII_client();
register_netdevice_notifier(&ipx_dev_notifier);
ipx_register_sysctl();
ipx_proc_init();
- return 0;
+out:
+ return rc;
}
static void __exit ipx_proto_finito(void)
destroy_EII_client(pEII_datalink);
pEII_datalink = NULL;
+ proto_unregister(&ipx_proto);
sock_unregister(ipx_family_ops.family);
}