aboutsummaryrefslogtreecommitdiff
path: root/net/ipx/af_ipx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipx/af_ipx.c')
-rw-r--r--net/ipx/af_ipx.c166
1 files changed, 93 insertions, 73 deletions
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index b6e70f92e7f..91729b807c7 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -40,6 +40,7 @@
#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>
@@ -51,18 +52,12 @@
#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>
-#ifdef CONFIG_SYSCTL
-extern void ipx_register_sysctl(void);
-extern void ipx_unregister_sysctl(void);
-#else
-#define ipx_register_sysctl()
-#define ipx_unregister_sysctl()
-#endif
-
/* Configuration Variables */
static unsigned char ipxcfg_max_hops = 16;
static char ipxcfg_auto_select_primary;
@@ -83,15 +78,6 @@ DEFINE_SPINLOCK(ipx_interfaces_lock);
struct ipx_interface *ipx_primary_net;
struct ipx_interface *ipx_internal_net;
-extern int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
- unsigned char *node);
-extern void ipxrtr_del_routes(struct ipx_interface *intrfc);
-extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
- struct iovec *iov, size_t len, int noblock);
-extern int ipxrtr_route_skb(struct sk_buff *skb);
-extern struct ipx_route *ipxrtr_lookup(__be32 net);
-extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
-
struct ipx_interface *ipx_interfaces_head(void)
{
struct ipx_interface *rc = NULL;
@@ -147,7 +133,6 @@ static void ipx_destroy_socket(struct sock *sk)
ipx_remove_socket(sk);
skb_queue_purge(&sk->sk_receive_queue);
sk_refcnt_debug_dec(sk);
- sock_put(sk);
}
/*
@@ -228,9 +213,8 @@ static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc,
__be16 port)
{
struct sock *s;
- struct hlist_node *node;
- sk_for_each(s, node, &intrfc->if_sklist)
+ sk_for_each(s, &intrfc->if_sklist)
if (ipx_sk(s)->port == port)
goto found;
s = NULL;
@@ -259,12 +243,11 @@ static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc,
__be16 port)
{
struct sock *s;
- struct hlist_node *node;
ipxitf_hold(intrfc);
spin_lock_bh(&intrfc->if_sklist_lock);
- sk_for_each(s, node, &intrfc->if_sklist) {
+ sk_for_each(s, &intrfc->if_sklist) {
struct ipx_sock *ipxs = ipx_sk(s);
if (ipxs->port == port &&
@@ -282,14 +265,14 @@ found:
static void __ipxitf_down(struct ipx_interface *intrfc)
{
struct sock *s;
- struct hlist_node *node, *t;
+ 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, node, t, &intrfc->if_sklist) {
+ sk_for_each_safe(s, t, &intrfc->if_sklist) {
struct ipx_sock *ipxs = ipx_sk(s);
s->sk_err = ENOLINK;
@@ -332,7 +315,7 @@ static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
static int ipxitf_device_event(struct notifier_block *notifier,
unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct ipx_interface *i, *tmp;
if (!net_eq(dev_net(dev), &init_net))
@@ -385,12 +368,11 @@ static int ipxitf_demux_socket(struct ipx_interface *intrfc,
int is_broadcast = !memcmp(ipx->ipx_dest.node, ipx_broadcast_node,
IPX_NODE_LEN);
struct sock *s;
- struct hlist_node *node;
int rc;
spin_lock_bh(&intrfc->if_sklist_lock);
- sk_for_each(s, node, &intrfc->if_sklist) {
+ sk_for_each(s, &intrfc->if_sklist) {
struct ipx_sock *ipxs = ipx_sk(s);
if (ipxs->port == ipx->ipx_dest.sock &&
@@ -446,12 +428,11 @@ static struct sock *ncp_connection_hack(struct ipx_interface *intrfc,
connection = (((int) *(ncphdr + 9)) << 8) | (int) *(ncphdr + 8);
if (connection) {
- struct hlist_node *node;
/* 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, node, &intrfc->if_sklist)
+ sk_for_each(sk, &intrfc->if_sklist)
if (ipx_sk(sk)->ipx_ncp_conn == connection) {
sock_hold(sk);
goto found;
@@ -983,10 +964,6 @@ static int ipxitf_create(struct ipx_interface_definition *idef)
goto out;
switch (idef->ipx_dlink_type) {
- case IPX_FRAME_TR_8022:
- printk(KERN_WARNING "IPX frame type 802.2TR is "
- "obsolete Use 802.2 instead.\n");
- /* fall through */
case IPX_FRAME_8022:
dlink_type = htons(ETH_P_802_2);
datalink = p8022_datalink;
@@ -996,10 +973,7 @@ static int ipxitf_create(struct ipx_interface_definition *idef)
dlink_type = htons(ETH_P_IPX);
datalink = pEII_datalink;
break;
- } else
- printk(KERN_WARNING "IPX frame type EtherII over "
- "token-ring is obsolete. Use SNAP "
- "instead.\n");
+ }
/* fall through */
case IPX_FRAME_SNAP:
dlink_type = htons(ETH_P_SNAP);
@@ -1275,7 +1249,6 @@ const char *ipx_frame_name(__be16 frame)
case ETH_P_802_2: rc = "802.2"; break;
case ETH_P_SNAP: rc = "SNAP"; break;
case ETH_P_802_3: rc = "802.3"; break;
- case ETH_P_TR_802_2: rc = "802.2TR"; break;
}
return rc;
@@ -1291,12 +1264,13 @@ const char *ipx_device_name(struct ipx_interface *intrfc)
* socket object. */
static int ipx_setsockopt(struct socket *sock, int level, int optname,
- char __user *optval, int optlen)
+ char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int opt;
int rc = -EINVAL;
+ lock_sock(sk);
if (optlen != sizeof(int))
goto out;
@@ -1311,6 +1285,7 @@ static int ipx_setsockopt(struct socket *sock, int level, int optname,
ipx_sk(sk)->type = opt;
rc = 0;
out:
+ release_sock(sk);
return rc;
}
@@ -1322,6 +1297,7 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname,
int len;
int rc = -ENOPROTOOPT;
+ lock_sock(sk);
if (!(level == SOL_IPX && optname == IPX_TYPE))
goto out;
@@ -1342,6 +1318,7 @@ static int ipx_getsockopt(struct socket *sock, int level, int optname,
rc = 0;
out:
+ release_sock(sk);
return rc;
}
@@ -1351,12 +1328,13 @@ static struct proto ipx_proto = {
.obj_size = sizeof(struct ipx_sock),
};
-static int ipx_create(struct net *net, struct socket *sock, int protocol)
+static int ipx_create(struct net *net, struct socket *sock, int protocol,
+ int kern)
{
int rc = -ESOCKTNOSUPPORT;
struct sock *sk;
- if (net != &init_net)
+ if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
/*
@@ -1375,7 +1353,7 @@ static int ipx_create(struct net *net, struct socket *sock, int protocol)
sk_refcnt_debug_inc(sk);
sock_init_data(sock, sk);
- sk->sk_no_check = 1; /* Checksum off by default */
+ sk->sk_no_check_tx = 1; /* Checksum off by default */
sock->ops = &ipx_dgram_ops;
rc = 0;
out:
@@ -1389,6 +1367,8 @@ static int ipx_release(struct socket *sock)
if (!sk)
goto out;
+ lock_sock(sk);
+ sk->sk_shutdown = SHUTDOWN_MASK;
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_state_change(sk);
@@ -1396,6 +1376,8 @@ static int ipx_release(struct socket *sock)
sock->sk = NULL;
sk_refcnt_debug_release(sk);
ipx_destroy_socket(sk);
+ release_sock(sk);
+ sock_put(sk);
out:
return 0;
}
@@ -1423,7 +1405,8 @@ static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc)
return htons(socketNum);
}
-static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+static int __ipx_bind(struct socket *sock,
+ struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
struct ipx_sock *ipxs = ipx_sk(sk);
@@ -1518,6 +1501,18 @@ out:
return rc;
}
+static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ struct sock *sk = sock->sk;
+ int rc;
+
+ lock_sock(sk);
+ rc = __ipx_bind(sock, uaddr, addr_len);
+ release_sock(sk);
+
+ return rc;
+}
+
static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
@@ -1530,6 +1525,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
+ lock_sock(sk);
if (addr_len != sizeof(*addr))
goto out;
addr = (struct sockaddr_ipx *)uaddr;
@@ -1549,7 +1545,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
IPX_NODE_LEN);
#endif /* CONFIG_IPX_INTERN */
- rc = ipx_bind(sock, (struct sockaddr *)&uaddr,
+ rc = __ipx_bind(sock, (struct sockaddr *)&uaddr,
sizeof(struct sockaddr_ipx));
if (rc)
goto out;
@@ -1576,6 +1572,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
ipxrtr_put(rt);
rc = 0;
out:
+ release_sock(sk);
return rc;
}
@@ -1591,6 +1588,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
*uaddr_len = sizeof(struct sockaddr_ipx);
+ lock_sock(sk);
if (peer) {
rc = -ENOTCONN;
if (sk->sk_state != TCP_ESTABLISHED)
@@ -1625,6 +1623,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
rc = 0;
out:
+ release_sock(sk);
return rc;
}
@@ -1694,11 +1693,12 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock,
{
struct sock *sk = sock->sk;
struct ipx_sock *ipxs = ipx_sk(sk);
- struct sockaddr_ipx *usipx = (struct sockaddr_ipx *)msg->msg_name;
+ DECLARE_SOCKADDR(struct sockaddr_ipx *, usipx, msg->msg_name);
struct sockaddr_ipx local_sipx;
int rc = -EINVAL;
int flags = msg->msg_flags;
+ lock_sock(sk);
/* Socket gets bound below anyway */
/* if (sk->sk_zapped)
return -EIO; */ /* Socket not bound */
@@ -1722,7 +1722,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock,
memcpy(uaddr.sipx_node, ipxs->intrfc->if_node,
IPX_NODE_LEN);
#endif
- rc = ipx_bind(sock, (struct sockaddr *)&uaddr,
+ rc = __ipx_bind(sock, (struct sockaddr *)&uaddr,
sizeof(struct sockaddr_ipx));
if (rc)
goto out;
@@ -1750,6 +1750,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock,
if (rc >= 0)
rc = len;
out:
+ release_sock(sk);
return rc;
}
@@ -1759,11 +1760,12 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
{
struct sock *sk = sock->sk;
struct ipx_sock *ipxs = ipx_sk(sk);
- struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
+ DECLARE_SOCKADDR(struct sockaddr_ipx *, sipx, msg->msg_name);
struct ipxhdr *ipx = NULL;
struct sk_buff *skb;
int copied, rc;
+ lock_sock(sk);
/* put the autobinding in */
if (!ipxs->port) {
struct sockaddr_ipx uaddr;
@@ -1778,7 +1780,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, IPX_NODE_LEN);
#endif /* CONFIG_IPX_INTERN */
- rc = ipx_bind(sock, (struct sockaddr *)&uaddr,
+ rc = __ipx_bind(sock, (struct sockaddr *)&uaddr,
sizeof(struct sockaddr_ipx));
if (rc)
goto out;
@@ -1790,8 +1792,11 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &rc);
- if (!skb)
+ if (!skb) {
+ if (rc == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN))
+ rc = 0;
goto out;
+ }
ipx = ipx_hdr(skb);
copied = ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr);
@@ -1807,8 +1812,6 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
if (skb->tstamp.tv64)
sk->sk_stamp = skb->tstamp;
- msg->msg_namelen = sizeof(*sipx);
-
if (sipx) {
sipx->sipx_family = AF_IPX;
sipx->sipx_port = ipx->ipx_source.sock;
@@ -1816,12 +1819,14 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net;
sipx->sipx_type = ipx->ipx_type;
sipx->sipx_zero = 0;
+ msg->msg_namelen = sizeof(*sipx);
}
rc = copied;
out_free:
skb_free_datagram(sk, skb);
out:
+ release_sock(sk);
return rc;
}
@@ -1833,9 +1838,10 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct sock *sk = sock->sk;
void __user *argp = (void __user *)arg;
+ lock_sock(sk);
switch (cmd) {
case TIOCOUTQ:
- amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+ amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
if (amount < 0)
amount = 0;
rc = put_user(amount, (int __user *)argp);
@@ -1879,9 +1885,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
(const unsigned short __user *)argp);
break;
case SIOCGSTAMP:
- rc = -EINVAL;
- if (sk)
- rc = sock_get_timestamp(sk, argp);
+ rc = sock_get_timestamp(sk, argp);
break;
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
@@ -1895,6 +1899,7 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
rc = -ENOIOCTLCMD;
break;
}
+ release_sock(sk);
return rc;
}
@@ -1921,18 +1926,38 @@ static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long
}
#endif
+static int ipx_shutdown(struct socket *sock, int mode)
+{
+ struct sock *sk = sock->sk;
+
+ if (mode < SHUT_RD || mode > SHUT_RDWR)
+ return -EINVAL;
+ /* This maps:
+ * SHUT_RD (0) -> RCV_SHUTDOWN (1)
+ * SHUT_WR (1) -> SEND_SHUTDOWN (2)
+ * SHUT_RDWR (2) -> SHUTDOWN_MASK (3)
+ */
+ ++mode;
+
+ lock_sock(sk);
+ sk->sk_shutdown |= mode;
+ release_sock(sk);
+ sk->sk_state_change(sk);
+
+ return 0;
+}
/*
* Socket family declarations
*/
-static struct net_proto_family ipx_family_ops = {
+static const struct net_proto_family ipx_family_ops = {
.family = PF_IPX,
.create = ipx_create,
.owner = THIS_MODULE,
};
-static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
+static const struct proto_ops ipx_dgram_ops = {
.family = PF_IPX,
.owner = THIS_MODULE,
.release = ipx_release,
@@ -1947,7 +1972,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
.compat_ioctl = ipx_compat_ioctl,
#endif
.listen = sock_no_listen,
- .shutdown = sock_no_shutdown, /* FIXME: support shutdown */
+ .shutdown = ipx_shutdown,
.setsockopt = ipx_setsockopt,
.getsockopt = ipx_getsockopt,
.sendmsg = ipx_sendmsg,
@@ -1956,15 +1981,13 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
.sendpage = sock_no_sendpage,
};
-SOCKOPS_WRAP(ipx_dgram, PF_IPX);
-
-static struct packet_type ipx_8023_packet_type = {
- .type = __constant_htons(ETH_P_802_3),
+static struct packet_type ipx_8023_packet_type __read_mostly = {
+ .type = cpu_to_be16(ETH_P_802_3),
.func = ipx_rcv,
};
-static struct packet_type ipx_dix_packet_type = {
- .type = __constant_htons(ETH_P_IPX),
+static struct packet_type ipx_dix_packet_type __read_mostly = {
+ .type = cpu_to_be16(ETH_P_IPX),
.func = ipx_rcv,
};
@@ -1972,18 +1995,15 @@ static struct notifier_block ipx_dev_notifier = {
.notifier_call = ipxitf_device_event,
};
-extern struct datalink_proto *make_EII_client(void);
-extern void destroy_EII_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_EII_err_msg[] __initdata =
+static const unsigned char ipx_8022_type = 0xE0;
+static const unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
+static const char ipx_EII_err_msg[] __initconst =
KERN_CRIT "IPX: Unable to register with Ethernet II\n";
-static char ipx_8023_err_msg[] __initdata =
+static const char ipx_8023_err_msg[] __initconst =
KERN_CRIT "IPX: Unable to register with 802.3\n";
-static char ipx_llc_err_msg[] __initdata =
+static const char ipx_llc_err_msg[] __initconst =
KERN_CRIT "IPX: Unable to register with 802.2\n";
-static char ipx_snap_err_msg[] __initdata =
+static const char ipx_snap_err_msg[] __initconst =
KERN_CRIT "IPX: Unable to register with SNAP\n";
static int __init ipx_init(void)