From 17926a79320afa9b95df6b977b40cca6d8713cea Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 26 Apr 2007 15:48:28 -0700 Subject: [AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both Provide AF_RXRPC sockets that can be used to talk to AFS servers, or serve answers to AFS clients. KerberosIV security is fully supported. The patches and some example test programs can be found in: http://people.redhat.com/~dhowells/rxrpc/ This will eventually replace the old implementation of kernel-only RxRPC currently resident in net/rxrpc/. Signed-off-by: David Howells Signed-off-by: David S. Miller --- include/rxrpc/packet.h | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 2 deletions(-) (limited to 'include/rxrpc/packet.h') diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h index 1447f0aaa0eb..452a9bb02d48 100644 --- a/include/rxrpc/packet.h +++ b/include/rxrpc/packet.h @@ -33,7 +33,8 @@ struct rxrpc_header #define RXRPC_MAXCALLS 4 /* max active calls per conn */ #define RXRPC_CHANNELMASK (RXRPC_MAXCALLS-1) /* mask for channel ID */ #define RXRPC_CIDMASK (~RXRPC_CHANNELMASK) /* mask for connection ID */ -#define RXRPC_CIDSHIFT 2 /* shift for connection ID */ +#define RXRPC_CIDSHIFT ilog2(RXRPC_MAXCALLS) /* shift for connection ID */ +#define RXRPC_CID_INC (1 << RXRPC_CIDSHIFT) /* connection ID increment */ __be32 callNumber; /* call ID (0 for connection-level packets) */ #define RXRPC_PROCESS_MAXCALLS (1<<2) /* maximum number of active calls per conn (power of 2) */ @@ -62,7 +63,10 @@ struct rxrpc_header uint8_t userStatus; /* app-layer defined status */ uint8_t securityIndex; /* security protocol ID */ - __be16 _rsvd; /* reserved (used by kerberos security as cksum) */ + union { + __be16 _rsvd; /* reserved */ + __be16 cksum; /* kerberos security checksum */ + }; __be16 serviceId; /* service ID */ } __attribute__((packed)); @@ -124,4 +128,81 @@ struct rxrpc_ackpacket } __attribute__((packed)); +/* + * ACK packets can have a further piece of information tagged on the end + */ +struct rxrpc_ackinfo { + __be32 rxMTU; /* maximum Rx MTU size (bytes) [AFS 3.3] */ + __be32 maxMTU; /* maximum interface MTU size (bytes) [AFS 3.3] */ + __be32 rwind; /* Rx window size (packets) [AFS 3.4] */ + __be32 jumbo_max; /* max packets to stick into a jumbo packet [AFS 3.5] */ +}; + +/*****************************************************************************/ +/* + * Kerberos security type-2 challenge packet + */ +struct rxkad_challenge { + __be32 version; /* version of this challenge type */ + __be32 nonce; /* encrypted random number */ + __be32 min_level; /* minimum security level */ + __be32 __padding; /* padding to 8-byte boundary */ +} __attribute__((packed)); + +/*****************************************************************************/ +/* + * Kerberos security type-2 response packet + */ +struct rxkad_response { + __be32 version; /* version of this reponse type */ + __be32 __pad; + + /* encrypted bit of the response */ + struct { + __be32 epoch; /* current epoch */ + __be32 cid; /* parent connection ID */ + __be32 checksum; /* checksum */ + __be32 securityIndex; /* security type */ + __be32 call_id[4]; /* encrypted call IDs */ + __be32 inc_nonce; /* challenge nonce + 1 */ + __be32 level; /* desired level */ + } encrypted; + + __be32 kvno; /* Kerberos key version number */ + __be32 ticket_len; /* Kerberos ticket length */ +} __attribute__((packed)); + +/*****************************************************************************/ +/* + * RxRPC-level abort codes + */ +#define RX_CALL_DEAD -1 /* call/conn has been inactive and is shut down */ +#define RX_INVALID_OPERATION -2 /* invalid operation requested / attempted */ +#define RX_CALL_TIMEOUT -3 /* call timeout exceeded */ +#define RX_EOF -4 /* unexpected end of data on read op */ +#define RX_PROTOCOL_ERROR -5 /* low-level protocol error */ +#define RX_USER_ABORT -6 /* generic user abort */ +#define RX_ADDRINUSE -7 /* UDP port in use */ +#define RX_DEBUGI_BADTYPE -8 /* bad debugging packet type */ + +/* + * Rx kerberos security abort codes + * - unfortunately we have no generalised security abort codes to say things + * like "unsupported security", so we have to use these instead and hope the + * other side understands + */ +#define RXKADINCONSISTENCY 19270400 /* security module structure inconsistent */ +#define RXKADPACKETSHORT 19270401 /* packet too short for security challenge */ +#define RXKADLEVELFAIL 19270402 /* security level negotiation failed */ +#define RXKADTICKETLEN 19270403 /* ticket length too short or too long */ +#define RXKADOUTOFSEQUENCE 19270404 /* packet had bad sequence number */ +#define RXKADNOAUTH 19270405 /* caller not authorised */ +#define RXKADBADKEY 19270406 /* illegal key: bad parity or weak */ +#define RXKADBADTICKET 19270407 /* security object was passed a bad ticket */ +#define RXKADUNKNOWNKEY 19270408 /* ticket contained unknown key version number */ +#define RXKADEXPIRED 19270409 /* authentication expired */ +#define RXKADSEALEDINCON 19270410 /* sealed data inconsistent */ +#define RXKADDATALEN 19270411 /* user data too long */ +#define RXKADILLEGALLEVEL 19270412 /* caller not authorised to use encrypted conns */ + #endif /* _LINUX_RXRPC_PACKET_H */ -- cgit v1.2.3-59-g8ed1b From 651350d10f93bed7003c9a66e24cf25e0f8eed3d Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 26 Apr 2007 15:50:17 -0700 Subject: [AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use Add an interface to the AF_RXRPC module so that the AFS filesystem module can more easily make use of the services available. AFS still opens a socket but then uses the action functions in lieu of sendmsg() and registers an intercept functions to grab messages before they're queued on the socket Rx queue. This permits AFS (or whatever) to: (1) Avoid the overhead of using the recvmsg() call. (2) Use different keys directly on individual client calls on one socket rather than having to open a whole slew of sockets, one for each key it might want to use. (3) Avoid calling request_key() at the point of issue of a call or opening of a socket. This is done instead by AFS at the point of open(), unlink() or other VFS operation and the key handed through. (4) Request the use of something other than GFP_KERNEL to allocate memory. Furthermore: (*) The socket buffer markings used by RxRPC are made available for AFS so that it can interpret the cooked RxRPC messages itself. (*) rxgen (un)marshalling abort codes are made available. The following documentation for the kernel interface is added to Documentation/networking/rxrpc.txt: ========================= AF_RXRPC KERNEL INTERFACE ========================= The AF_RXRPC module also provides an interface for use by in-kernel utilities such as the AFS filesystem. This permits such a utility to: (1) Use different keys directly on individual client calls on one socket rather than having to open a whole slew of sockets, one for each key it might want to use. (2) Avoid having RxRPC call request_key() at the point of issue of a call or opening of a socket. Instead the utility is responsible for requesting a key at the appropriate point. AFS, for instance, would do this during VFS operations such as open() or unlink(). The key is then handed through when the call is initiated. (3) Request the use of something other than GFP_KERNEL to allocate memory. (4) Avoid the overhead of using the recvmsg() call. RxRPC messages can be intercepted before they get put into the socket Rx queue and the socket buffers manipulated directly. To use the RxRPC facility, a kernel utility must still open an AF_RXRPC socket, bind an addess as appropriate and listen if it's to be a server socket, but then it passes this to the kernel interface functions. The kernel interface functions are as follows: (*) Begin a new client call. struct rxrpc_call * rxrpc_kernel_begin_call(struct socket *sock, struct sockaddr_rxrpc *srx, struct key *key, unsigned long user_call_ID, gfp_t gfp); This allocates the infrastructure to make a new RxRPC call and assigns call and connection numbers. The call will be made on the UDP port that the socket is bound to. The call will go to the destination address of a connected client socket unless an alternative is supplied (srx is non-NULL). If a key is supplied then this will be used to secure the call instead of the key bound to the socket with the RXRPC_SECURITY_KEY sockopt. Calls secured in this way will still share connections if at all possible. The user_call_ID is equivalent to that supplied to sendmsg() in the control data buffer. It is entirely feasible to use this to point to a kernel data structure. If this function is successful, an opaque reference to the RxRPC call is returned. The caller now holds a reference on this and it must be properly ended. (*) End a client call. void rxrpc_kernel_end_call(struct rxrpc_call *call); This is used to end a previously begun call. The user_call_ID is expunged from AF_RXRPC's knowledge and will not be seen again in association with the specified call. (*) Send data through a call. int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, size_t len); This is used to supply either the request part of a client call or the reply part of a server call. msg.msg_iovlen and msg.msg_iov specify the data buffers to be used. msg_iov may not be NULL and must point exclusively to in-kernel virtual addresses. msg.msg_flags may be given MSG_MORE if there will be subsequent data sends for this call. The msg must not specify a destination address, control data or any flags other than MSG_MORE. len is the total amount of data to transmit. (*) Abort a call. void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code); This is used to abort a call if it's still in an abortable state. The abort code specified will be placed in the ABORT message sent. (*) Intercept received RxRPC messages. typedef void (*rxrpc_interceptor_t)(struct sock *sk, unsigned long user_call_ID, struct sk_buff *skb); void rxrpc_kernel_intercept_rx_messages(struct socket *sock, rxrpc_interceptor_t interceptor); This installs an interceptor function on the specified AF_RXRPC socket. All messages that would otherwise wind up in the socket's Rx queue are then diverted to this function. Note that care must be taken to process the messages in the right order to maintain DATA message sequentiality. The interceptor function itself is provided with the address of the socket and handling the incoming message, the ID assigned by the kernel utility to the call and the socket buffer containing the message. The skb->mark field indicates the type of message: MARK MEANING =============================== ======================================= RXRPC_SKB_MARK_DATA Data message RXRPC_SKB_MARK_FINAL_ACK Final ACK received for an incoming call RXRPC_SKB_MARK_BUSY Client call rejected as server busy RXRPC_SKB_MARK_REMOTE_ABORT Call aborted by peer RXRPC_SKB_MARK_NET_ERROR Network error detected RXRPC_SKB_MARK_LOCAL_ERROR Local error encountered RXRPC_SKB_MARK_NEW_CALL New incoming call awaiting acceptance The remote abort message can be probed with rxrpc_kernel_get_abort_code(). The two error messages can be probed with rxrpc_kernel_get_error_number(). A new call can be accepted with rxrpc_kernel_accept_call(). Data messages can have their contents extracted with the usual bunch of socket buffer manipulation functions. A data message can be determined to be the last one in a sequence with rxrpc_kernel_is_data_last(). When a data message has been used up, rxrpc_kernel_data_delivered() should be called on it.. Non-data messages should be handled to rxrpc_kernel_free_skb() to dispose of. It is possible to get extra refs on all types of message for later freeing, but this may pin the state of a call until the message is finally freed. (*) Accept an incoming call. struct rxrpc_call * rxrpc_kernel_accept_call(struct socket *sock, unsigned long user_call_ID); This is used to accept an incoming call and to assign it a call ID. This function is similar to rxrpc_kernel_begin_call() and calls accepted must be ended in the same way. If this function is successful, an opaque reference to the RxRPC call is returned. The caller now holds a reference on this and it must be properly ended. (*) Reject an incoming call. int rxrpc_kernel_reject_call(struct socket *sock); This is used to reject the first incoming call on the socket's queue with a BUSY message. -ENODATA is returned if there were no incoming calls. Other errors may be returned if the call had been aborted (-ECONNABORTED) or had timed out (-ETIME). (*) Record the delivery of a data message and free it. void rxrpc_kernel_data_delivered(struct sk_buff *skb); This is used to record a data message as having been delivered and to update the ACK state for the call. The socket buffer will be freed. (*) Free a message. void rxrpc_kernel_free_skb(struct sk_buff *skb); This is used to free a non-DATA socket buffer intercepted from an AF_RXRPC socket. (*) Determine if a data message is the last one on a call. bool rxrpc_kernel_is_data_last(struct sk_buff *skb); This is used to determine if a socket buffer holds the last data message to be received for a call (true will be returned if it does, false if not). The data message will be part of the reply on a client call and the request on an incoming call. In the latter case there will be more messages, but in the former case there will not. (*) Get the abort code from an abort message. u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb); This is used to extract the abort code from a remote abort message. (*) Get the error number from a local or network error message. int rxrpc_kernel_get_error_number(struct sk_buff *skb); This is used to extract the error number from a message indicating either a local error occurred or a network error occurred. Signed-off-by: David Howells Signed-off-by: David S. Miller --- Documentation/networking/rxrpc.txt | 196 +++++++++++++++++++++++++++++++++++++ include/net/af_rxrpc.h | 44 ++++++++- include/rxrpc/packet.h | 12 +++ net/rxrpc/af_rxrpc.c | 141 ++++++++++++++++++++++++-- net/rxrpc/ar-accept.c | 119 ++++++++++++++++++++-- net/rxrpc/ar-ack.c | 10 +- net/rxrpc/ar-call.c | 75 ++++++++------ net/rxrpc/ar-connection.c | 28 ++++-- net/rxrpc/ar-connevent.c | 20 +++- net/rxrpc/ar-error.c | 6 +- net/rxrpc/ar-input.c | 60 +++++++----- net/rxrpc/ar-internal.h | 44 ++++----- net/rxrpc/ar-local.c | 2 +- net/rxrpc/ar-output.c | 84 +++++++++++++++- net/rxrpc/ar-peer.c | 2 +- net/rxrpc/ar-recvmsg.c | 75 +++++++++++++- net/rxrpc/ar-skbuff.c | 16 ++- net/rxrpc/ar-transport.c | 8 +- 18 files changed, 813 insertions(+), 129 deletions(-) (limited to 'include/rxrpc/packet.h') diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt index fb809b738a0d..cae231b1c134 100644 --- a/Documentation/networking/rxrpc.txt +++ b/Documentation/networking/rxrpc.txt @@ -25,6 +25,8 @@ Contents of this document: (*) Example server usage. + (*) AF_RXRPC kernel interface. + ======== OVERVIEW @@ -661,3 +663,197 @@ A server would be set up to accept operations in the following manner: Note that all the communications for a particular service take place through the one server socket, using control messages on sendmsg() and recvmsg() to determine the call affected. + + +========================= +AF_RXRPC KERNEL INTERFACE +========================= + +The AF_RXRPC module also provides an interface for use by in-kernel utilities +such as the AFS filesystem. This permits such a utility to: + + (1) Use different keys directly on individual client calls on one socket + rather than having to open a whole slew of sockets, one for each key it + might want to use. + + (2) Avoid having RxRPC call request_key() at the point of issue of a call or + opening of a socket. Instead the utility is responsible for requesting a + key at the appropriate point. AFS, for instance, would do this during VFS + operations such as open() or unlink(). The key is then handed through + when the call is initiated. + + (3) Request the use of something other than GFP_KERNEL to allocate memory. + + (4) Avoid the overhead of using the recvmsg() call. RxRPC messages can be + intercepted before they get put into the socket Rx queue and the socket + buffers manipulated directly. + +To use the RxRPC facility, a kernel utility must still open an AF_RXRPC socket, +bind an addess as appropriate and listen if it's to be a server socket, but +then it passes this to the kernel interface functions. + +The kernel interface functions are as follows: + + (*) Begin a new client call. + + struct rxrpc_call * + rxrpc_kernel_begin_call(struct socket *sock, + struct sockaddr_rxrpc *srx, + struct key *key, + unsigned long user_call_ID, + gfp_t gfp); + + This allocates the infrastructure to make a new RxRPC call and assigns + call and connection numbers. The call will be made on the UDP port that + the socket is bound to. The call will go to the destination address of a + connected client socket unless an alternative is supplied (srx is + non-NULL). + + If a key is supplied then this will be used to secure the call instead of + the key bound to the socket with the RXRPC_SECURITY_KEY sockopt. Calls + secured in this way will still share connections if at all possible. + + The user_call_ID is equivalent to that supplied to sendmsg() in the + control data buffer. It is entirely feasible to use this to point to a + kernel data structure. + + If this function is successful, an opaque reference to the RxRPC call is + returned. The caller now holds a reference on this and it must be + properly ended. + + (*) End a client call. + + void rxrpc_kernel_end_call(struct rxrpc_call *call); + + This is used to end a previously begun call. The user_call_ID is expunged + from AF_RXRPC's knowledge and will not be seen again in association with + the specified call. + + (*) Send data through a call. + + int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, + size_t len); + + This is used to supply either the request part of a client call or the + reply part of a server call. msg.msg_iovlen and msg.msg_iov specify the + data buffers to be used. msg_iov may not be NULL and must point + exclusively to in-kernel virtual addresses. msg.msg_flags may be given + MSG_MORE if there will be subsequent data sends for this call. + + The msg must not specify a destination address, control data or any flags + other than MSG_MORE. len is the total amount of data to transmit. + + (*) Abort a call. + + void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code); + + This is used to abort a call if it's still in an abortable state. The + abort code specified will be placed in the ABORT message sent. + + (*) Intercept received RxRPC messages. + + typedef void (*rxrpc_interceptor_t)(struct sock *sk, + unsigned long user_call_ID, + struct sk_buff *skb); + + void + rxrpc_kernel_intercept_rx_messages(struct socket *sock, + rxrpc_interceptor_t interceptor); + + This installs an interceptor function on the specified AF_RXRPC socket. + All messages that would otherwise wind up in the socket's Rx queue are + then diverted to this function. Note that care must be taken to process + the messages in the right order to maintain DATA message sequentiality. + + The interceptor function itself is provided with the address of the socket + and handling the incoming message, the ID assigned by the kernel utility + to the call and the socket buffer containing the message. + + The skb->mark field indicates the type of message: + + MARK MEANING + =============================== ======================================= + RXRPC_SKB_MARK_DATA Data message + RXRPC_SKB_MARK_FINAL_ACK Final ACK received for an incoming call + RXRPC_SKB_MARK_BUSY Client call rejected as server busy + RXRPC_SKB_MARK_REMOTE_ABORT Call aborted by peer + RXRPC_SKB_MARK_NET_ERROR Network error detected + RXRPC_SKB_MARK_LOCAL_ERROR Local error encountered + RXRPC_SKB_MARK_NEW_CALL New incoming call awaiting acceptance + + The remote abort message can be probed with rxrpc_kernel_get_abort_code(). + The two error messages can be probed with rxrpc_kernel_get_error_number(). + A new call can be accepted with rxrpc_kernel_accept_call(). + + Data messages can have their contents extracted with the usual bunch of + socket buffer manipulation functions. A data message can be determined to + be the last one in a sequence with rxrpc_kernel_is_data_last(). When a + data message has been used up, rxrpc_kernel_data_delivered() should be + called on it.. + + Non-data messages should be handled to rxrpc_kernel_free_skb() to dispose + of. It is possible to get extra refs on all types of message for later + freeing, but this may pin the state of a call until the message is finally + freed. + + (*) Accept an incoming call. + + struct rxrpc_call * + rxrpc_kernel_accept_call(struct socket *sock, + unsigned long user_call_ID); + + This is used to accept an incoming call and to assign it a call ID. This + function is similar to rxrpc_kernel_begin_call() and calls accepted must + be ended in the same way. + + If this function is successful, an opaque reference to the RxRPC call is + returned. The caller now holds a reference on this and it must be + properly ended. + + (*) Reject an incoming call. + + int rxrpc_kernel_reject_call(struct socket *sock); + + This is used to reject the first incoming call on the socket's queue with + a BUSY message. -ENODATA is returned if there were no incoming calls. + Other errors may be returned if the call had been aborted (-ECONNABORTED) + or had timed out (-ETIME). + + (*) Record the delivery of a data message and free it. + + void rxrpc_kernel_data_delivered(struct sk_buff *skb); + + This is used to record a data message as having been delivered and to + update the ACK state for the call. The socket buffer will be freed. + + (*) Free a message. + + void rxrpc_kernel_free_skb(struct sk_buff *skb); + + This is used to free a non-DATA socket buffer intercepted from an AF_RXRPC + socket. + + (*) Determine if a data message is the last one on a call. + + bool rxrpc_kernel_is_data_last(struct sk_buff *skb); + + This is used to determine if a socket buffer holds the last data message + to be received for a call (true will be returned if it does, false + if not). + + The data message will be part of the reply on a client call and the + request on an incoming call. In the latter case there will be more + messages, but in the former case there will not. + + (*) Get the abort code from an abort message. + + u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb); + + This is used to extract the abort code from a remote abort message. + + (*) Get the error number from a local or network error message. + + int rxrpc_kernel_get_error_number(struct sk_buff *skb); + + This is used to extract the error number from a message indicating either + a local error occurred or a network error occurred. diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index b01ca2589d69..00c2eaa07c25 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -1,6 +1,6 @@ -/* RxRPC definitions +/* RxRPC kernel service interface definitions * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or @@ -12,6 +12,46 @@ #ifndef _NET_RXRPC_H #define _NET_RXRPC_H +#ifdef __KERNEL__ + #include +struct rxrpc_call; + +/* + * the mark applied to socket buffers that may be intercepted + */ +enum { + RXRPC_SKB_MARK_DATA, /* data message */ + RXRPC_SKB_MARK_FINAL_ACK, /* final ACK received message */ + RXRPC_SKB_MARK_BUSY, /* server busy message */ + RXRPC_SKB_MARK_REMOTE_ABORT, /* remote abort message */ + RXRPC_SKB_MARK_NET_ERROR, /* network error message */ + RXRPC_SKB_MARK_LOCAL_ERROR, /* local error message */ + RXRPC_SKB_MARK_NEW_CALL, /* local error message */ +}; + +typedef void (*rxrpc_interceptor_t)(struct sock *, unsigned long, + struct sk_buff *); +extern void rxrpc_kernel_intercept_rx_messages(struct socket *, + rxrpc_interceptor_t); +extern struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *, + struct sockaddr_rxrpc *, + struct key *, + unsigned long, + gfp_t); +extern int rxrpc_kernel_send_data(struct rxrpc_call *, struct msghdr *, + size_t); +extern void rxrpc_kernel_abort_call(struct rxrpc_call *, u32); +extern void rxrpc_kernel_end_call(struct rxrpc_call *); +extern bool rxrpc_kernel_is_data_last(struct sk_buff *); +extern u32 rxrpc_kernel_get_abort_code(struct sk_buff *); +extern int rxrpc_kernel_get_error_number(struct sk_buff *); +extern void rxrpc_kernel_data_delivered(struct sk_buff *); +extern void rxrpc_kernel_free_skb(struct sk_buff *); +extern struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *, + unsigned long); +extern int rxrpc_kernel_reject_call(struct socket *); + +#endif /* __KERNEL__ */ #endif /* _NET_RXRPC_H */ diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h index 452a9bb02d48..09b11a1e8d46 100644 --- a/include/rxrpc/packet.h +++ b/include/rxrpc/packet.h @@ -185,6 +185,18 @@ struct rxkad_response { #define RX_ADDRINUSE -7 /* UDP port in use */ #define RX_DEBUGI_BADTYPE -8 /* bad debugging packet type */ +/* + * (un)marshalling abort codes (rxgen) + */ +#define RXGEN_CC_MARSHAL -450 +#define RXGEN_CC_UNMARSHAL -451 +#define RXGEN_SS_MARSHAL -452 +#define RXGEN_SS_UNMARSHAL -453 +#define RXGEN_DECODE -454 +#define RXGEN_OPCODE -455 +#define RXGEN_SS_XDRFREE -456 +#define RXGEN_CC_XDRFREE -457 + /* * Rx kerberos security abort codes * - unfortunately we have no generalised security abort codes to say things diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index bfa8822e2286..2c57df9c131b 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -41,6 +41,8 @@ atomic_t rxrpc_debug_id; /* count of skbs currently in use */ atomic_t rxrpc_n_skbs; +struct workqueue_struct *rxrpc_workqueue; + static void rxrpc_sock_destructor(struct sock *); /* @@ -214,7 +216,8 @@ static int rxrpc_listen(struct socket *sock, int backlog) */ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, struct sockaddr *addr, - int addr_len, int flags) + int addr_len, int flags, + gfp_t gfp) { struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr; struct rxrpc_transport *trans; @@ -232,17 +235,129 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, return ERR_PTR(-EAFNOSUPPORT); /* find a remote transport endpoint from the local one */ - peer = rxrpc_get_peer(srx, GFP_KERNEL); + peer = rxrpc_get_peer(srx, gfp); if (IS_ERR(peer)) return ERR_PTR(PTR_ERR(peer)); /* find a transport */ - trans = rxrpc_get_transport(rx->local, peer, GFP_KERNEL); + trans = rxrpc_get_transport(rx->local, peer, gfp); rxrpc_put_peer(peer); _leave(" = %p", trans); return trans; } +/** + * rxrpc_kernel_begin_call - Allow a kernel service to begin a call + * @sock: The socket on which to make the call + * @srx: The address of the peer to contact (defaults to socket setting) + * @key: The security context to use (defaults to socket setting) + * @user_call_ID: The ID to use + * + * Allow a kernel service to begin a call on the nominated socket. This just + * sets up all the internal tracking structures and allocates connection and + * call IDs as appropriate. The call to be used is returned. + * + * The default socket destination address and security may be overridden by + * supplying @srx and @key. + */ +struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, + struct sockaddr_rxrpc *srx, + struct key *key, + unsigned long user_call_ID, + gfp_t gfp) +{ + struct rxrpc_conn_bundle *bundle; + struct rxrpc_transport *trans; + struct rxrpc_call *call; + struct rxrpc_sock *rx = rxrpc_sk(sock->sk); + __be16 service_id; + + _enter(",,%x,%lx", key_serial(key), user_call_ID); + + lock_sock(&rx->sk); + + if (srx) { + trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx, + sizeof(*srx), 0, gfp); + if (IS_ERR(trans)) { + call = ERR_PTR(PTR_ERR(trans)); + trans = NULL; + goto out; + } + } else { + trans = rx->trans; + if (!trans) { + call = ERR_PTR(-ENOTCONN); + goto out; + } + atomic_inc(&trans->usage); + } + + service_id = rx->service_id; + if (srx) + service_id = htons(srx->srx_service); + + if (!key) + key = rx->key; + if (key && !key->payload.data) + key = NULL; /* a no-security key */ + + bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp); + if (IS_ERR(bundle)) { + call = ERR_PTR(PTR_ERR(bundle)); + goto out; + } + + call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, true, + gfp); + rxrpc_put_bundle(trans, bundle); +out: + rxrpc_put_transport(trans); + release_sock(&rx->sk); + _leave(" = %p", call); + return call; +} + +EXPORT_SYMBOL(rxrpc_kernel_begin_call); + +/** + * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using + * @call: The call to end + * + * Allow a kernel service to end a call it was using. The call must be + * complete before this is called (the call should be aborted if necessary). + */ +void rxrpc_kernel_end_call(struct rxrpc_call *call) +{ + _enter("%d{%d}", call->debug_id, atomic_read(&call->usage)); + rxrpc_remove_user_ID(call->socket, call); + rxrpc_put_call(call); +} + +EXPORT_SYMBOL(rxrpc_kernel_end_call); + +/** + * rxrpc_kernel_intercept_rx_messages - Intercept received RxRPC messages + * @sock: The socket to intercept received messages on + * @interceptor: The function to pass the messages to + * + * Allow a kernel service to intercept messages heading for the Rx queue on an + * RxRPC socket. They get passed to the specified function instead. + * @interceptor should free the socket buffers it is given. @interceptor is + * called with the socket receive queue spinlock held and softirqs disabled - + * this ensures that the messages will be delivered in the right order. + */ +void rxrpc_kernel_intercept_rx_messages(struct socket *sock, + rxrpc_interceptor_t interceptor) +{ + struct rxrpc_sock *rx = rxrpc_sk(sock->sk); + + _enter(""); + rx->interceptor = interceptor; +} + +EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages); + /* * connect an RxRPC socket * - this just targets it at a specific destination; no actual connection @@ -294,7 +409,8 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr, return -EBUSY; /* server sockets can't connect as well */ } - trans = rxrpc_name_to_transport(sock, addr, addr_len, flags); + trans = rxrpc_name_to_transport(sock, addr, addr_len, flags, + GFP_KERNEL); if (IS_ERR(trans)) { release_sock(&rx->sk); _leave(" = %ld", PTR_ERR(trans)); @@ -344,7 +460,7 @@ static int rxrpc_sendmsg(struct kiocb *iocb, struct socket *sock, if (m->msg_name) { ret = -EISCONN; trans = rxrpc_name_to_transport(sock, m->msg_name, - m->msg_namelen, 0); + m->msg_namelen, 0, GFP_KERNEL); if (IS_ERR(trans)) { ret = PTR_ERR(trans); trans = NULL; @@ -576,7 +692,7 @@ static int rxrpc_release_sock(struct sock *sk) /* try to flush out this socket */ rxrpc_release_calls_on_socket(rx); - flush_scheduled_work(); + flush_workqueue(rxrpc_workqueue); rxrpc_purge_queue(&sk->sk_receive_queue); if (rx->conn) { @@ -673,15 +789,21 @@ static int __init af_rxrpc_init(void) rxrpc_epoch = htonl(xtime.tv_sec); + ret = -ENOMEM; rxrpc_call_jar = kmem_cache_create( "rxrpc_call_jar", sizeof(struct rxrpc_call), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!rxrpc_call_jar) { printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n"); - ret = -ENOMEM; goto error_call_jar; } + rxrpc_workqueue = create_workqueue("krxrpcd"); + if (!rxrpc_workqueue) { + printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n"); + goto error_work_queue; + } + ret = proto_register(&rxrpc_proto, 1); if (ret < 0) { printk(KERN_CRIT "RxRPC: Cannot register protocol\n"); @@ -719,6 +841,8 @@ error_key_type: error_sock: proto_unregister(&rxrpc_proto); error_proto: + destroy_workqueue(rxrpc_workqueue); +error_work_queue: kmem_cache_destroy(rxrpc_call_jar); error_call_jar: return ret; @@ -743,9 +867,10 @@ static void __exit af_rxrpc_exit(void) ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0); _debug("flush scheduled work"); - flush_scheduled_work(); + flush_workqueue(rxrpc_workqueue); proc_net_remove("rxrpc_conns"); proc_net_remove("rxrpc_calls"); + destroy_workqueue(rxrpc_workqueue); kmem_cache_destroy(rxrpc_call_jar); _leave(""); } diff --git a/net/rxrpc/ar-accept.c b/net/rxrpc/ar-accept.c index e7af780cd6f9..92a87fde8bfe 100644 --- a/net/rxrpc/ar-accept.c +++ b/net/rxrpc/ar-accept.c @@ -139,7 +139,7 @@ static int rxrpc_accept_incoming_call(struct rxrpc_local *local, call->conn->state = RXRPC_CONN_SERVER_CHALLENGING; atomic_inc(&call->conn->usage); set_bit(RXRPC_CONN_CHALLENGE, &call->conn->events); - schedule_work(&call->conn->processor); + rxrpc_queue_conn(call->conn); } else { _debug("conn ready"); call->state = RXRPC_CALL_SERVER_ACCEPTING; @@ -183,7 +183,7 @@ invalid_service: if (!test_bit(RXRPC_CALL_RELEASE, &call->flags) && !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) { rxrpc_get_call(call); - schedule_work(&call->processor); + rxrpc_queue_call(call); } read_unlock_bh(&call->state_lock); rxrpc_put_call(call); @@ -310,7 +310,8 @@ security_mismatch: * handle acceptance of a call by userspace * - assign the user call ID to the call at the front of the queue */ -int rxrpc_accept_call(struct rxrpc_sock *rx, unsigned long user_call_ID) +struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx, + unsigned long user_call_ID) { struct rxrpc_call *call; struct rb_node *parent, **pp; @@ -374,12 +375,76 @@ int rxrpc_accept_call(struct rxrpc_sock *rx, unsigned long user_call_ID) BUG(); if (test_and_set_bit(RXRPC_CALL_ACCEPTED, &call->events)) BUG(); - schedule_work(&call->processor); + rxrpc_queue_call(call); + rxrpc_get_call(call); write_unlock_bh(&call->state_lock); write_unlock(&rx->call_lock); - _leave(" = 0"); - return 0; + _leave(" = %p{%d}", call, call->debug_id); + return call; + + /* if the call is already dying or dead, then we leave the socket's ref + * on it to be released by rxrpc_dead_call_expired() as induced by + * rxrpc_release_call() */ +out_release: + _debug("release %p", call); + if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) && + !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) + rxrpc_queue_call(call); +out_discard: + write_unlock_bh(&call->state_lock); + _debug("discard %p", call); +out: + write_unlock(&rx->call_lock); + _leave(" = %d", ret); + return ERR_PTR(ret); +} + +/* + * handle rejectance of a call by userspace + * - reject the call at the front of the queue + */ +int rxrpc_reject_call(struct rxrpc_sock *rx) +{ + struct rxrpc_call *call; + int ret; + + _enter(""); + + ASSERT(!irqs_disabled()); + + write_lock(&rx->call_lock); + + ret = -ENODATA; + if (list_empty(&rx->acceptq)) + goto out; + + /* dequeue the first call and check it's still valid */ + call = list_entry(rx->acceptq.next, struct rxrpc_call, accept_link); + list_del_init(&call->accept_link); + sk_acceptq_removed(&rx->sk); + + write_lock_bh(&call->state_lock); + switch (call->state) { + case RXRPC_CALL_SERVER_ACCEPTING: + call->state = RXRPC_CALL_SERVER_BUSY; + if (test_and_set_bit(RXRPC_CALL_REJECT_BUSY, &call->events)) + rxrpc_queue_call(call); + ret = 0; + goto out_release; + case RXRPC_CALL_REMOTELY_ABORTED: + case RXRPC_CALL_LOCALLY_ABORTED: + ret = -ECONNABORTED; + goto out_release; + case RXRPC_CALL_NETWORK_ERROR: + ret = call->conn->error; + goto out_release; + case RXRPC_CALL_DEAD: + ret = -ETIME; + goto out_discard; + default: + BUG(); + } /* if the call is already dying or dead, then we leave the socket's ref * on it to be released by rxrpc_dead_call_expired() as induced by @@ -388,7 +453,7 @@ out_release: _debug("release %p", call); if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) && !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); out_discard: write_unlock_bh(&call->state_lock); _debug("discard %p", call); @@ -397,3 +462,43 @@ out: _leave(" = %d", ret); return ret; } + +/** + * rxrpc_kernel_accept_call - Allow a kernel service to accept an incoming call + * @sock: The socket on which the impending call is waiting + * @user_call_ID: The tag to attach to the call + * + * Allow a kernel service to accept an incoming call, assuming the incoming + * call is still valid. + */ +struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *sock, + unsigned long user_call_ID) +{ + struct rxrpc_call *call; + + _enter(",%lx", user_call_ID); + call = rxrpc_accept_call(rxrpc_sk(sock->sk), user_call_ID); + _leave(" = %p", call); + return call; +} + +EXPORT_SYMBOL(rxrpc_kernel_accept_call); + +/** + * rxrpc_kernel_reject_call - Allow a kernel service to reject an incoming call + * @sock: The socket on which the impending call is waiting + * + * Allow a kernel service to reject an incoming call with a BUSY message, + * assuming the incoming call is still valid. + */ +int rxrpc_kernel_reject_call(struct socket *sock) +{ + int ret; + + _enter(""); + ret = rxrpc_reject_call(rxrpc_sk(sock->sk)); + _leave(" = %d", ret); + return ret; +} + +EXPORT_SYMBOL(rxrpc_kernel_reject_call); diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index 8f7764eca96c..fc07a926df56 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c @@ -113,7 +113,7 @@ cancel_timer: read_lock_bh(&call->state_lock); if (call->state <= RXRPC_CALL_COMPLETE && !test_and_set_bit(RXRPC_CALL_ACK, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); } @@ -1166,7 +1166,7 @@ send_message_2: _debug("sendmsg failed: %d", ret); read_lock_bh(&call->state_lock); if (call->state < RXRPC_CALL_DEAD) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); goto error; } @@ -1210,7 +1210,7 @@ maybe_reschedule: if (call->events || !skb_queue_empty(&call->rx_queue)) { read_lock_bh(&call->state_lock); if (call->state < RXRPC_CALL_DEAD) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); } @@ -1224,7 +1224,7 @@ maybe_reschedule: read_lock_bh(&call->state_lock); if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) && !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); } @@ -1238,7 +1238,7 @@ error: * work pending bit and the work item being processed again */ if (call->events && !work_pending(&call->processor)) { _debug("jumpstart %x", ntohl(call->conn->cid)); - schedule_work(&call->processor); + rxrpc_queue_call(call); } _leave(""); diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c index ac31cceda2f1..4d92d88ff1fc 100644 --- a/net/rxrpc/ar-call.c +++ b/net/rxrpc/ar-call.c @@ -19,7 +19,7 @@ struct kmem_cache *rxrpc_call_jar; LIST_HEAD(rxrpc_calls); DEFINE_RWLOCK(rxrpc_call_lock); static unsigned rxrpc_call_max_lifetime = 60; -static unsigned rxrpc_dead_call_timeout = 10; +static unsigned rxrpc_dead_call_timeout = 2; static void rxrpc_destroy_call(struct work_struct *work); static void rxrpc_call_life_expired(unsigned long _call); @@ -264,7 +264,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx, switch (call->state) { case RXRPC_CALL_LOCALLY_ABORTED: if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); case RXRPC_CALL_REMOTELY_ABORTED: read_unlock(&call->state_lock); goto aborted_call; @@ -398,6 +398,7 @@ found_extant_call: */ void rxrpc_release_call(struct rxrpc_call *call) { + struct rxrpc_connection *conn = call->conn; struct rxrpc_sock *rx = call->socket; _enter("{%d,%d,%d,%d}", @@ -413,8 +414,7 @@ void rxrpc_release_call(struct rxrpc_call *call) /* dissociate from the socket * - the socket's ref on the call is passed to the death timer */ - _debug("RELEASE CALL %p (%d CONN %p)", - call, call->debug_id, call->conn); + _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn); write_lock_bh(&rx->call_lock); if (!list_empty(&call->accept_link)) { @@ -430,24 +430,42 @@ void rxrpc_release_call(struct rxrpc_call *call) } write_unlock_bh(&rx->call_lock); - if (call->conn->out_clientflag) - spin_lock(&call->conn->trans->client_lock); - write_lock_bh(&call->conn->lock); - /* free up the channel for reuse */ - if (call->conn->out_clientflag) { - call->conn->avail_calls++; - if (call->conn->avail_calls == RXRPC_MAXCALLS) - list_move_tail(&call->conn->bundle_link, - &call->conn->bundle->unused_conns); - else if (call->conn->avail_calls == 1) - list_move_tail(&call->conn->bundle_link, - &call->conn->bundle->avail_conns); + spin_lock(&conn->trans->client_lock); + write_lock_bh(&conn->lock); + write_lock(&call->state_lock); + + if (conn->channels[call->channel] == call) + conn->channels[call->channel] = NULL; + + if (conn->out_clientflag && conn->bundle) { + conn->avail_calls++; + switch (conn->avail_calls) { + case 1: + list_move_tail(&conn->bundle_link, + &conn->bundle->avail_conns); + case 2 ... RXRPC_MAXCALLS - 1: + ASSERT(conn->channels[0] == NULL || + conn->channels[1] == NULL || + conn->channels[2] == NULL || + conn->channels[3] == NULL); + break; + case RXRPC_MAXCALLS: + list_move_tail(&conn->bundle_link, + &conn->bundle->unused_conns); + ASSERT(conn->channels[0] == NULL && + conn->channels[1] == NULL && + conn->channels[2] == NULL && + conn->channels[3] == NULL); + break; + default: + printk(KERN_ERR "RxRPC: conn->avail_calls=%d\n", + conn->avail_calls); + BUG(); + } } - write_lock(&call->state_lock); - if (call->conn->channels[call->channel] == call) - call->conn->channels[call->channel] = NULL; + spin_unlock(&conn->trans->client_lock); if (call->state < RXRPC_CALL_COMPLETE && call->state != RXRPC_CALL_CLIENT_FINAL_ACK) { @@ -455,13 +473,12 @@ void rxrpc_release_call(struct rxrpc_call *call) call->state = RXRPC_CALL_LOCALLY_ABORTED; call->abort_code = RX_CALL_DEAD; set_bit(RXRPC_CALL_ABORT, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } write_unlock(&call->state_lock); - write_unlock_bh(&call->conn->lock); - if (call->conn->out_clientflag) - spin_unlock(&call->conn->trans->client_lock); + write_unlock_bh(&conn->lock); + /* clean up the Rx queue */ if (!skb_queue_empty(&call->rx_queue) || !skb_queue_empty(&call->rx_oos_queue)) { struct rxrpc_skb_priv *sp; @@ -538,7 +555,7 @@ static void rxrpc_mark_call_released(struct rxrpc_call *call) if (!test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) sched = true; if (sched) - schedule_work(&call->processor); + rxrpc_queue_call(call); } write_unlock(&call->state_lock); } @@ -588,7 +605,7 @@ void __rxrpc_put_call(struct rxrpc_call *call) if (atomic_dec_and_test(&call->usage)) { _debug("call %d dead", call->debug_id); ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD); - schedule_work(&call->destroyer); + rxrpc_queue_work(&call->destroyer); } _leave(""); } @@ -613,7 +630,7 @@ static void rxrpc_cleanup_call(struct rxrpc_call *call) ASSERTCMP(call->events, ==, 0); if (work_pending(&call->processor)) { _debug("defer destroy"); - schedule_work(&call->destroyer); + rxrpc_queue_work(&call->destroyer); return; } @@ -742,7 +759,7 @@ static void rxrpc_call_life_expired(unsigned long _call) read_lock_bh(&call->state_lock); if (call->state < RXRPC_CALL_COMPLETE) { set_bit(RXRPC_CALL_LIFE_TIMER, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } read_unlock_bh(&call->state_lock); } @@ -763,7 +780,7 @@ static void rxrpc_resend_time_expired(unsigned long _call) clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags); if (call->state < RXRPC_CALL_COMPLETE && !test_and_set_bit(RXRPC_CALL_RESEND_TIMER, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); } @@ -782,6 +799,6 @@ static void rxrpc_ack_time_expired(unsigned long _call) read_lock_bh(&call->state_lock); if (call->state < RXRPC_CALL_COMPLETE && !test_and_set_bit(RXRPC_CALL_ACK, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); } diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index 01eb33c30571..43cb3e051ece 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c @@ -356,7 +356,7 @@ static int rxrpc_connect_exclusive(struct rxrpc_sock *rx, conn->out_clientflag = RXRPC_CLIENT_INITIATED; conn->cid = 0; conn->state = RXRPC_CONN_CLIENT; - conn->avail_calls = RXRPC_MAXCALLS; + conn->avail_calls = RXRPC_MAXCALLS - 1; conn->security_level = rx->min_sec_level; conn->key = key_get(rx->key); @@ -447,6 +447,11 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, if (--conn->avail_calls == 0) list_move(&conn->bundle_link, &bundle->busy_conns); + ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS); + ASSERT(conn->channels[0] == NULL || + conn->channels[1] == NULL || + conn->channels[2] == NULL || + conn->channels[3] == NULL); atomic_inc(&conn->usage); break; } @@ -456,6 +461,12 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, conn = list_entry(bundle->unused_conns.next, struct rxrpc_connection, bundle_link); + ASSERTCMP(conn->avail_calls, ==, RXRPC_MAXCALLS); + conn->avail_calls = RXRPC_MAXCALLS - 1; + ASSERT(conn->channels[0] == NULL && + conn->channels[1] == NULL && + conn->channels[2] == NULL && + conn->channels[3] == NULL); atomic_inc(&conn->usage); list_move(&conn->bundle_link, &bundle->avail_conns); break; @@ -512,7 +523,7 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, candidate->state = RXRPC_CONN_CLIENT; candidate->avail_calls = RXRPC_MAXCALLS; candidate->security_level = rx->min_sec_level; - candidate->key = key_get(rx->key); + candidate->key = key_get(bundle->key); ret = rxrpc_init_client_conn_security(candidate); if (ret < 0) { @@ -555,6 +566,10 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, for (chan = 0; chan < RXRPC_MAXCALLS; chan++) if (!conn->channels[chan]) goto found_channel; + ASSERT(conn->channels[0] == NULL || + conn->channels[1] == NULL || + conn->channels[2] == NULL || + conn->channels[3] == NULL); BUG(); found_channel: @@ -567,6 +582,7 @@ found_channel: _net("CONNECT client on conn %d chan %d as call %x", conn->debug_id, chan, ntohl(call->call_id)); + ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS); spin_unlock(&trans->client_lock); rxrpc_add_call_ID_to_conn(conn, call); @@ -778,7 +794,7 @@ void rxrpc_put_connection(struct rxrpc_connection *conn) conn->put_time = xtime.tv_sec; if (atomic_dec_and_test(&conn->usage)) { _debug("zombie"); - schedule_delayed_work(&rxrpc_connection_reap, 0); + rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); } _leave(""); @@ -862,8 +878,8 @@ void rxrpc_connection_reaper(struct work_struct *work) if (earliest != ULONG_MAX) { _debug("reschedule reaper %ld", (long) earliest - now); ASSERTCMP(earliest, >, now); - schedule_delayed_work(&rxrpc_connection_reap, - (earliest - now) * HZ); + rxrpc_queue_delayed_work(&rxrpc_connection_reap, + (earliest - now) * HZ); } /* then destroy all those pulled out */ @@ -889,7 +905,7 @@ void __exit rxrpc_destroy_all_connections(void) rxrpc_connection_timeout = 0; cancel_delayed_work(&rxrpc_connection_reap); - schedule_delayed_work(&rxrpc_connection_reap, 0); + rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); _leave(""); } diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c index 4b02815c1ded..1ada43d51165 100644 --- a/net/rxrpc/ar-connevent.c +++ b/net/rxrpc/ar-connevent.c @@ -45,7 +45,7 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state, set_bit(RXRPC_CALL_CONN_ABORT, &call->events); else set_bit(RXRPC_CALL_RCVD_ABORT, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } write_unlock(&call->state_lock); } @@ -133,7 +133,7 @@ void rxrpc_call_is_secure(struct rxrpc_call *call) read_lock(&call->state_lock); if (call->state < RXRPC_CALL_COMPLETE && !test_and_set_bit(RXRPC_CALL_SECURED, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock(&call->state_lock); } } @@ -307,6 +307,22 @@ protocol_error: goto out; } +/* + * put a packet up for transport-level abort + */ +void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb) +{ + CHECK_SLAB_OKAY(&local->usage); + + if (!atomic_inc_not_zero(&local->usage)) { + printk("resurrected on reject\n"); + BUG(); + } + + skb_queue_tail(&local->reject_queue, skb); + rxrpc_queue_work(&local->rejecter); +} + /* * reject packets through the local endpoint */ diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c index f5539e2f7b58..2c27df1ffa17 100644 --- a/net/rxrpc/ar-error.c +++ b/net/rxrpc/ar-error.c @@ -111,7 +111,7 @@ void rxrpc_UDP_error_report(struct sock *sk) /* pass the transport ref to error_handler to release */ skb_queue_tail(&trans->error_queue, skb); - schedule_work(&trans->error_handler); + rxrpc_queue_work(&trans->error_handler); /* reset and regenerate socket error */ spin_lock_bh(&sk->sk_error_queue.lock); @@ -235,7 +235,7 @@ void rxrpc_UDP_error_handler(struct work_struct *work) call->state < RXRPC_CALL_NETWORK_ERROR) { call->state = RXRPC_CALL_NETWORK_ERROR; set_bit(RXRPC_CALL_RCVD_ERROR, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } write_unlock(&call->state_lock); list_del_init(&call->error_link); @@ -245,7 +245,7 @@ void rxrpc_UDP_error_handler(struct work_struct *work) } if (!skb_queue_empty(&trans->error_queue)) - schedule_work(&trans->error_handler); + rxrpc_queue_work(&trans->error_handler); rxrpc_free_skb(skb); rxrpc_put_transport(trans); diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index 323c3454561c..ceb5d619a1d4 100644 --- a/net/rxrpc/ar-input.c +++ b/net/rxrpc/ar-input.c @@ -42,6 +42,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb, bool force, bool terminal) { struct rxrpc_skb_priv *sp; + struct rxrpc_sock *rx = call->socket; struct sock *sk; int skb_len, ret; @@ -64,7 +65,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb, return 0; } - sk = &call->socket->sk; + sk = &rx->sk; if (!force) { /* cast skb->rcvbuf to unsigned... It's pointless, but @@ -89,25 +90,30 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb, skb->sk = sk; atomic_add(skb->truesize, &sk->sk_rmem_alloc); - /* Cache the SKB length before we tack it onto the receive - * queue. Once it is added it no longer belongs to us and - * may be freed by other threads of control pulling packets - * from the queue. - */ - skb_len = skb->len; - - _net("post skb %p", skb); - __skb_queue_tail(&sk->sk_receive_queue, skb); - spin_unlock_bh(&sk->sk_receive_queue.lock); - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk, skb_len); - if (terminal) { _debug("<<<< TERMINAL MESSAGE >>>>"); set_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags); } + /* allow interception by a kernel service */ + if (rx->interceptor) { + rx->interceptor(sk, call->user_call_ID, skb); + spin_unlock_bh(&sk->sk_receive_queue.lock); + } else { + + /* Cache the SKB length before we tack it onto the + * receive queue. Once it is added it no longer + * belongs to us and may be freed by other threads of + * control pulling packets from the queue */ + skb_len = skb->len; + + _net("post skb %p", skb); + __skb_queue_tail(&sk->sk_receive_queue, skb); + spin_unlock_bh(&sk->sk_receive_queue.lock); + + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb_len); + } skb = NULL; } else { spin_unlock_bh(&sk->sk_receive_queue.lock); @@ -232,7 +238,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call, read_lock(&call->state_lock); if (call->state < RXRPC_CALL_COMPLETE && !test_and_set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock(&call->state_lock); } @@ -267,7 +273,7 @@ enqueue_packet: atomic_inc(&call->ackr_not_idle); read_lock(&call->state_lock); if (call->state < RXRPC_CALL_DEAD) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock(&call->state_lock); _leave(" = 0 [queued]"); return 0; @@ -360,7 +366,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb) call->state = RXRPC_CALL_REMOTELY_ABORTED; call->abort_code = abort_code; set_bit(RXRPC_CALL_RCVD_ABORT, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } goto free_packet_unlock; @@ -375,7 +381,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb) case RXRPC_CALL_CLIENT_SEND_REQUEST: call->state = RXRPC_CALL_SERVER_BUSY; set_bit(RXRPC_CALL_RCVD_BUSY, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); case RXRPC_CALL_SERVER_BUSY: goto free_packet_unlock; default: @@ -419,7 +425,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb) read_lock_bh(&call->state_lock); if (call->state < RXRPC_CALL_DEAD) { skb_queue_tail(&call->rx_queue, skb); - schedule_work(&call->processor); + rxrpc_queue_call(call); skb = NULL; } read_unlock_bh(&call->state_lock); @@ -434,7 +440,7 @@ protocol_error_locked: call->state = RXRPC_CALL_LOCALLY_ABORTED; call->abort_code = RX_PROTOCOL_ERROR; set_bit(RXRPC_CALL_ABORT, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } free_packet_unlock: write_unlock_bh(&call->state_lock); @@ -506,7 +512,7 @@ protocol_error: call->state = RXRPC_CALL_LOCALLY_ABORTED; call->abort_code = RX_PROTOCOL_ERROR; set_bit(RXRPC_CALL_ABORT, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); } write_unlock_bh(&call->state_lock); _leave(""); @@ -542,7 +548,7 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn, switch (call->state) { case RXRPC_CALL_LOCALLY_ABORTED: if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); case RXRPC_CALL_REMOTELY_ABORTED: case RXRPC_CALL_NETWORK_ERROR: case RXRPC_CALL_DEAD: @@ -591,7 +597,7 @@ dead_call: sp->hdr.seq == __constant_cpu_to_be32(1)) { _debug("incoming call"); skb_queue_tail(&conn->trans->local->accept_queue, skb); - schedule_work(&conn->trans->local->acceptor); + rxrpc_queue_work(&conn->trans->local->acceptor); goto done; } @@ -630,7 +636,7 @@ found_completed_call: _debug("final ack again"); rxrpc_get_call(call); set_bit(RXRPC_CALL_ACK_FINAL, &call->events); - schedule_work(&call->processor); + rxrpc_queue_call(call); free_unlock: read_unlock(&call->state_lock); @@ -651,7 +657,7 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn, atomic_inc(&conn->usage); skb_queue_tail(&conn->rx_queue, skb); - schedule_work(&conn->processor); + rxrpc_queue_conn(conn); } /* @@ -767,7 +773,7 @@ cant_route_call: if (sp->hdr.seq == __constant_cpu_to_be32(1)) { _debug("first packet"); skb_queue_tail(&local->accept_queue, skb); - schedule_work(&local->acceptor); + rxrpc_queue_work(&local->acceptor); rxrpc_put_local(local); _leave(" [incoming]"); return; diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 7bfbf471c81e..cb1eb492ee48 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -19,8 +19,6 @@ #define CHECK_SLAB_OKAY(X) do {} while(0) #endif -extern atomic_t rxrpc_n_skbs; - #define FCRYPT_BSIZE 8 struct rxrpc_crypt { union { @@ -29,8 +27,12 @@ struct rxrpc_crypt { }; } __attribute__((aligned(8))); -extern __be32 rxrpc_epoch; /* local epoch for detecting local-end reset */ -extern atomic_t rxrpc_debug_id; /* current debugging ID */ +#define rxrpc_queue_work(WS) queue_work(rxrpc_workqueue, (WS)) +#define rxrpc_queue_delayed_work(WS,D) \ + queue_delayed_work(rxrpc_workqueue, (WS), (D)) + +#define rxrpc_queue_call(CALL) rxrpc_queue_work(&(CALL)->processor) +#define rxrpc_queue_conn(CONN) rxrpc_queue_work(&(CONN)->processor) /* * sk_state for RxRPC sockets @@ -50,6 +52,7 @@ enum { struct rxrpc_sock { /* WARNING: sk has to be the first member */ struct sock sk; + rxrpc_interceptor_t interceptor; /* kernel service Rx interceptor function */ struct rxrpc_local *local; /* local endpoint */ struct rxrpc_transport *trans; /* transport handler */ struct rxrpc_conn_bundle *bundle; /* virtual connection bundle */ @@ -91,16 +94,6 @@ struct rxrpc_skb_priv { #define rxrpc_skb(__skb) ((struct rxrpc_skb_priv *) &(__skb)->cb) -enum { - RXRPC_SKB_MARK_DATA, /* data message */ - RXRPC_SKB_MARK_FINAL_ACK, /* final ACK received message */ - RXRPC_SKB_MARK_BUSY, /* server busy message */ - RXRPC_SKB_MARK_REMOTE_ABORT, /* remote abort message */ - RXRPC_SKB_MARK_NET_ERROR, /* network error message */ - RXRPC_SKB_MARK_LOCAL_ERROR, /* local error message */ - RXRPC_SKB_MARK_NEW_CALL, /* local error message */ -}; - enum rxrpc_command { RXRPC_CMD_SEND_DATA, /* send data message */ RXRPC_CMD_SEND_ABORT, /* request abort generation */ @@ -439,25 +432,20 @@ static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code) } /* - * put a packet up for transport-level abort + * af_rxrpc.c */ -static inline -void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb) -{ - CHECK_SLAB_OKAY(&local->usage); - if (!atomic_inc_not_zero(&local->usage)) { - printk("resurrected on reject\n"); - BUG(); - } - skb_queue_tail(&local->reject_queue, skb); - schedule_work(&local->rejecter); -} +extern atomic_t rxrpc_n_skbs; +extern __be32 rxrpc_epoch; +extern atomic_t rxrpc_debug_id; +extern struct workqueue_struct *rxrpc_workqueue; /* * ar-accept.c */ extern void rxrpc_accept_incoming_calls(struct work_struct *); -extern int rxrpc_accept_call(struct rxrpc_sock *, unsigned long); +extern struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *, + unsigned long); +extern int rxrpc_reject_call(struct rxrpc_sock *); /* * ar-ack.c @@ -514,6 +502,7 @@ rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_header *, * ar-connevent.c */ extern void rxrpc_process_connection(struct work_struct *); +extern void rxrpc_reject_packet(struct rxrpc_local *, struct sk_buff *); extern void rxrpc_reject_packets(struct work_struct *); /* @@ -583,6 +572,7 @@ extern struct file_operations rxrpc_connection_seq_fops; /* * ar-recvmsg.c */ +extern void rxrpc_remove_user_ID(struct rxrpc_sock *, struct rxrpc_call *); extern int rxrpc_recvmsg(struct kiocb *, struct socket *, struct msghdr *, size_t, int); diff --git a/net/rxrpc/ar-local.c b/net/rxrpc/ar-local.c index a20a2c0fe105..fe03f71f17da 100644 --- a/net/rxrpc/ar-local.c +++ b/net/rxrpc/ar-local.c @@ -228,7 +228,7 @@ void rxrpc_put_local(struct rxrpc_local *local) write_lock_bh(&rxrpc_local_lock); if (unlikely(atomic_dec_and_test(&local->usage))) { _debug("destroy local"); - schedule_work(&local->destroyer); + rxrpc_queue_work(&local->destroyer); } write_unlock_bh(&rxrpc_local_lock); _leave(""); diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index 67aa9510f09b..5cdde4a48ed1 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -113,7 +113,7 @@ static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code) clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events); clear_bit(RXRPC_CALL_ACK, &call->events); clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags); - schedule_work(&call->processor); + rxrpc_queue_call(call); } write_unlock_bh(&call->state_lock); @@ -194,6 +194,77 @@ int rxrpc_client_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx, return ret; } +/** + * rxrpc_kernel_send_data - Allow a kernel service to send data on a call + * @call: The call to send data through + * @msg: The data to send + * @len: The amount of data to send + * + * Allow a kernel service to send data on a call. The call must be in an state + * appropriate to sending data. No control data should be supplied in @msg, + * nor should an address be supplied. MSG_MORE should be flagged if there's + * more data to come, otherwise this data will end the transmission phase. + */ +int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg, + size_t len) +{ + int ret; + + _enter("{%d,%s},", call->debug_id, rxrpc_call_states[call->state]); + + ASSERTCMP(msg->msg_name, ==, NULL); + ASSERTCMP(msg->msg_control, ==, NULL); + + lock_sock(&call->socket->sk); + + _debug("CALL %d USR %lx ST %d on CONN %p", + call->debug_id, call->user_call_ID, call->state, call->conn); + + if (call->state >= RXRPC_CALL_COMPLETE) { + ret = -ESHUTDOWN; /* it's too late for this call */ + } else if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST && + call->state != RXRPC_CALL_SERVER_ACK_REQUEST && + call->state != RXRPC_CALL_SERVER_SEND_REPLY) { + ret = -EPROTO; /* request phase complete for this client call */ + } else { + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = rxrpc_send_data(NULL, call->socket, call, msg, len); + set_fs(oldfs); + } + + release_sock(&call->socket->sk); + _leave(" = %d", ret); + return ret; +} + +EXPORT_SYMBOL(rxrpc_kernel_send_data); + +/* + * rxrpc_kernel_abort_call - Allow a kernel service to abort a call + * @call: The call to be aborted + * @abort_code: The abort code to stick into the ABORT packet + * + * Allow a kernel service to abort a call, if it's still in an abortable state. + */ +void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code) +{ + _enter("{%d},%d", call->debug_id, abort_code); + + lock_sock(&call->socket->sk); + + _debug("CALL %d USR %lx ST %d on CONN %p", + call->debug_id, call->user_call_ID, call->state, call->conn); + + if (call->state < RXRPC_CALL_COMPLETE) + rxrpc_send_abort(call, abort_code); + + release_sock(&call->socket->sk); + _leave(""); +} + +EXPORT_SYMBOL(rxrpc_kernel_abort_call); + /* * send a message through a server socket * - caller holds the socket locked @@ -214,8 +285,13 @@ int rxrpc_server_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx, if (ret < 0) return ret; - if (cmd == RXRPC_CMD_ACCEPT) - return rxrpc_accept_call(rx, user_call_ID); + if (cmd == RXRPC_CMD_ACCEPT) { + call = rxrpc_accept_call(rx, user_call_ID); + if (IS_ERR(call)) + return PTR_ERR(call); + rxrpc_put_call(call); + return 0; + } call = rxrpc_find_server_call(rx, user_call_ID); if (!call) @@ -363,7 +439,7 @@ static inline void rxrpc_instant_resend(struct rxrpc_call *call) clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags); if (call->state < RXRPC_CALL_COMPLETE && !test_and_set_bit(RXRPC_CALL_RESEND_TIMER, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); } read_unlock_bh(&call->state_lock); } diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index 69ac355546ae..d399de4a7fe2 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c @@ -219,7 +219,7 @@ void rxrpc_put_peer(struct rxrpc_peer *peer) return; } - schedule_work(&peer->destroyer); + rxrpc_queue_work(&peer->destroyer); _leave(""); } diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c index e947d5c15900..f19121d4795b 100644 --- a/net/rxrpc/ar-recvmsg.c +++ b/net/rxrpc/ar-recvmsg.c @@ -19,7 +19,7 @@ * removal a call's user ID from the socket tree to make the user ID available * again and so that it won't be seen again in association with that call */ -static void rxrpc_remove_user_ID(struct rxrpc_sock *rx, struct rxrpc_call *call) +void rxrpc_remove_user_ID(struct rxrpc_sock *rx, struct rxrpc_call *call) { _debug("RELEASE CALL %d", call->debug_id); @@ -33,7 +33,7 @@ static void rxrpc_remove_user_ID(struct rxrpc_sock *rx, struct rxrpc_call *call) read_lock_bh(&call->state_lock); if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) && !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) - schedule_work(&call->processor); + rxrpc_queue_call(call); read_unlock_bh(&call->state_lock); } @@ -364,3 +364,74 @@ wait_error: return copied; } + +/** + * rxrpc_kernel_data_delivered - Record delivery of data message + * @skb: Message holding data + * + * Record the delivery of a data message. This permits RxRPC to keep its + * tracking correct. The socket buffer will be deleted. + */ +void rxrpc_kernel_data_delivered(struct sk_buff *skb) +{ + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + struct rxrpc_call *call = sp->call; + + ASSERTCMP(ntohl(sp->hdr.seq), >=, call->rx_data_recv); + ASSERTCMP(ntohl(sp->hdr.seq), <=, call->rx_data_recv + 1); + call->rx_data_recv = ntohl(sp->hdr.seq); + + ASSERTCMP(ntohl(sp->hdr.seq), >, call->rx_data_eaten); + rxrpc_free_skb(skb); +} + +EXPORT_SYMBOL(rxrpc_kernel_data_delivered); + +/** + * rxrpc_kernel_is_data_last - Determine if data message is last one + * @skb: Message holding data + * + * Determine if data message is last one for the parent call. + */ +bool rxrpc_kernel_is_data_last(struct sk_buff *skb) +{ + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + + ASSERTCMP(skb->mark, ==, RXRPC_SKB_MARK_DATA); + + return sp->hdr.flags & RXRPC_LAST_PACKET; +} + +EXPORT_SYMBOL(rxrpc_kernel_is_data_last); + +/** + * rxrpc_kernel_get_abort_code - Get the abort code from an RxRPC abort message + * @skb: Message indicating an abort + * + * Get the abort code from an RxRPC abort message. + */ +u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb) +{ + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + + ASSERTCMP(skb->mark, ==, RXRPC_SKB_MARK_REMOTE_ABORT); + + return sp->call->abort_code; +} + +EXPORT_SYMBOL(rxrpc_kernel_get_abort_code); + +/** + * rxrpc_kernel_get_error - Get the error number from an RxRPC error message + * @skb: Message indicating an error + * + * Get the error number from an RxRPC error message. + */ +int rxrpc_kernel_get_error_number(struct sk_buff *skb) +{ + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + + return sp->error; +} + +EXPORT_SYMBOL(rxrpc_kernel_get_error_number); diff --git a/net/rxrpc/ar-skbuff.c b/net/rxrpc/ar-skbuff.c index d73f6fc76011..de755e04d29c 100644 --- a/net/rxrpc/ar-skbuff.c +++ b/net/rxrpc/ar-skbuff.c @@ -36,7 +36,7 @@ static void rxrpc_request_final_ACK(struct rxrpc_call *call) rxrpc_get_call(call); set_bit(RXRPC_CALL_ACK_FINAL, &call->events); if (try_to_del_timer_sync(&call->ack_timer) >= 0) - schedule_work(&call->processor); + rxrpc_queue_call(call); break; case RXRPC_CALL_SERVER_RECV_REQUEST: @@ -116,3 +116,17 @@ void rxrpc_packet_destructor(struct sk_buff *skb) sock_rfree(skb); _leave(""); } + +/** + * rxrpc_kernel_free_skb - Free an RxRPC socket buffer + * @skb: The socket buffer to be freed + * + * Let RxRPC free its own socket buffer, permitting it to maintain debug + * accounting. + */ +void rxrpc_kernel_free_skb(struct sk_buff *skb) +{ + rxrpc_free_skb(skb); +} + +EXPORT_SYMBOL(rxrpc_kernel_free_skb); diff --git a/net/rxrpc/ar-transport.c b/net/rxrpc/ar-transport.c index 9b4e5cb545d2..d43d78f19302 100644 --- a/net/rxrpc/ar-transport.c +++ b/net/rxrpc/ar-transport.c @@ -189,7 +189,7 @@ void rxrpc_put_transport(struct rxrpc_transport *trans) /* let the reaper determine the timeout to avoid a race with * overextending the timeout if the reaper is running at the * same time */ - schedule_delayed_work(&rxrpc_transport_reap, 0); + rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0); _leave(""); } @@ -243,8 +243,8 @@ static void rxrpc_transport_reaper(struct work_struct *work) if (earliest != ULONG_MAX) { _debug("reschedule reaper %ld", (long) earliest - now); ASSERTCMP(earliest, >, now); - schedule_delayed_work(&rxrpc_transport_reap, - (earliest - now) * HZ); + rxrpc_queue_delayed_work(&rxrpc_transport_reap, + (earliest - now) * HZ); } /* then destroy all those pulled out */ @@ -270,7 +270,7 @@ void __exit rxrpc_destroy_all_transports(void) rxrpc_transport_timeout = 0; cancel_delayed_work(&rxrpc_transport_reap); - schedule_delayed_work(&rxrpc_transport_reap, 0); + rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0); _leave(""); } -- cgit v1.2.3-59-g8ed1b From 63b6be55e8b51cb718468794d343058e96c7462c Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 26 Apr 2007 15:55:48 -0700 Subject: [AF_RXRPC]: Delete the old RxRPC code. Delete the old RxRPC code as it's now no longer used. Signed-off-by: David Howells Signed-off-by: David S. Miller --- fs/Kconfig | 4 - include/rxrpc/call.h | 212 ----- include/rxrpc/connection.h | 83 -- include/rxrpc/krxiod.h | 27 - include/rxrpc/krxsecd.h | 22 - include/rxrpc/krxtimod.h | 45 - include/rxrpc/message.h | 71 -- include/rxrpc/packet.h | 22 +- include/rxrpc/peer.h | 82 -- include/rxrpc/rxrpc.h | 36 - include/rxrpc/transport.h | 106 --- net/rxrpc/Makefile | 27 +- net/rxrpc/call.c | 2277 -------------------------------------------- net/rxrpc/connection.c | 777 --------------- net/rxrpc/internal.h | 106 --- net/rxrpc/krxiod.c | 262 ----- net/rxrpc/krxsecd.c | 270 ------ net/rxrpc/krxtimod.c | 204 ---- net/rxrpc/main.c | 180 ---- net/rxrpc/peer.c | 398 -------- net/rxrpc/proc.c | 617 ------------ net/rxrpc/rxrpc_syms.c | 34 - net/rxrpc/sysctl.c | 121 --- net/rxrpc/transport.c | 846 ---------------- 24 files changed, 9 insertions(+), 6820 deletions(-) delete mode 100644 include/rxrpc/call.h delete mode 100644 include/rxrpc/connection.h delete mode 100644 include/rxrpc/krxiod.h delete mode 100644 include/rxrpc/krxsecd.h delete mode 100644 include/rxrpc/krxtimod.h delete mode 100644 include/rxrpc/message.h delete mode 100644 include/rxrpc/peer.h delete mode 100644 include/rxrpc/rxrpc.h delete mode 100644 include/rxrpc/transport.h delete mode 100644 net/rxrpc/call.c delete mode 100644 net/rxrpc/connection.c delete mode 100644 net/rxrpc/internal.h delete mode 100644 net/rxrpc/krxiod.c delete mode 100644 net/rxrpc/krxsecd.c delete mode 100644 net/rxrpc/krxtimod.c delete mode 100644 net/rxrpc/main.c delete mode 100644 net/rxrpc/peer.c delete mode 100644 net/rxrpc/proc.c delete mode 100644 net/rxrpc/rxrpc_syms.c delete mode 100644 net/rxrpc/sysctl.c delete mode 100644 net/rxrpc/transport.c (limited to 'include/rxrpc/packet.h') diff --git a/fs/Kconfig b/fs/Kconfig index 075c9997ddc5..e33c08924572 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -2038,10 +2038,6 @@ config AFS_DEBUG If unsure, say N. - -config RXRPC - tristate - config 9P_FS tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)" depends on INET && EXPERIMENTAL diff --git a/include/rxrpc/call.h b/include/rxrpc/call.h deleted file mode 100644 index b86f83743510..000000000000 --- a/include/rxrpc/call.h +++ /dev/null @@ -1,212 +0,0 @@ -/* call.h: Rx call record - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_CALL_H -#define _LINUX_RXRPC_CALL_H - -#include -#include -#include -#include - -#define RXRPC_CALL_ACK_WINDOW_SIZE 16 - -extern unsigned rxrpc_call_rcv_timeout; /* receive activity timeout (secs) */ - -/* application call state - * - only state 0 and ffff are reserved, the state is set to 1 after an opid is received - */ -enum rxrpc_app_cstate { - RXRPC_CSTATE_COMPLETE = 0, /* operation complete */ - RXRPC_CSTATE_ERROR, /* operation ICMP error or aborted */ - RXRPC_CSTATE_SRVR_RCV_OPID, /* [SERVER] receiving operation ID */ - RXRPC_CSTATE_SRVR_RCV_ARGS, /* [SERVER] receiving operation data */ - RXRPC_CSTATE_SRVR_GOT_ARGS, /* [SERVER] completely received operation data */ - RXRPC_CSTATE_SRVR_SND_REPLY, /* [SERVER] sending operation reply */ - RXRPC_CSTATE_SRVR_RCV_FINAL_ACK, /* [SERVER] receiving final ACK */ - RXRPC_CSTATE_CLNT_SND_ARGS, /* [CLIENT] sending operation args */ - RXRPC_CSTATE_CLNT_RCV_REPLY, /* [CLIENT] receiving operation reply */ - RXRPC_CSTATE_CLNT_GOT_REPLY, /* [CLIENT] completely received operation reply */ -} __attribute__((packed)); - -extern const char *rxrpc_call_states[]; - -enum rxrpc_app_estate { - RXRPC_ESTATE_NO_ERROR = 0, /* no error */ - RXRPC_ESTATE_LOCAL_ABORT, /* aborted locally by application layer */ - RXRPC_ESTATE_PEER_ABORT, /* aborted remotely by peer */ - RXRPC_ESTATE_LOCAL_ERROR, /* local ICMP network error */ - RXRPC_ESTATE_REMOTE_ERROR, /* remote ICMP network error */ -} __attribute__((packed)); - -extern const char *rxrpc_call_error_states[]; - -/*****************************************************************************/ -/* - * Rx call record and application scratch buffer - * - the call record occupies the bottom of a complete page - * - the application scratch buffer occupies the rest - */ -struct rxrpc_call -{ - atomic_t usage; - struct rxrpc_connection *conn; /* connection upon which active */ - spinlock_t lock; /* access lock */ - struct module *owner; /* owner module */ - wait_queue_head_t waitq; /* wait queue for events to happen */ - struct list_head link; /* general internal list link */ - struct list_head call_link; /* master call list link */ - __be32 chan_ix; /* connection channel index */ - __be32 call_id; /* call ID on connection */ - unsigned long cjif; /* jiffies at call creation */ - unsigned long flags; /* control flags */ -#define RXRPC_CALL_ACKS_TIMO 0x00000001 /* ACKS timeout reached */ -#define RXRPC_CALL_ACKR_TIMO 0x00000002 /* ACKR timeout reached */ -#define RXRPC_CALL_RCV_TIMO 0x00000004 /* RCV timeout reached */ -#define RXRPC_CALL_RCV_PKT 0x00000008 /* received packet */ - - /* transmission */ - rxrpc_seq_t snd_seq_count; /* outgoing packet sequence number counter */ - struct rxrpc_message *snd_nextmsg; /* next message being constructed for sending */ - struct rxrpc_message *snd_ping; /* last ping message sent */ - unsigned short snd_resend_cnt; /* count of resends since last ACK */ - - /* transmission ACK tracking */ - struct list_head acks_pendq; /* messages pending ACK (ordered by seq) */ - unsigned acks_pend_cnt; /* number of un-ACK'd packets */ - rxrpc_seq_t acks_dftv_seq; /* highest definitively ACK'd msg seq */ - struct timer_list acks_timeout; /* timeout on expected ACK */ - - /* reception */ - struct list_head rcv_receiveq; /* messages pending reception (ordered by seq) */ - struct list_head rcv_krxiodq_lk; /* krxiod queue for new inbound packets */ - struct timer_list rcv_timeout; /* call receive activity timeout */ - - /* reception ACK'ing */ - rxrpc_seq_t ackr_win_bot; /* bottom of ACK window */ - rxrpc_seq_t ackr_win_top; /* top of ACK window */ - rxrpc_seq_t ackr_high_seq; /* highest seqno yet received */ - rxrpc_seq_net_t ackr_prev_seq; /* previous seqno received */ - unsigned ackr_pend_cnt; /* number of pending ACKs */ - struct timer_list ackr_dfr_timo; /* timeout on deferred ACK */ - char ackr_dfr_perm; /* request for deferred ACKs permitted */ - rxrpc_seq_t ackr_dfr_seq; /* seqno for deferred ACK */ - struct rxrpc_ackpacket ackr; /* pending normal ACK packet */ - uint8_t ackr_array[RXRPC_CALL_ACK_WINDOW_SIZE]; /* ACK records */ - - /* presentation layer */ - char app_last_rcv; /* T if received last packet from remote end */ - enum rxrpc_app_cstate app_call_state; /* call state */ - enum rxrpc_app_estate app_err_state; /* abort/error state */ - struct list_head app_readyq; /* ordered ready received packet queue */ - struct list_head app_unreadyq; /* ordered post-hole recv'd packet queue */ - rxrpc_seq_t app_ready_seq; /* last seq number dropped into readyq */ - size_t app_ready_qty; /* amount of data ready in readyq */ - unsigned app_opcode; /* operation ID */ - unsigned app_abort_code; /* abort code (when aborted) */ - int app_errno; /* error number (when ICMP error received) */ - - /* statisics */ - unsigned pkt_rcv_count; /* count of received packets on this call */ - unsigned pkt_snd_count; /* count of sent packets on this call */ - unsigned app_read_count; /* number of reads issued */ - - /* bits for the application to use */ - rxrpc_call_attn_func_t app_attn_func; /* callback when attention required */ - rxrpc_call_error_func_t app_error_func; /* callback when abort sent (cleanup and put) */ - rxrpc_call_aemap_func_t app_aemap_func; /* callback to map abort code to/from errno */ - void *app_user; /* application data */ - struct list_head app_link; /* application list linkage */ - struct list_head app_attn_link; /* application attention list linkage */ - size_t app_mark; /* trigger callback when app_ready_qty>=app_mark */ - char app_async_read; /* T if in async-read mode */ - uint8_t *app_read_buf; /* application async read buffer (app_mark size) */ - uint8_t *app_scr_alloc; /* application scratch allocation pointer */ - void *app_scr_ptr; /* application pointer into scratch buffer */ - -#define RXRPC_APP_MARK_EOF 0xFFFFFFFFU /* mark at end of input */ - - /* application scratch buffer */ - uint8_t app_scratch[0] __attribute__((aligned(sizeof(long)))); -}; - -#define RXRPC_CALL_SCRATCH_SIZE (PAGE_SIZE - sizeof(struct rxrpc_call)) - -#define rxrpc_call_reset_scratch(CALL) \ -do { (CALL)->app_scr_alloc = (CALL)->app_scratch; } while(0) - -#define rxrpc_call_alloc_scratch(CALL,SIZE) \ -({ \ - void *ptr; \ - ptr = (CALL)->app_scr_alloc; \ - (CALL)->app_scr_alloc += (SIZE); \ - if ((SIZE)>RXRPC_CALL_SCRATCH_SIZE || \ - (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) { \ - printk("rxrpc_call_alloc_scratch(%p,%Zu)\n",(CALL),(size_t)(SIZE)); \ - BUG(); \ - } \ - ptr; \ -}) - -#define rxrpc_call_alloc_scratch_s(CALL,TYPE) \ -({ \ - size_t size = sizeof(TYPE); \ - TYPE *ptr; \ - ptr = (TYPE*)(CALL)->app_scr_alloc; \ - (CALL)->app_scr_alloc += size; \ - if (size>RXRPC_CALL_SCRATCH_SIZE || \ - (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) { \ - printk("rxrpc_call_alloc_scratch(%p,%Zu)\n",(CALL),size); \ - BUG(); \ - } \ - ptr; \ -}) - -#define rxrpc_call_is_ack_pending(CALL) ((CALL)->ackr.reason != 0) - -extern int rxrpc_create_call(struct rxrpc_connection *conn, - rxrpc_call_attn_func_t attn, - rxrpc_call_error_func_t error, - rxrpc_call_aemap_func_t aemap, - struct rxrpc_call **_call); - -extern int rxrpc_incoming_call(struct rxrpc_connection *conn, - struct rxrpc_message *msg, - struct rxrpc_call **_call); - -static inline void rxrpc_get_call(struct rxrpc_call *call) -{ - BUG_ON(atomic_read(&call->usage)<=0); - atomic_inc(&call->usage); - /*printk("rxrpc_get_call(%p{u=%d})\n",(C),atomic_read(&(C)->usage));*/ -} - -extern void rxrpc_put_call(struct rxrpc_call *call); - -extern void rxrpc_call_do_stuff(struct rxrpc_call *call); - -extern int rxrpc_call_abort(struct rxrpc_call *call, int error); - -#define RXRPC_CALL_READ_BLOCK 0x0001 /* block if not enough data and not yet EOF */ -#define RXRPC_CALL_READ_ALL 0x0002 /* error if insufficient data received */ -extern int rxrpc_call_read_data(struct rxrpc_call *call, void *buffer, size_t size, int flags); - -extern int rxrpc_call_write_data(struct rxrpc_call *call, - size_t sioc, - struct kvec *siov, - uint8_t rxhdr_flags, - gfp_t alloc_flags, - int dup_data, - size_t *size_sent); - -extern void rxrpc_call_handle_error(struct rxrpc_call *conn, int local, int errno); - -#endif /* _LINUX_RXRPC_CALL_H */ diff --git a/include/rxrpc/connection.h b/include/rxrpc/connection.h deleted file mode 100644 index 41e6781ad067..000000000000 --- a/include/rxrpc/connection.h +++ /dev/null @@ -1,83 +0,0 @@ -/* connection.h: Rx connection record - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_CONNECTION_H -#define _LINUX_RXRPC_CONNECTION_H - -#include -#include - -struct sk_buff; - -/*****************************************************************************/ -/* - * Rx connection - * - connections are matched by (rmt_port,rmt_addr,service_id,conn_id,clientflag) - * - connections only retain a refcount on the peer when they are active - * - connections with refcount==0 are inactive and reside in the peer's graveyard - */ -struct rxrpc_connection -{ - atomic_t usage; - struct rxrpc_transport *trans; /* transport endpoint */ - struct rxrpc_peer *peer; /* peer from/to which connected */ - struct rxrpc_service *service; /* responsible service (inbound conns) */ - struct rxrpc_timer timeout; /* decaching timer */ - struct list_head link; /* link in peer's list */ - struct list_head proc_link; /* link in proc list */ - struct list_head err_link; /* link in ICMP error processing list */ - struct list_head id_link; /* link in ID grant list */ - struct sockaddr_in addr; /* remote address */ - struct rxrpc_call *channels[4]; /* channels (active calls) */ - wait_queue_head_t chanwait; /* wait for channel to become available */ - spinlock_t lock; /* access lock */ - struct timeval atime; /* last access time */ - size_t mtu_size; /* MTU size for outbound messages */ - unsigned call_counter; /* call ID counter */ - rxrpc_serial_t serial_counter; /* packet serial number counter */ - - /* the following should all be in net order */ - __be32 in_epoch; /* peer's epoch */ - __be32 out_epoch; /* my epoch */ - __be32 conn_id; /* connection ID, appropriately shifted */ - __be16 service_id; /* service ID */ - uint8_t security_ix; /* security ID */ - uint8_t in_clientflag; /* RXRPC_CLIENT_INITIATED if we are server */ - uint8_t out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */ -}; - -extern int rxrpc_create_connection(struct rxrpc_transport *trans, - __be16 port, - __be32 addr, - uint16_t service_id, - void *security, - struct rxrpc_connection **_conn); - -extern int rxrpc_connection_lookup(struct rxrpc_peer *peer, - struct rxrpc_message *msg, - struct rxrpc_connection **_conn); - -static inline void rxrpc_get_connection(struct rxrpc_connection *conn) -{ - BUG_ON(atomic_read(&conn->usage)<0); - atomic_inc(&conn->usage); - //printk("rxrpc_get_conn(%p{u=%d})\n",conn,atomic_read(&conn->usage)); -} - -extern void rxrpc_put_connection(struct rxrpc_connection *conn); - -extern int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn, - struct rxrpc_call *call, - struct rxrpc_message *msg); - -extern void rxrpc_conn_handle_error(struct rxrpc_connection *conn, int local, int errno); - -#endif /* _LINUX_RXRPC_CONNECTION_H */ diff --git a/include/rxrpc/krxiod.h b/include/rxrpc/krxiod.h deleted file mode 100644 index c0e0e82e4df2..000000000000 --- a/include/rxrpc/krxiod.h +++ /dev/null @@ -1,27 +0,0 @@ -/* krxiod.h: Rx RPC I/O kernel thread interface - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_KRXIOD_H -#define _LINUX_RXRPC_KRXIOD_H - -#include - -extern int rxrpc_krxiod_init(void); -extern void rxrpc_krxiod_kill(void); -extern void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans); -extern void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans); -extern void rxrpc_krxiod_queue_peer(struct rxrpc_peer *peer); -extern void rxrpc_krxiod_dequeue_peer(struct rxrpc_peer *peer); -extern void rxrpc_krxiod_clear_peers(struct rxrpc_transport *trans); -extern void rxrpc_krxiod_queue_call(struct rxrpc_call *call); -extern void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call); - -#endif /* _LINUX_RXRPC_KRXIOD_H */ diff --git a/include/rxrpc/krxsecd.h b/include/rxrpc/krxsecd.h deleted file mode 100644 index 55ce43a25b38..000000000000 --- a/include/rxrpc/krxsecd.h +++ /dev/null @@ -1,22 +0,0 @@ -/* krxsecd.h: Rx RPC security kernel thread interface - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_KRXSECD_H -#define _LINUX_RXRPC_KRXSECD_H - -#include - -extern int rxrpc_krxsecd_init(void); -extern void rxrpc_krxsecd_kill(void); -extern void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans); -extern void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg); - -#endif /* _LINUX_RXRPC_KRXSECD_H */ diff --git a/include/rxrpc/krxtimod.h b/include/rxrpc/krxtimod.h deleted file mode 100644 index b3d298b612f2..000000000000 --- a/include/rxrpc/krxtimod.h +++ /dev/null @@ -1,45 +0,0 @@ -/* krxtimod.h: RxRPC timeout daemon - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_KRXTIMOD_H -#define _LINUX_RXRPC_KRXTIMOD_H - -#include - -struct rxrpc_timer_ops { - /* called when the front of the timer queue has timed out */ - void (*timed_out)(struct rxrpc_timer *timer); -}; - -/*****************************************************************************/ -/* - * RXRPC timer/timeout record - */ -struct rxrpc_timer -{ - struct list_head link; /* link in timer queue */ - unsigned long timo_jif; /* timeout time */ - const struct rxrpc_timer_ops *ops; /* timeout expiry function */ -}; - -static inline void rxrpc_timer_init(rxrpc_timer_t *timer, const struct rxrpc_timer_ops *ops) -{ - INIT_LIST_HEAD(&timer->link); - timer->ops = ops; -} - -extern int rxrpc_krxtimod_start(void); -extern void rxrpc_krxtimod_kill(void); - -extern void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout); -extern int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer); - -#endif /* _LINUX_RXRPC_KRXTIMOD_H */ diff --git a/include/rxrpc/message.h b/include/rxrpc/message.h deleted file mode 100644 index b318f273d4f2..000000000000 --- a/include/rxrpc/message.h +++ /dev/null @@ -1,71 +0,0 @@ -/* message.h: Rx message caching - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_MESSAGE_H -#define _LINUX_RXRPC_MESSAGE_H - -#include - -/*****************************************************************************/ -/* - * Rx message record - */ -struct rxrpc_message -{ - atomic_t usage; - struct list_head link; /* list link */ - struct timeval stamp; /* time received or last sent */ - rxrpc_seq_t seq; /* message sequence number */ - - int state; /* the state the message is currently in */ -#define RXRPC_MSG_PREPARED 0 -#define RXRPC_MSG_SENT 1 -#define RXRPC_MSG_ACKED 2 /* provisionally ACK'd */ -#define RXRPC_MSG_DONE 3 /* definitively ACK'd (msg->sequsage); } while(0) - -extern void __rxrpc_put_message(struct rxrpc_message *msg); -static inline void rxrpc_put_message(struct rxrpc_message *msg) -{ - BUG_ON(atomic_read(&msg->usage)<=0); - if (atomic_dec_and_test(&msg->usage)) - __rxrpc_put_message(msg); -} - -extern int rxrpc_conn_newmsg(struct rxrpc_connection *conn, - struct rxrpc_call *call, - uint8_t type, - int count, - struct kvec *diov, - gfp_t alloc_flags, - struct rxrpc_message **_msg); - -extern int rxrpc_conn_sendmsg(struct rxrpc_connection *conn, struct rxrpc_message *msg); - -#endif /* _LINUX_RXRPC_MESSAGE_H */ diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h index 09b11a1e8d46..b69e6e173ea1 100644 --- a/include/rxrpc/packet.h +++ b/include/rxrpc/packet.h @@ -1,6 +1,6 @@ /* packet.h: Rx packet layout and definitions * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. + * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or @@ -12,21 +12,17 @@ #ifndef _LINUX_RXRPC_PACKET_H #define _LINUX_RXRPC_PACKET_H -#include - -#define RXRPC_IPUDP_SIZE 28 -extern size_t RXRPC_MAX_PACKET_SIZE; -#define RXRPC_MAX_PACKET_DATA_SIZE (RXRPC_MAX_PACKET_SIZE - sizeof(struct rxrpc_header)) -#define RXRPC_LOCAL_PACKET_SIZE RXRPC_MAX_PACKET_SIZE -#define RXRPC_REMOTE_PACKET_SIZE (576 - RXRPC_IPUDP_SIZE) +typedef u32 rxrpc_seq_t; /* Rx message sequence number */ +typedef u32 rxrpc_serial_t; /* Rx message serial number */ +typedef __be32 rxrpc_seq_net_t; /* on-the-wire Rx message sequence number */ +typedef __be32 rxrpc_serial_net_t; /* on-the-wire Rx message serial number */ /*****************************************************************************/ /* * on-the-wire Rx packet header * - all multibyte fields should be in network byte order */ -struct rxrpc_header -{ +struct rxrpc_header { __be32 epoch; /* client boot timestamp */ __be32 cid; /* connection and channel ID */ @@ -85,8 +81,7 @@ extern const char *rxrpc_pkts[]; * - new__rsvd = j__rsvd * - duplicating all other fields */ -struct rxrpc_jumbo_header -{ +struct rxrpc_jumbo_header { uint8_t flags; /* packet flags (as per rxrpc_header) */ uint8_t pad; __be16 _rsvd; /* reserved (used by kerberos security as cksum) */ @@ -99,8 +94,7 @@ struct rxrpc_jumbo_header * on-the-wire Rx ACK packet data payload * - all multibyte fields should be in network byte order */ -struct rxrpc_ackpacket -{ +struct rxrpc_ackpacket { __be16 bufferSpace; /* number of packet buffers available */ __be16 maxSkew; /* diff between serno being ACK'd and highest serial no * received */ diff --git a/include/rxrpc/peer.h b/include/rxrpc/peer.h deleted file mode 100644 index 8b8fe97cbbcc..000000000000 --- a/include/rxrpc/peer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* peer.h: Rx RPC per-transport peer record - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_PEER_H -#define _LINUX_RXRPC_PEER_H - -#include -#include -#include - -struct rxrpc_peer_ops -{ - /* peer record being added */ - int (*adding)(struct rxrpc_peer *peer); - - /* peer record being discarded from graveyard */ - void (*discarding)(struct rxrpc_peer *peer); - - /* change of epoch detected on connection */ - void (*change_of_epoch)(struct rxrpc_connection *conn); -}; - -/*****************************************************************************/ -/* - * Rx RPC per-transport peer record - * - peers only retain a refcount on the transport when they are active - * - peers with refcount==0 are inactive and reside in the transport's graveyard - */ -struct rxrpc_peer -{ - atomic_t usage; - struct rxrpc_peer_ops *ops; /* operations on this peer */ - struct rxrpc_transport *trans; /* owner transport */ - struct rxrpc_timer timeout; /* timeout for grave destruction */ - struct list_head link; /* link in transport's peer list */ - struct list_head proc_link; /* link in /proc list */ - rwlock_t conn_idlock; /* lock for connection IDs */ - struct list_head conn_idlist; /* list of connections granted IDs */ - uint32_t conn_idcounter; /* connection ID counter */ - rwlock_t conn_lock; /* lock for active/dead connections */ - struct list_head conn_active; /* active connections to/from this peer */ - struct list_head conn_graveyard; /* graveyard for inactive connections */ - spinlock_t conn_gylock; /* lock for conn_graveyard */ - wait_queue_head_t conn_gy_waitq; /* wait queue hit when graveyard is empty */ - atomic_t conn_count; /* number of attached connections */ - struct in_addr addr; /* remote address */ - size_t if_mtu; /* interface MTU for this peer */ - spinlock_t lock; /* access lock */ - - void *user; /* application layer data */ - - /* calculated RTT cache */ -#define RXRPC_RTT_CACHE_SIZE 32 - suseconds_t rtt; /* current RTT estimate (in uS) */ - unsigned rtt_point; /* next entry at which to insert */ - unsigned rtt_usage; /* amount of cache actually used */ - suseconds_t rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */ -}; - - -extern int rxrpc_peer_lookup(struct rxrpc_transport *trans, - __be32 addr, - struct rxrpc_peer **_peer); - -static inline void rxrpc_get_peer(struct rxrpc_peer *peer) -{ - BUG_ON(atomic_read(&peer->usage)<0); - atomic_inc(&peer->usage); - //printk("rxrpc_get_peer(%p{u=%d})\n",peer,atomic_read(&peer->usage)); -} - -extern void rxrpc_put_peer(struct rxrpc_peer *peer); - -#endif /* _LINUX_RXRPC_PEER_H */ diff --git a/include/rxrpc/rxrpc.h b/include/rxrpc/rxrpc.h deleted file mode 100644 index 8d9874cef991..000000000000 --- a/include/rxrpc/rxrpc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* rx.h: Rx RPC interface - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_RXRPC_H -#define _LINUX_RXRPC_RXRPC_H - -#ifdef __KERNEL__ - -extern __be32 rxrpc_epoch; - -#ifdef CONFIG_SYSCTL -extern int rxrpc_ktrace; -extern int rxrpc_kdebug; -extern int rxrpc_kproto; -extern int rxrpc_knet; -#else -#define rxrpc_ktrace 0 -#define rxrpc_kdebug 0 -#define rxrpc_kproto 0 -#define rxrpc_knet 0 -#endif - -extern int rxrpc_sysctl_init(void); -extern void rxrpc_sysctl_cleanup(void); - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_RXRPC_RXRPC_H */ diff --git a/include/rxrpc/transport.h b/include/rxrpc/transport.h deleted file mode 100644 index 7c7b9683fa39..000000000000 --- a/include/rxrpc/transport.h +++ /dev/null @@ -1,106 +0,0 @@ -/* transport.h: Rx transport management - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#ifndef _LINUX_RXRPC_TRANSPORT_H -#define _LINUX_RXRPC_TRANSPORT_H - -#include -#include -#include -#include -#include - -typedef int (*rxrpc_newcall_fnx_t)(struct rxrpc_call *call); - -extern wait_queue_head_t rxrpc_krxiod_wq; - -/*****************************************************************************/ -/* - * Rx operation specification - * - tables of these must be sorted by op ID so that they can be binary-chop searched - */ -struct rxrpc_operation -{ - unsigned id; /* operation ID */ - size_t asize; /* minimum size of argument block */ - const char *name; /* name of operation */ - void *user; /* initial user data */ -}; - -/*****************************************************************************/ -/* - * Rx transport service record - */ -struct rxrpc_service -{ - struct list_head link; /* link in services list on transport */ - struct module *owner; /* owner module */ - rxrpc_newcall_fnx_t new_call; /* new call handler function */ - const char *name; /* name of service */ - unsigned short service_id; /* Rx service ID */ - rxrpc_call_attn_func_t attn_func; /* call requires attention callback */ - rxrpc_call_error_func_t error_func; /* call error callback */ - rxrpc_call_aemap_func_t aemap_func; /* abort -> errno mapping callback */ - - const struct rxrpc_operation *ops_begin; /* beginning of operations table */ - const struct rxrpc_operation *ops_end; /* end of operations table */ -}; - -/*****************************************************************************/ -/* - * Rx transport endpoint record - */ -struct rxrpc_transport -{ - atomic_t usage; - struct socket *socket; /* my UDP socket */ - struct list_head services; /* services listening on this socket */ - struct list_head link; /* link in transport list */ - struct list_head proc_link; /* link in transport proc list */ - struct list_head krxiodq_link; /* krxiod attention queue link */ - spinlock_t lock; /* access lock */ - struct list_head peer_active; /* active peers connected to over this socket */ - struct list_head peer_graveyard; /* inactive peer list */ - spinlock_t peer_gylock; /* peer graveyard lock */ - wait_queue_head_t peer_gy_waitq; /* wait queue hit when peer graveyard is empty */ - rwlock_t peer_lock; /* peer list access lock */ - atomic_t peer_count; /* number of peers */ - struct rxrpc_peer_ops *peer_ops; /* default peer operations */ - unsigned short port; /* port upon which listening */ - volatile char error_rcvd; /* T if received ICMP error outstanding */ -}; - -extern int rxrpc_create_transport(unsigned short port, - struct rxrpc_transport **_trans); - -static inline void rxrpc_get_transport(struct rxrpc_transport *trans) -{ - BUG_ON(atomic_read(&trans->usage) <= 0); - atomic_inc(&trans->usage); - //printk("rxrpc_get_transport(%p{u=%d})\n", - // trans, atomic_read(&trans->usage)); -} - -extern void rxrpc_put_transport(struct rxrpc_transport *trans); - -extern int rxrpc_add_service(struct rxrpc_transport *trans, - struct rxrpc_service *srv); - -extern void rxrpc_del_service(struct rxrpc_transport *trans, - struct rxrpc_service *srv); - -extern void rxrpc_trans_receive_packet(struct rxrpc_transport *trans); - -extern int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans, - struct rxrpc_message *msg, - int error); - -#endif /* _LINUX_RXRPC_TRANSPORT_H */ diff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile index 07bf82ffec6a..c46867c61c98 100644 --- a/net/rxrpc/Makefile +++ b/net/rxrpc/Makefile @@ -1,9 +1,7 @@ # -# Makefile for Linux kernel Rx RPC +# Makefile for Linux kernel RxRPC # -#CFLAGS += -finstrument-functions - af-rxrpc-objs := \ af_rxrpc.o \ ar-accept.o \ @@ -29,26 +27,3 @@ endif obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o obj-$(CONFIG_RXKAD) += rxkad.o - -# -# obsolete RxRPC interface, still used by fs/afs/ -# -rxrpc-objs := \ - call.o \ - connection.o \ - krxiod.o \ - krxsecd.o \ - krxtimod.o \ - main.o \ - peer.o \ - rxrpc_syms.o \ - transport.o - -ifeq ($(CONFIG_PROC_FS),y) -rxrpc-objs += proc.o -endif -ifeq ($(CONFIG_SYSCTL),y) -rxrpc-objs += sysctl.o -endif - -obj-$(CONFIG_RXRPC) += rxrpc.o diff --git a/net/rxrpc/call.c b/net/rxrpc/call.c deleted file mode 100644 index d07122b57e0d..000000000000 --- a/net/rxrpc/call.c +++ /dev/null @@ -1,2277 +0,0 @@ -/* call.c: Rx call routines - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -__RXACCT_DECL(atomic_t rxrpc_call_count); -__RXACCT_DECL(atomic_t rxrpc_message_count); - -LIST_HEAD(rxrpc_calls); -DECLARE_RWSEM(rxrpc_calls_sem); - -unsigned rxrpc_call_rcv_timeout = HZ/3; -static unsigned rxrpc_call_acks_timeout = HZ/3; -static unsigned rxrpc_call_dfr_ack_timeout = HZ/20; -static unsigned short rxrpc_call_max_resend = HZ/10; - -const char *rxrpc_call_states[] = { - "COMPLETE", - "ERROR", - "SRVR_RCV_OPID", - "SRVR_RCV_ARGS", - "SRVR_GOT_ARGS", - "SRVR_SND_REPLY", - "SRVR_RCV_FINAL_ACK", - "CLNT_SND_ARGS", - "CLNT_RCV_REPLY", - "CLNT_GOT_REPLY" -}; - -const char *rxrpc_call_error_states[] = { - "NO_ERROR", - "LOCAL_ABORT", - "PEER_ABORT", - "LOCAL_ERROR", - "REMOTE_ERROR" -}; - -const char *rxrpc_pkts[] = { - "?00", - "data", "ack", "busy", "abort", "ackall", "chall", "resp", "debug", - "?09", "?10", "?11", "?12", "?13", "?14", "?15" -}; - -static const char *rxrpc_acks[] = { - "---", "REQ", "DUP", "SEQ", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL", - "-?-" -}; - -static const char _acktype[] = "NA-"; - -static void rxrpc_call_receive_packet(struct rxrpc_call *call); -static void rxrpc_call_receive_data_packet(struct rxrpc_call *call, - struct rxrpc_message *msg); -static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call, - struct rxrpc_message *msg); -static void rxrpc_call_definitively_ACK(struct rxrpc_call *call, - rxrpc_seq_t higest); -static void rxrpc_call_resend(struct rxrpc_call *call, rxrpc_seq_t highest); -static int __rxrpc_call_read_data(struct rxrpc_call *call); - -static int rxrpc_call_record_ACK(struct rxrpc_call *call, - struct rxrpc_message *msg, - rxrpc_seq_t seq, - size_t count); - -static int rxrpc_call_flush(struct rxrpc_call *call); - -#define _state(call) \ - _debug("[[[ state %s ]]]", rxrpc_call_states[call->app_call_state]); - -static void rxrpc_call_default_attn_func(struct rxrpc_call *call) -{ - wake_up(&call->waitq); -} - -static void rxrpc_call_default_error_func(struct rxrpc_call *call) -{ - wake_up(&call->waitq); -} - -static void rxrpc_call_default_aemap_func(struct rxrpc_call *call) -{ - switch (call->app_err_state) { - case RXRPC_ESTATE_LOCAL_ABORT: - call->app_abort_code = -call->app_errno; - case RXRPC_ESTATE_PEER_ABORT: - call->app_errno = -ECONNABORTED; - default: - break; - } -} - -static void __rxrpc_call_acks_timeout(unsigned long _call) -{ - struct rxrpc_call *call = (struct rxrpc_call *) _call; - - _debug("ACKS TIMEOUT %05lu", jiffies - call->cjif); - - call->flags |= RXRPC_CALL_ACKS_TIMO; - rxrpc_krxiod_queue_call(call); -} - -static void __rxrpc_call_rcv_timeout(unsigned long _call) -{ - struct rxrpc_call *call = (struct rxrpc_call *) _call; - - _debug("RCV TIMEOUT %05lu", jiffies - call->cjif); - - call->flags |= RXRPC_CALL_RCV_TIMO; - rxrpc_krxiod_queue_call(call); -} - -static void __rxrpc_call_ackr_timeout(unsigned long _call) -{ - struct rxrpc_call *call = (struct rxrpc_call *) _call; - - _debug("ACKR TIMEOUT %05lu",jiffies - call->cjif); - - call->flags |= RXRPC_CALL_ACKR_TIMO; - rxrpc_krxiod_queue_call(call); -} - -/*****************************************************************************/ -/* - * calculate a timeout based on an RTT value - */ -static inline unsigned long __rxrpc_rtt_based_timeout(struct rxrpc_call *call, - unsigned long val) -{ - unsigned long expiry = call->conn->peer->rtt / (1000000 / HZ); - - expiry += 10; - if (expiry < HZ / 25) - expiry = HZ / 25; - if (expiry > HZ) - expiry = HZ; - - _leave(" = %lu jiffies", expiry); - return jiffies + expiry; -} /* end __rxrpc_rtt_based_timeout() */ - -/*****************************************************************************/ -/* - * create a new call record - */ -static inline int __rxrpc_create_call(struct rxrpc_connection *conn, - struct rxrpc_call **_call) -{ - struct rxrpc_call *call; - - _enter("%p", conn); - - /* allocate and initialise a call record */ - call = (struct rxrpc_call *) get_zeroed_page(GFP_KERNEL); - if (!call) { - _leave(" ENOMEM"); - return -ENOMEM; - } - - atomic_set(&call->usage, 1); - - init_waitqueue_head(&call->waitq); - spin_lock_init(&call->lock); - INIT_LIST_HEAD(&call->link); - INIT_LIST_HEAD(&call->acks_pendq); - INIT_LIST_HEAD(&call->rcv_receiveq); - INIT_LIST_HEAD(&call->rcv_krxiodq_lk); - INIT_LIST_HEAD(&call->app_readyq); - INIT_LIST_HEAD(&call->app_unreadyq); - INIT_LIST_HEAD(&call->app_link); - INIT_LIST_HEAD(&call->app_attn_link); - - init_timer(&call->acks_timeout); - call->acks_timeout.data = (unsigned long) call; - call->acks_timeout.function = __rxrpc_call_acks_timeout; - - init_timer(&call->rcv_timeout); - call->rcv_timeout.data = (unsigned long) call; - call->rcv_timeout.function = __rxrpc_call_rcv_timeout; - - init_timer(&call->ackr_dfr_timo); - call->ackr_dfr_timo.data = (unsigned long) call; - call->ackr_dfr_timo.function = __rxrpc_call_ackr_timeout; - - call->conn = conn; - call->ackr_win_bot = 1; - call->ackr_win_top = call->ackr_win_bot + RXRPC_CALL_ACK_WINDOW_SIZE - 1; - call->ackr_prev_seq = 0; - call->app_mark = RXRPC_APP_MARK_EOF; - call->app_attn_func = rxrpc_call_default_attn_func; - call->app_error_func = rxrpc_call_default_error_func; - call->app_aemap_func = rxrpc_call_default_aemap_func; - call->app_scr_alloc = call->app_scratch; - - call->cjif = jiffies; - - _leave(" = 0 (%p)", call); - - *_call = call; - - return 0; -} /* end __rxrpc_create_call() */ - -/*****************************************************************************/ -/* - * create a new call record for outgoing calls - */ -int rxrpc_create_call(struct rxrpc_connection *conn, - rxrpc_call_attn_func_t attn, - rxrpc_call_error_func_t error, - rxrpc_call_aemap_func_t aemap, - struct rxrpc_call **_call) -{ - DECLARE_WAITQUEUE(myself, current); - - struct rxrpc_call *call; - int ret, cix, loop; - - _enter("%p", conn); - - /* allocate and initialise a call record */ - ret = __rxrpc_create_call(conn, &call); - if (ret < 0) { - _leave(" = %d", ret); - return ret; - } - - call->app_call_state = RXRPC_CSTATE_CLNT_SND_ARGS; - if (attn) - call->app_attn_func = attn; - if (error) - call->app_error_func = error; - if (aemap) - call->app_aemap_func = aemap; - - _state(call); - - spin_lock(&conn->lock); - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&conn->chanwait, &myself); - - try_again: - /* try to find an unused channel */ - for (cix = 0; cix < 4; cix++) - if (!conn->channels[cix]) - goto obtained_chan; - - /* no free channels - wait for one to become available */ - ret = -EINTR; - if (signal_pending(current)) - goto error_unwait; - - spin_unlock(&conn->lock); - - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock(&conn->lock); - goto try_again; - - /* got a channel - now attach to the connection */ - obtained_chan: - remove_wait_queue(&conn->chanwait, &myself); - set_current_state(TASK_RUNNING); - - /* concoct a unique call number */ - next_callid: - call->call_id = htonl(++conn->call_counter); - for (loop = 0; loop < 4; loop++) - if (conn->channels[loop] && - conn->channels[loop]->call_id == call->call_id) - goto next_callid; - - rxrpc_get_connection(conn); - conn->channels[cix] = call; /* assign _after_ done callid check loop */ - do_gettimeofday(&conn->atime); - call->chan_ix = htonl(cix); - - spin_unlock(&conn->lock); - - down_write(&rxrpc_calls_sem); - list_add_tail(&call->call_link, &rxrpc_calls); - up_write(&rxrpc_calls_sem); - - __RXACCT(atomic_inc(&rxrpc_call_count)); - *_call = call; - - _leave(" = 0 (call=%p cix=%u)", call, cix); - return 0; - - error_unwait: - remove_wait_queue(&conn->chanwait, &myself); - set_current_state(TASK_RUNNING); - spin_unlock(&conn->lock); - - free_page((unsigned long) call); - _leave(" = %d", ret); - return ret; -} /* end rxrpc_create_call() */ - -/*****************************************************************************/ -/* - * create a new call record for incoming calls - */ -int rxrpc_incoming_call(struct rxrpc_connection *conn, - struct rxrpc_message *msg, - struct rxrpc_call **_call) -{ - struct rxrpc_call *call; - unsigned cix; - int ret; - - cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK; - - _enter("%p,%u,%u", conn, ntohl(msg->hdr.callNumber), cix); - - /* allocate and initialise a call record */ - ret = __rxrpc_create_call(conn, &call); - if (ret < 0) { - _leave(" = %d", ret); - return ret; - } - - call->pkt_rcv_count = 1; - call->app_call_state = RXRPC_CSTATE_SRVR_RCV_OPID; - call->app_mark = sizeof(uint32_t); - - _state(call); - - /* attach to the connection */ - ret = -EBUSY; - call->chan_ix = htonl(cix); - call->call_id = msg->hdr.callNumber; - - spin_lock(&conn->lock); - - if (!conn->channels[cix] || - conn->channels[cix]->app_call_state == RXRPC_CSTATE_COMPLETE || - conn->channels[cix]->app_call_state == RXRPC_CSTATE_ERROR - ) { - conn->channels[cix] = call; - rxrpc_get_connection(conn); - ret = 0; - } - - spin_unlock(&conn->lock); - - if (ret < 0) { - free_page((unsigned long) call); - call = NULL; - } - - if (ret == 0) { - down_write(&rxrpc_calls_sem); - list_add_tail(&call->call_link, &rxrpc_calls); - up_write(&rxrpc_calls_sem); - __RXACCT(atomic_inc(&rxrpc_call_count)); - *_call = call; - } - - _leave(" = %d [%p]", ret, call); - return ret; -} /* end rxrpc_incoming_call() */ - -/*****************************************************************************/ -/* - * free a call record - */ -void rxrpc_put_call(struct rxrpc_call *call) -{ - struct rxrpc_connection *conn = call->conn; - struct rxrpc_message *msg; - - _enter("%p{u=%d}",call,atomic_read(&call->usage)); - - /* sanity check */ - if (atomic_read(&call->usage) <= 0) - BUG(); - - /* to prevent a race, the decrement and the de-list must be effectively - * atomic */ - spin_lock(&conn->lock); - if (likely(!atomic_dec_and_test(&call->usage))) { - spin_unlock(&conn->lock); - _leave(""); - return; - } - - if (conn->channels[ntohl(call->chan_ix)] == call) - conn->channels[ntohl(call->chan_ix)] = NULL; - - spin_unlock(&conn->lock); - - wake_up(&conn->chanwait); - - rxrpc_put_connection(conn); - - /* clear the timers and dequeue from krxiod */ - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->rcv_timeout); - del_timer_sync(&call->ackr_dfr_timo); - - rxrpc_krxiod_dequeue_call(call); - - /* clean up the contents of the struct */ - if (call->snd_nextmsg) - rxrpc_put_message(call->snd_nextmsg); - - if (call->snd_ping) - rxrpc_put_message(call->snd_ping); - - while (!list_empty(&call->acks_pendq)) { - msg = list_entry(call->acks_pendq.next, - struct rxrpc_message, link); - list_del(&msg->link); - rxrpc_put_message(msg); - } - - while (!list_empty(&call->rcv_receiveq)) { - msg = list_entry(call->rcv_receiveq.next, - struct rxrpc_message, link); - list_del(&msg->link); - rxrpc_put_message(msg); - } - - while (!list_empty(&call->app_readyq)) { - msg = list_entry(call->app_readyq.next, - struct rxrpc_message, link); - list_del(&msg->link); - rxrpc_put_message(msg); - } - - while (!list_empty(&call->app_unreadyq)) { - msg = list_entry(call->app_unreadyq.next, - struct rxrpc_message, link); - list_del(&msg->link); - rxrpc_put_message(msg); - } - - module_put(call->owner); - - down_write(&rxrpc_calls_sem); - list_del(&call->call_link); - up_write(&rxrpc_calls_sem); - - __RXACCT(atomic_dec(&rxrpc_call_count)); - free_page((unsigned long) call); - - _leave(" [destroyed]"); -} /* end rxrpc_put_call() */ - -/*****************************************************************************/ -/* - * actually generate a normal ACK - */ -static inline int __rxrpc_call_gen_normal_ACK(struct rxrpc_call *call, - rxrpc_seq_t seq) -{ - struct rxrpc_message *msg; - struct kvec diov[3]; - __be32 aux[4]; - int delta, ret; - - /* ACKs default to DELAY */ - if (!call->ackr.reason) - call->ackr.reason = RXRPC_ACK_DELAY; - - _proto("Rx %05lu Sending ACK { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }", - jiffies - call->cjif, - ntohs(call->ackr.maxSkew), - ntohl(call->ackr.firstPacket), - ntohl(call->ackr.previousPacket), - ntohl(call->ackr.serial), - rxrpc_acks[call->ackr.reason], - call->ackr.nAcks); - - aux[0] = htonl(call->conn->peer->if_mtu); /* interface MTU */ - aux[1] = htonl(1444); /* max MTU */ - aux[2] = htonl(16); /* rwind */ - aux[3] = htonl(4); /* max packets */ - - diov[0].iov_len = sizeof(struct rxrpc_ackpacket); - diov[0].iov_base = &call->ackr; - diov[1].iov_len = call->ackr_pend_cnt + 3; - diov[1].iov_base = call->ackr_array; - diov[2].iov_len = sizeof(aux); - diov[2].iov_base = &aux; - - /* build and send the message */ - ret = rxrpc_conn_newmsg(call->conn,call, RXRPC_PACKET_TYPE_ACK, - 3, diov, GFP_KERNEL, &msg); - if (ret < 0) - goto out; - - msg->seq = seq; - msg->hdr.seq = htonl(seq); - msg->hdr.flags |= RXRPC_SLOW_START_OK; - - ret = rxrpc_conn_sendmsg(call->conn, msg); - rxrpc_put_message(msg); - if (ret < 0) - goto out; - call->pkt_snd_count++; - - /* count how many actual ACKs there were at the front */ - for (delta = 0; delta < call->ackr_pend_cnt; delta++) - if (call->ackr_array[delta] != RXRPC_ACK_TYPE_ACK) - break; - - call->ackr_pend_cnt -= delta; /* all ACK'd to this point */ - - /* crank the ACK window around */ - if (delta == 0) { - /* un-ACK'd window */ - } - else if (delta < RXRPC_CALL_ACK_WINDOW_SIZE) { - /* partially ACK'd window - * - shuffle down to avoid losing out-of-sequence packets - */ - call->ackr_win_bot += delta; - call->ackr_win_top += delta; - - memmove(&call->ackr_array[0], - &call->ackr_array[delta], - call->ackr_pend_cnt); - - memset(&call->ackr_array[call->ackr_pend_cnt], - RXRPC_ACK_TYPE_NACK, - sizeof(call->ackr_array) - call->ackr_pend_cnt); - } - else { - /* fully ACK'd window - * - just clear the whole thing - */ - memset(&call->ackr_array, - RXRPC_ACK_TYPE_NACK, - sizeof(call->ackr_array)); - } - - /* clear this ACK */ - memset(&call->ackr, 0, sizeof(call->ackr)); - - out: - if (!call->app_call_state) - printk("___ STATE 0 ___\n"); - return ret; -} /* end __rxrpc_call_gen_normal_ACK() */ - -/*****************************************************************************/ -/* - * note the reception of a packet in the call's ACK records and generate an - * appropriate ACK packet if necessary - * - returns 0 if packet should be processed, 1 if packet should be ignored - * and -ve on an error - */ -static int rxrpc_call_generate_ACK(struct rxrpc_call *call, - struct rxrpc_header *hdr, - struct rxrpc_ackpacket *ack) -{ - struct rxrpc_message *msg; - rxrpc_seq_t seq; - unsigned offset; - int ret = 0, err; - u8 special_ACK, do_ACK, force; - - _enter("%p,%p { seq=%d tp=%d fl=%02x }", - call, hdr, ntohl(hdr->seq), hdr->type, hdr->flags); - - seq = ntohl(hdr->seq); - offset = seq - call->ackr_win_bot; - do_ACK = RXRPC_ACK_DELAY; - special_ACK = 0; - force = (seq == 1); - - if (call->ackr_high_seq < seq) - call->ackr_high_seq = seq; - - /* deal with generation of obvious special ACKs first */ - if (ack && ack->reason == RXRPC_ACK_PING) { - special_ACK = RXRPC_ACK_PING_RESPONSE; - ret = 1; - goto gen_ACK; - } - - if (seq < call->ackr_win_bot) { - special_ACK = RXRPC_ACK_DUPLICATE; - ret = 1; - goto gen_ACK; - } - - if (seq >= call->ackr_win_top) { - special_ACK = RXRPC_ACK_EXCEEDS_WINDOW; - ret = 1; - goto gen_ACK; - } - - if (call->ackr_array[offset] != RXRPC_ACK_TYPE_NACK) { - special_ACK = RXRPC_ACK_DUPLICATE; - ret = 1; - goto gen_ACK; - } - - /* okay... it's a normal data packet inside the ACK window */ - call->ackr_array[offset] = RXRPC_ACK_TYPE_ACK; - - if (offset < call->ackr_pend_cnt) { - } - else if (offset > call->ackr_pend_cnt) { - do_ACK = RXRPC_ACK_OUT_OF_SEQUENCE; - call->ackr_pend_cnt = offset; - goto gen_ACK; - } - - if (hdr->flags & RXRPC_REQUEST_ACK) { - do_ACK = RXRPC_ACK_REQUESTED; - } - - /* generate an ACK on the final packet of a reply just received */ - if (hdr->flags & RXRPC_LAST_PACKET) { - if (call->conn->out_clientflag) - force = 1; - } - else if (!(hdr->flags & RXRPC_MORE_PACKETS)) { - do_ACK = RXRPC_ACK_REQUESTED; - } - - /* re-ACK packets previously received out-of-order */ - for (offset++; offset < RXRPC_CALL_ACK_WINDOW_SIZE; offset++) - if (call->ackr_array[offset] != RXRPC_ACK_TYPE_ACK) - break; - - call->ackr_pend_cnt = offset; - - /* generate an ACK if we fill up the window */ - if (call->ackr_pend_cnt >= RXRPC_CALL_ACK_WINDOW_SIZE) - force = 1; - - gen_ACK: - _debug("%05lu ACKs pend=%u norm=%s special=%s%s", - jiffies - call->cjif, - call->ackr_pend_cnt, - rxrpc_acks[do_ACK], - rxrpc_acks[special_ACK], - force ? " immediate" : - do_ACK == RXRPC_ACK_REQUESTED ? " merge-req" : - hdr->flags & RXRPC_LAST_PACKET ? " finalise" : - " defer" - ); - - /* send any pending normal ACKs if need be */ - if (call->ackr_pend_cnt > 0) { - /* fill out the appropriate form */ - call->ackr.bufferSpace = htons(RXRPC_CALL_ACK_WINDOW_SIZE); - call->ackr.maxSkew = htons(min(call->ackr_high_seq - seq, - 65535U)); - call->ackr.firstPacket = htonl(call->ackr_win_bot); - call->ackr.previousPacket = call->ackr_prev_seq; - call->ackr.serial = hdr->serial; - call->ackr.nAcks = call->ackr_pend_cnt; - - if (do_ACK == RXRPC_ACK_REQUESTED) - call->ackr.reason = do_ACK; - - /* generate the ACK immediately if necessary */ - if (special_ACK || force) { - err = __rxrpc_call_gen_normal_ACK( - call, do_ACK == RXRPC_ACK_DELAY ? 0 : seq); - if (err < 0) { - ret = err; - goto out; - } - } - } - - if (call->ackr.reason == RXRPC_ACK_REQUESTED) - call->ackr_dfr_seq = seq; - - /* start the ACK timer if not running if there are any pending deferred - * ACKs */ - if (call->ackr_pend_cnt > 0 && - call->ackr.reason != RXRPC_ACK_REQUESTED && - !timer_pending(&call->ackr_dfr_timo) - ) { - unsigned long timo; - - timo = rxrpc_call_dfr_ack_timeout + jiffies; - - _debug("START ACKR TIMER for cj=%lu", timo - call->cjif); - - spin_lock(&call->lock); - mod_timer(&call->ackr_dfr_timo, timo); - spin_unlock(&call->lock); - } - else if ((call->ackr_pend_cnt == 0 || - call->ackr.reason == RXRPC_ACK_REQUESTED) && - timer_pending(&call->ackr_dfr_timo) - ) { - /* stop timer if no pending ACKs */ - _debug("CLEAR ACKR TIMER"); - del_timer_sync(&call->ackr_dfr_timo); - } - - /* send a special ACK if one is required */ - if (special_ACK) { - struct rxrpc_ackpacket ack; - struct kvec diov[2]; - uint8_t acks[1] = { RXRPC_ACK_TYPE_ACK }; - - /* fill out the appropriate form */ - ack.bufferSpace = htons(RXRPC_CALL_ACK_WINDOW_SIZE); - ack.maxSkew = htons(min(call->ackr_high_seq - seq, - 65535U)); - ack.firstPacket = htonl(call->ackr_win_bot); - ack.previousPacket = call->ackr_prev_seq; - ack.serial = hdr->serial; - ack.reason = special_ACK; - ack.nAcks = 0; - - _proto("Rx Sending s-ACK" - " { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }", - ntohs(ack.maxSkew), - ntohl(ack.firstPacket), - ntohl(ack.previousPacket), - ntohl(ack.serial), - rxrpc_acks[ack.reason], - ack.nAcks); - - diov[0].iov_len = sizeof(struct rxrpc_ackpacket); - diov[0].iov_base = &ack; - diov[1].iov_len = sizeof(acks); - diov[1].iov_base = acks; - - /* build and send the message */ - err = rxrpc_conn_newmsg(call->conn,call, RXRPC_PACKET_TYPE_ACK, - hdr->seq ? 2 : 1, diov, - GFP_KERNEL, - &msg); - if (err < 0) { - ret = err; - goto out; - } - - msg->seq = seq; - msg->hdr.seq = htonl(seq); - msg->hdr.flags |= RXRPC_SLOW_START_OK; - - err = rxrpc_conn_sendmsg(call->conn, msg); - rxrpc_put_message(msg); - if (err < 0) { - ret = err; - goto out; - } - call->pkt_snd_count++; - } - - out: - if (hdr->seq) - call->ackr_prev_seq = hdr->seq; - - _leave(" = %d", ret); - return ret; -} /* end rxrpc_call_generate_ACK() */ - -/*****************************************************************************/ -/* - * handle work to be done on a call - * - includes packet reception and timeout processing - */ -void rxrpc_call_do_stuff(struct rxrpc_call *call) -{ - _enter("%p{flags=%lx}", call, call->flags); - - /* handle packet reception */ - if (call->flags & RXRPC_CALL_RCV_PKT) { - _debug("- receive packet"); - call->flags &= ~RXRPC_CALL_RCV_PKT; - rxrpc_call_receive_packet(call); - } - - /* handle overdue ACKs */ - if (call->flags & RXRPC_CALL_ACKS_TIMO) { - _debug("- overdue ACK timeout"); - call->flags &= ~RXRPC_CALL_ACKS_TIMO; - rxrpc_call_resend(call, call->snd_seq_count); - } - - /* handle lack of reception */ - if (call->flags & RXRPC_CALL_RCV_TIMO) { - _debug("- reception timeout"); - call->flags &= ~RXRPC_CALL_RCV_TIMO; - rxrpc_call_abort(call, -EIO); - } - - /* handle deferred ACKs */ - if (call->flags & RXRPC_CALL_ACKR_TIMO || - (call->ackr.nAcks > 0 && call->ackr.reason == RXRPC_ACK_REQUESTED) - ) { - _debug("- deferred ACK timeout: cj=%05lu r=%s n=%u", - jiffies - call->cjif, - rxrpc_acks[call->ackr.reason], - call->ackr.nAcks); - - call->flags &= ~RXRPC_CALL_ACKR_TIMO; - - if (call->ackr.nAcks > 0 && - call->app_call_state != RXRPC_CSTATE_ERROR) { - /* generate ACK */ - __rxrpc_call_gen_normal_ACK(call, call->ackr_dfr_seq); - call->ackr_dfr_seq = 0; - } - } - - _leave(""); - -} /* end rxrpc_call_do_stuff() */ - -/*****************************************************************************/ -/* - * send an abort message at call or connection level - * - must be called with call->lock held - * - the supplied error code is sent as the packet data - */ -static int __rxrpc_call_abort(struct rxrpc_call *call, int errno) -{ - struct rxrpc_connection *conn = call->conn; - struct rxrpc_message *msg; - struct kvec diov[1]; - int ret; - __be32 _error; - - _enter("%p{%08x},%p{%d},%d", - conn, ntohl(conn->conn_id), call, ntohl(call->call_id), errno); - - /* if this call is already aborted, then just wake up any waiters */ - if (call->app_call_state == RXRPC_CSTATE_ERROR) { - spin_unlock(&call->lock); - call->app_error_func(call); - _leave(" = 0"); - return 0; - } - - rxrpc_get_call(call); - - /* change the state _with_ the lock still held */ - call->app_call_state = RXRPC_CSTATE_ERROR; - call->app_err_state = RXRPC_ESTATE_LOCAL_ABORT; - call->app_errno = errno; - call->app_mark = RXRPC_APP_MARK_EOF; - call->app_read_buf = NULL; - call->app_async_read = 0; - - _state(call); - - /* ask the app to translate the error code */ - call->app_aemap_func(call); - - spin_unlock(&call->lock); - - /* flush any outstanding ACKs */ - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->rcv_timeout); - del_timer_sync(&call->ackr_dfr_timo); - - if (rxrpc_call_is_ack_pending(call)) - __rxrpc_call_gen_normal_ACK(call, 0); - - /* send the abort packet only if we actually traded some other - * packets */ - ret = 0; - if (call->pkt_snd_count || call->pkt_rcv_count) { - /* actually send the abort */ - _proto("Rx Sending Call ABORT { data=%d }", - call->app_abort_code); - - _error = htonl(call->app_abort_code); - - diov[0].iov_len = sizeof(_error); - diov[0].iov_base = &_error; - - ret = rxrpc_conn_newmsg(conn, call, RXRPC_PACKET_TYPE_ABORT, - 1, diov, GFP_KERNEL, &msg); - if (ret == 0) { - ret = rxrpc_conn_sendmsg(conn, msg); - rxrpc_put_message(msg); - } - } - - /* tell the app layer to let go */ - call->app_error_func(call); - - rxrpc_put_call(call); - - _leave(" = %d", ret); - return ret; -} /* end __rxrpc_call_abort() */ - -/*****************************************************************************/ -/* - * send an abort message at call or connection level - * - the supplied error code is sent as the packet data - */ -int rxrpc_call_abort(struct rxrpc_call *call, int error) -{ - spin_lock(&call->lock); - - return __rxrpc_call_abort(call, error); - -} /* end rxrpc_call_abort() */ - -/*****************************************************************************/ -/* - * process packets waiting for this call - */ -static void rxrpc_call_receive_packet(struct rxrpc_call *call) -{ - struct rxrpc_message *msg; - struct list_head *_p; - - _enter("%p", call); - - rxrpc_get_call(call); /* must not go away too soon if aborted by - * app-layer */ - - while (!list_empty(&call->rcv_receiveq)) { - /* try to get next packet */ - _p = NULL; - spin_lock(&call->lock); - if (!list_empty(&call->rcv_receiveq)) { - _p = call->rcv_receiveq.next; - list_del_init(_p); - } - spin_unlock(&call->lock); - - if (!_p) - break; - - msg = list_entry(_p, struct rxrpc_message, link); - - _proto("Rx %05lu Received %s packet (%%%u,#%u,%c%c%c%c%c)", - jiffies - call->cjif, - rxrpc_pkts[msg->hdr.type], - ntohl(msg->hdr.serial), - msg->seq, - msg->hdr.flags & RXRPC_JUMBO_PACKET ? 'j' : '-', - msg->hdr.flags & RXRPC_MORE_PACKETS ? 'm' : '-', - msg->hdr.flags & RXRPC_LAST_PACKET ? 'l' : '-', - msg->hdr.flags & RXRPC_REQUEST_ACK ? 'r' : '-', - msg->hdr.flags & RXRPC_CLIENT_INITIATED ? 'C' : 'S' - ); - - switch (msg->hdr.type) { - /* deal with data packets */ - case RXRPC_PACKET_TYPE_DATA: - /* ACK the packet if necessary */ - switch (rxrpc_call_generate_ACK(call, &msg->hdr, - NULL)) { - case 0: /* useful packet */ - rxrpc_call_receive_data_packet(call, msg); - break; - case 1: /* duplicate or out-of-window packet */ - break; - default: - rxrpc_put_message(msg); - goto out; - } - break; - - /* deal with ACK packets */ - case RXRPC_PACKET_TYPE_ACK: - rxrpc_call_receive_ack_packet(call, msg); - break; - - /* deal with abort packets */ - case RXRPC_PACKET_TYPE_ABORT: { - __be32 _dbuf, *dp; - - dp = skb_header_pointer(msg->pkt, msg->offset, - sizeof(_dbuf), &_dbuf); - if (dp == NULL) - printk("Rx Received short ABORT packet\n"); - - _proto("Rx Received Call ABORT { data=%d }", - (dp ? ntohl(*dp) : 0)); - - spin_lock(&call->lock); - call->app_call_state = RXRPC_CSTATE_ERROR; - call->app_err_state = RXRPC_ESTATE_PEER_ABORT; - call->app_abort_code = (dp ? ntohl(*dp) : 0); - call->app_errno = -ECONNABORTED; - call->app_mark = RXRPC_APP_MARK_EOF; - call->app_read_buf = NULL; - call->app_async_read = 0; - - /* ask the app to translate the error code */ - call->app_aemap_func(call); - _state(call); - spin_unlock(&call->lock); - call->app_error_func(call); - break; - } - default: - /* deal with other packet types */ - _proto("Rx Unsupported packet type %u (#%u)", - msg->hdr.type, msg->seq); - break; - } - - rxrpc_put_message(msg); - } - - out: - rxrpc_put_call(call); - _leave(""); -} /* end rxrpc_call_receive_packet() */ - -/*****************************************************************************/ -/* - * process next data packet - * - as the next data packet arrives: - * - it is queued on app_readyq _if_ it is the next one expected - * (app_ready_seq+1) - * - it is queued on app_unreadyq _if_ it is not the next one expected - * - if a packet placed on app_readyq completely fills a hole leading up to - * the first packet on app_unreadyq, then packets now in sequence are - * tranferred to app_readyq - * - the application layer can only see packets on app_readyq - * (app_ready_qty bytes) - * - the application layer is prodded every time a new packet arrives - */ -static void rxrpc_call_receive_data_packet(struct rxrpc_call *call, - struct rxrpc_message *msg) -{ - const struct rxrpc_operation *optbl, *op; - struct rxrpc_message *pmsg; - struct list_head *_p; - int ret, lo, hi, rmtimo; - __be32 opid; - - _enter("%p{%u},%p{%u}", call, ntohl(call->call_id), msg, msg->seq); - - rxrpc_get_message(msg); - - /* add to the unready queue if we'd have to create a hole in the ready - * queue otherwise */ - if (msg->seq != call->app_ready_seq + 1) { - _debug("Call add packet %d to unreadyq", msg->seq); - - /* insert in seq order */ - list_for_each(_p, &call->app_unreadyq) { - pmsg = list_entry(_p, struct rxrpc_message, link); - if (pmsg->seq > msg->seq) - break; - } - - list_add_tail(&msg->link, _p); - - _leave(" [unreadyq]"); - return; - } - - /* next in sequence - simply append into the call's ready queue */ - _debug("Call add packet %d to readyq (+%Zd => %Zd bytes)", - msg->seq, msg->dsize, call->app_ready_qty); - - spin_lock(&call->lock); - call->app_ready_seq = msg->seq; - call->app_ready_qty += msg->dsize; - list_add_tail(&msg->link, &call->app_readyq); - - /* move unready packets to the readyq if we got rid of a hole */ - while (!list_empty(&call->app_unreadyq)) { - pmsg = list_entry(call->app_unreadyq.next, - struct rxrpc_message, link); - - if (pmsg->seq != call->app_ready_seq + 1) - break; - - /* next in sequence - just move list-to-list */ - _debug("Call transfer packet %d to readyq (+%Zd => %Zd bytes)", - pmsg->seq, pmsg->dsize, call->app_ready_qty); - - call->app_ready_seq = pmsg->seq; - call->app_ready_qty += pmsg->dsize; - list_move_tail(&pmsg->link, &call->app_readyq); - } - - /* see if we've got the last packet yet */ - if (!list_empty(&call->app_readyq)) { - pmsg = list_entry(call->app_readyq.prev, - struct rxrpc_message, link); - if (pmsg->hdr.flags & RXRPC_LAST_PACKET) { - call->app_last_rcv = 1; - _debug("Last packet on readyq"); - } - } - - switch (call->app_call_state) { - /* do nothing if call already aborted */ - case RXRPC_CSTATE_ERROR: - spin_unlock(&call->lock); - _leave(" [error]"); - return; - - /* extract the operation ID from an incoming call if that's not - * yet been done */ - case RXRPC_CSTATE_SRVR_RCV_OPID: - spin_unlock(&call->lock); - - /* handle as yet insufficient data for the operation ID */ - if (call->app_ready_qty < 4) { - if (call->app_last_rcv) - /* trouble - last packet seen */ - rxrpc_call_abort(call, -EINVAL); - - _leave(""); - return; - } - - /* pull the operation ID out of the buffer */ - ret = rxrpc_call_read_data(call, &opid, sizeof(opid), 0); - if (ret < 0) { - printk("Unexpected error from read-data: %d\n", ret); - if (call->app_call_state != RXRPC_CSTATE_ERROR) - rxrpc_call_abort(call, ret); - _leave(""); - return; - } - call->app_opcode = ntohl(opid); - - /* locate the operation in the available ops table */ - optbl = call->conn->service->ops_begin; - lo = 0; - hi = call->conn->service->ops_end - optbl; - - while (lo < hi) { - int mid = (hi + lo) / 2; - op = &optbl[mid]; - if (call->app_opcode == op->id) - goto found_op; - if (call->app_opcode > op->id) - lo = mid + 1; - else - hi = mid; - } - - /* search failed */ - kproto("Rx Client requested operation %d from %s service", - call->app_opcode, call->conn->service->name); - rxrpc_call_abort(call, -EINVAL); - _leave(" [inval]"); - return; - - found_op: - _proto("Rx Client requested operation %s from %s service", - op->name, call->conn->service->name); - - /* we're now waiting for the argument block (unless the call - * was aborted) */ - spin_lock(&call->lock); - if (call->app_call_state == RXRPC_CSTATE_SRVR_RCV_OPID || - call->app_call_state == RXRPC_CSTATE_SRVR_SND_REPLY) { - if (!call->app_last_rcv) - call->app_call_state = - RXRPC_CSTATE_SRVR_RCV_ARGS; - else if (call->app_ready_qty > 0) - call->app_call_state = - RXRPC_CSTATE_SRVR_GOT_ARGS; - else - call->app_call_state = - RXRPC_CSTATE_SRVR_SND_REPLY; - call->app_mark = op->asize; - call->app_user = op->user; - } - spin_unlock(&call->lock); - - _state(call); - break; - - case RXRPC_CSTATE_SRVR_RCV_ARGS: - /* change state if just received last packet of arg block */ - if (call->app_last_rcv) - call->app_call_state = RXRPC_CSTATE_SRVR_GOT_ARGS; - spin_unlock(&call->lock); - - _state(call); - break; - - case RXRPC_CSTATE_CLNT_RCV_REPLY: - /* change state if just received last packet of reply block */ - rmtimo = 0; - if (call->app_last_rcv) { - call->app_call_state = RXRPC_CSTATE_CLNT_GOT_REPLY; - rmtimo = 1; - } - spin_unlock(&call->lock); - - if (rmtimo) { - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->rcv_timeout); - del_timer_sync(&call->ackr_dfr_timo); - } - - _state(call); - break; - - default: - /* deal with data reception in an unexpected state */ - printk("Unexpected state [[[ %u ]]]\n", call->app_call_state); - __rxrpc_call_abort(call, -EBADMSG); - _leave(""); - return; - } - - if (call->app_call_state == RXRPC_CSTATE_CLNT_RCV_REPLY && - call->app_last_rcv) - BUG(); - - /* otherwise just invoke the data function whenever we can satisfy its desire for more - * data - */ - _proto("Rx Received Op Data: st=%u qty=%Zu mk=%Zu%s", - call->app_call_state, call->app_ready_qty, call->app_mark, - call->app_last_rcv ? " last-rcvd" : ""); - - spin_lock(&call->lock); - - ret = __rxrpc_call_read_data(call); - switch (ret) { - case 0: - spin_unlock(&call->lock); - call->app_attn_func(call); - break; - case -EAGAIN: - spin_unlock(&call->lock); - break; - case -ECONNABORTED: - spin_unlock(&call->lock); - break; - default: - __rxrpc_call_abort(call, ret); - break; - } - - _state(call); - - _leave(""); - -} /* end rxrpc_call_receive_data_packet() */ - -/*****************************************************************************/ -/* - * received an ACK packet - */ -static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call, - struct rxrpc_message *msg) -{ - struct rxrpc_ackpacket _ack, *ap; - rxrpc_serial_net_t serial; - rxrpc_seq_t seq; - int ret; - - _enter("%p{%u},%p{%u}", call, ntohl(call->call_id), msg, msg->seq); - - /* extract the basic ACK record */ - ap = skb_header_pointer(msg->pkt, msg->offset, sizeof(_ack), &_ack); - if (ap == NULL) { - printk("Rx Received short ACK packet\n"); - return; - } - msg->offset += sizeof(_ack); - - serial = ap->serial; - seq = ntohl(ap->firstPacket); - - _proto("Rx Received ACK %%%d { b=%hu m=%hu f=%u p=%u s=%u r=%s n=%u }", - ntohl(msg->hdr.serial), - ntohs(ap->bufferSpace), - ntohs(ap->maxSkew), - seq, - ntohl(ap->previousPacket), - ntohl(serial), - rxrpc_acks[ap->reason], - call->ackr.nAcks - ); - - /* check the other side isn't ACK'ing a sequence number I haven't sent - * yet */ - if (ap->nAcks > 0 && - (seq > call->snd_seq_count || - seq + ap->nAcks - 1 > call->snd_seq_count)) { - printk("Received ACK (#%u-#%u) for unsent packet\n", - seq, seq + ap->nAcks - 1); - rxrpc_call_abort(call, -EINVAL); - _leave(""); - return; - } - - /* deal with RTT calculation */ - if (serial) { - struct rxrpc_message *rttmsg; - - /* find the prompting packet */ - spin_lock(&call->lock); - if (call->snd_ping && call->snd_ping->hdr.serial == serial) { - /* it was a ping packet */ - rttmsg = call->snd_ping; - call->snd_ping = NULL; - spin_unlock(&call->lock); - - if (rttmsg) { - rttmsg->rttdone = 1; - rxrpc_peer_calculate_rtt(call->conn->peer, - rttmsg, msg); - rxrpc_put_message(rttmsg); - } - } - else { - struct list_head *_p; - - /* it ought to be a data packet - look in the pending - * ACK list */ - list_for_each(_p, &call->acks_pendq) { - rttmsg = list_entry(_p, struct rxrpc_message, - link); - if (rttmsg->hdr.serial == serial) { - if (rttmsg->rttdone) - /* never do RTT twice without - * resending */ - break; - - rttmsg->rttdone = 1; - rxrpc_peer_calculate_rtt( - call->conn->peer, rttmsg, msg); - break; - } - } - spin_unlock(&call->lock); - } - } - - switch (ap->reason) { - /* deal with negative/positive acknowledgement of data - * packets */ - case RXRPC_ACK_REQUESTED: - case RXRPC_ACK_DELAY: - case RXRPC_ACK_IDLE: - rxrpc_call_definitively_ACK(call, seq - 1); - - case RXRPC_ACK_DUPLICATE: - case RXRPC_ACK_OUT_OF_SEQUENCE: - case RXRPC_ACK_EXCEEDS_WINDOW: - call->snd_resend_cnt = 0; - ret = rxrpc_call_record_ACK(call, msg, seq, ap->nAcks); - if (ret < 0) - rxrpc_call_abort(call, ret); - break; - - /* respond to ping packets immediately */ - case RXRPC_ACK_PING: - rxrpc_call_generate_ACK(call, &msg->hdr, ap); - break; - - /* only record RTT on ping response packets */ - case RXRPC_ACK_PING_RESPONSE: - if (call->snd_ping) { - struct rxrpc_message *rttmsg; - - /* only do RTT stuff if the response matches the - * retained ping */ - rttmsg = NULL; - spin_lock(&call->lock); - if (call->snd_ping && - call->snd_ping->hdr.serial == ap->serial) { - rttmsg = call->snd_ping; - call->snd_ping = NULL; - } - spin_unlock(&call->lock); - - if (rttmsg) { - rttmsg->rttdone = 1; - rxrpc_peer_calculate_rtt(call->conn->peer, - rttmsg, msg); - rxrpc_put_message(rttmsg); - } - } - break; - - default: - printk("Unsupported ACK reason %u\n", ap->reason); - break; - } - - _leave(""); -} /* end rxrpc_call_receive_ack_packet() */ - -/*****************************************************************************/ -/* - * record definitive ACKs for all messages up to and including the one with the - * 'highest' seq - */ -static void rxrpc_call_definitively_ACK(struct rxrpc_call *call, - rxrpc_seq_t highest) -{ - struct rxrpc_message *msg; - int now_complete; - - _enter("%p{ads=%u},%u", call, call->acks_dftv_seq, highest); - - while (call->acks_dftv_seq < highest) { - call->acks_dftv_seq++; - - _proto("Definitive ACK on packet #%u", call->acks_dftv_seq); - - /* discard those at front of queue until message with highest - * ACK is found */ - spin_lock(&call->lock); - msg = NULL; - if (!list_empty(&call->acks_pendq)) { - msg = list_entry(call->acks_pendq.next, - struct rxrpc_message, link); - list_del_init(&msg->link); /* dequeue */ - if (msg->state == RXRPC_MSG_SENT) - call->acks_pend_cnt--; - } - spin_unlock(&call->lock); - - /* insanity check */ - if (!msg) - panic("%s(): acks_pendq unexpectedly empty\n", - __FUNCTION__); - - if (msg->seq != call->acks_dftv_seq) - panic("%s(): Packet #%u expected at front of acks_pendq" - " (#%u found)\n", - __FUNCTION__, call->acks_dftv_seq, msg->seq); - - /* discard the message */ - msg->state = RXRPC_MSG_DONE; - rxrpc_put_message(msg); - } - - /* if all sent packets are definitively ACK'd then prod any sleepers just in case */ - now_complete = 0; - spin_lock(&call->lock); - if (call->acks_dftv_seq == call->snd_seq_count) { - if (call->app_call_state != RXRPC_CSTATE_COMPLETE) { - call->app_call_state = RXRPC_CSTATE_COMPLETE; - _state(call); - now_complete = 1; - } - } - spin_unlock(&call->lock); - - if (now_complete) { - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->rcv_timeout); - del_timer_sync(&call->ackr_dfr_timo); - call->app_attn_func(call); - } - - _leave(""); -} /* end rxrpc_call_definitively_ACK() */ - -/*****************************************************************************/ -/* - * record the specified amount of ACKs/NAKs - */ -static int rxrpc_call_record_ACK(struct rxrpc_call *call, - struct rxrpc_message *msg, - rxrpc_seq_t seq, - size_t count) -{ - struct rxrpc_message *dmsg; - struct list_head *_p; - rxrpc_seq_t highest; - unsigned ix; - size_t chunk; - char resend, now_complete; - u8 acks[16]; - - _enter("%p{apc=%u ads=%u},%p,%u,%Zu", - call, call->acks_pend_cnt, call->acks_dftv_seq, - msg, seq, count); - - /* handle re-ACK'ing of definitively ACK'd packets (may be out-of-order - * ACKs) */ - if (seq <= call->acks_dftv_seq) { - unsigned delta = call->acks_dftv_seq - seq; - - if (count <= delta) { - _leave(" = 0 [all definitively ACK'd]"); - return 0; - } - - seq += delta; - count -= delta; - msg->offset += delta; - } - - highest = seq + count - 1; - resend = 0; - while (count > 0) { - /* extract up to 16 ACK slots at a time */ - chunk = min(count, sizeof(acks)); - count -= chunk; - - memset(acks, 2, sizeof(acks)); - - if (skb_copy_bits(msg->pkt, msg->offset, &acks, chunk) < 0) { - printk("Rx Received short ACK packet\n"); - _leave(" = -EINVAL"); - return -EINVAL; - } - msg->offset += chunk; - - /* check that the ACK set is valid */ - for (ix = 0; ix < chunk; ix++) { - switch (acks[ix]) { - case RXRPC_ACK_TYPE_ACK: - break; - case RXRPC_ACK_TYPE_NACK: - resend = 1; - break; - default: - printk("Rx Received unsupported ACK state" - " %u\n", acks[ix]); - _leave(" = -EINVAL"); - return -EINVAL; - } - } - - _proto("Rx ACK of packets #%u-#%u " - "[%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c] (pend=%u)", - seq, (unsigned) (seq + chunk - 1), - _acktype[acks[0x0]], - _acktype[acks[0x1]], - _acktype[acks[0x2]], - _acktype[acks[0x3]], - _acktype[acks[0x4]], - _acktype[acks[0x5]], - _acktype[acks[0x6]], - _acktype[acks[0x7]], - _acktype[acks[0x8]], - _acktype[acks[0x9]], - _acktype[acks[0xA]], - _acktype[acks[0xB]], - _acktype[acks[0xC]], - _acktype[acks[0xD]], - _acktype[acks[0xE]], - _acktype[acks[0xF]], - call->acks_pend_cnt - ); - - /* mark the packets in the ACK queue as being provisionally - * ACK'd */ - ix = 0; - spin_lock(&call->lock); - - /* find the first packet ACK'd/NAK'd here */ - list_for_each(_p, &call->acks_pendq) { - dmsg = list_entry(_p, struct rxrpc_message, link); - if (dmsg->seq == seq) - goto found_first; - _debug("- %u: skipping #%u", ix, dmsg->seq); - } - goto bad_queue; - - found_first: - do { - _debug("- %u: processing #%u (%c) apc=%u", - ix, dmsg->seq, _acktype[acks[ix]], - call->acks_pend_cnt); - - if (acks[ix] == RXRPC_ACK_TYPE_ACK) { - if (dmsg->state == RXRPC_MSG_SENT) - call->acks_pend_cnt--; - dmsg->state = RXRPC_MSG_ACKED; - } - else { - if (dmsg->state == RXRPC_MSG_ACKED) - call->acks_pend_cnt++; - dmsg->state = RXRPC_MSG_SENT; - } - ix++; - seq++; - - _p = dmsg->link.next; - dmsg = list_entry(_p, struct rxrpc_message, link); - } while(ix < chunk && - _p != &call->acks_pendq && - dmsg->seq == seq); - - if (ix < chunk) - goto bad_queue; - - spin_unlock(&call->lock); - } - - if (resend) - rxrpc_call_resend(call, highest); - - /* if all packets are provisionally ACK'd, then wake up anyone who's - * waiting for that */ - now_complete = 0; - spin_lock(&call->lock); - if (call->acks_pend_cnt == 0) { - if (call->app_call_state == RXRPC_CSTATE_SRVR_RCV_FINAL_ACK) { - call->app_call_state = RXRPC_CSTATE_COMPLETE; - _state(call); - } - now_complete = 1; - } - spin_unlock(&call->lock); - - if (now_complete) { - _debug("- wake up waiters"); - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->rcv_timeout); - del_timer_sync(&call->ackr_dfr_timo); - call->app_attn_func(call); - } - - _leave(" = 0 (apc=%u)", call->acks_pend_cnt); - return 0; - - bad_queue: - panic("%s(): acks_pendq in bad state (packet #%u absent)\n", - __FUNCTION__, seq); - -} /* end rxrpc_call_record_ACK() */ - -/*****************************************************************************/ -/* - * transfer data from the ready packet queue to the asynchronous read buffer - * - since this func is the only one going to look at packets queued on - * app_readyq, we don't need a lock to modify or access them, only to modify - * the queue pointers - * - called with call->lock held - * - the buffer must be in kernel space - * - returns: - * 0 if buffer filled - * -EAGAIN if buffer not filled and more data to come - * -EBADMSG if last packet received and insufficient data left - * -ECONNABORTED if the call has in an error state - */ -static int __rxrpc_call_read_data(struct rxrpc_call *call) -{ - struct rxrpc_message *msg; - size_t qty; - int ret; - - _enter("%p{as=%d buf=%p qty=%Zu/%Zu}", - call, - call->app_async_read, call->app_read_buf, - call->app_ready_qty, call->app_mark); - - /* check the state */ - switch (call->app_call_state) { - case RXRPC_CSTATE_SRVR_RCV_ARGS: - case RXRPC_CSTATE_CLNT_RCV_REPLY: - if (call->app_last_rcv) { - printk("%s(%p,%p,%Zd):" - " Inconsistent call state (%s, last pkt)", - __FUNCTION__, - call, call->app_read_buf, call->app_mark, - rxrpc_call_states[call->app_call_state]); - BUG(); - } - break; - - case RXRPC_CSTATE_SRVR_RCV_OPID: - case RXRPC_CSTATE_SRVR_GOT_ARGS: - case RXRPC_CSTATE_CLNT_GOT_REPLY: - break; - - case RXRPC_CSTATE_SRVR_SND_REPLY: - if (!call->app_last_rcv) { - printk("%s(%p,%p,%Zd):" - " Inconsistent call state (%s, not last pkt)", - __FUNCTION__, - call, call->app_read_buf, call->app_mark, - rxrpc_call_states[call->app_call_state]); - BUG(); - } - _debug("Trying to read data from call in SND_REPLY state"); - break; - - case RXRPC_CSTATE_ERROR: - _leave(" = -ECONNABORTED"); - return -ECONNABORTED; - - default: - printk("reading in unexpected state [[[ %u ]]]\n", - call->app_call_state); - BUG(); - } - - /* handle the case of not having an async buffer */ - if (!call->app_async_read) { - if (call->app_mark == RXRPC_APP_MARK_EOF) { - ret = call->app_last_rcv ? 0 : -EAGAIN; - } - else { - if (call->app_mark >= call->app_ready_qty) { - call->app_mark = RXRPC_APP_MARK_EOF; - ret = 0; - } - else { - ret = call->app_last_rcv ? -EBADMSG : -EAGAIN; - } - } - - _leave(" = %d [no buf]", ret); - return 0; - } - - while (!list_empty(&call->app_readyq) && call->app_mark > 0) { - msg = list_entry(call->app_readyq.next, - struct rxrpc_message, link); - - /* drag as much data as we need out of this packet */ - qty = min(call->app_mark, msg->dsize); - - _debug("reading %Zu from skb=%p off=%lu", - qty, msg->pkt, msg->offset); - - if (call->app_read_buf) - if (skb_copy_bits(msg->pkt, msg->offset, - call->app_read_buf, qty) < 0) - panic("%s: Failed to copy data from packet:" - " (%p,%p,%Zd)", - __FUNCTION__, - call, call->app_read_buf, qty); - - /* if that packet is now empty, discard it */ - call->app_ready_qty -= qty; - msg->dsize -= qty; - - if (msg->dsize == 0) { - list_del_init(&msg->link); - rxrpc_put_message(msg); - } - else { - msg->offset += qty; - } - - call->app_mark -= qty; - if (call->app_read_buf) - call->app_read_buf += qty; - } - - if (call->app_mark == 0) { - call->app_async_read = 0; - call->app_mark = RXRPC_APP_MARK_EOF; - call->app_read_buf = NULL; - - /* adjust the state if used up all packets */ - if (list_empty(&call->app_readyq) && call->app_last_rcv) { - switch (call->app_call_state) { - case RXRPC_CSTATE_SRVR_RCV_OPID: - call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY; - call->app_mark = RXRPC_APP_MARK_EOF; - _state(call); - del_timer_sync(&call->rcv_timeout); - break; - case RXRPC_CSTATE_SRVR_GOT_ARGS: - call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY; - _state(call); - del_timer_sync(&call->rcv_timeout); - break; - default: - call->app_call_state = RXRPC_CSTATE_COMPLETE; - _state(call); - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->ackr_dfr_timo); - del_timer_sync(&call->rcv_timeout); - break; - } - } - - _leave(" = 0"); - return 0; - } - - if (call->app_last_rcv) { - _debug("Insufficient data (%Zu/%Zu)", - call->app_ready_qty, call->app_mark); - call->app_async_read = 0; - call->app_mark = RXRPC_APP_MARK_EOF; - call->app_read_buf = NULL; - - _leave(" = -EBADMSG"); - return -EBADMSG; - } - - _leave(" = -EAGAIN"); - return -EAGAIN; -} /* end __rxrpc_call_read_data() */ - -/*****************************************************************************/ -/* - * attempt to read the specified amount of data from the call's ready queue - * into the buffer provided - * - since this func is the only one going to look at packets queued on - * app_readyq, we don't need a lock to modify or access them, only to modify - * the queue pointers - * - if the buffer pointer is NULL, then data is merely drained, not copied - * - if flags&RXRPC_CALL_READ_BLOCK, then the function will wait until there is - * enough data or an error will be generated - * - note that the caller must have added the calling task to the call's wait - * queue beforehand - * - if flags&RXRPC_CALL_READ_ALL, then an error will be generated if this - * function doesn't read all available data - */ -int rxrpc_call_read_data(struct rxrpc_call *call, - void *buffer, size_t size, int flags) -{ - int ret; - - _enter("%p{arq=%Zu},%p,%Zd,%x", - call, call->app_ready_qty, buffer, size, flags); - - spin_lock(&call->lock); - - if (unlikely(!!call->app_read_buf)) { - spin_unlock(&call->lock); - _leave(" = -EBUSY"); - return -EBUSY; - } - - call->app_mark = size; - call->app_read_buf = buffer; - call->app_async_read = 1; - call->app_read_count++; - - /* read as much data as possible */ - ret = __rxrpc_call_read_data(call); - switch (ret) { - case 0: - if (flags & RXRPC_CALL_READ_ALL && - (!call->app_last_rcv || call->app_ready_qty > 0)) { - _leave(" = -EBADMSG"); - __rxrpc_call_abort(call, -EBADMSG); - return -EBADMSG; - } - - spin_unlock(&call->lock); - call->app_attn_func(call); - _leave(" = 0"); - return ret; - - case -ECONNABORTED: - spin_unlock(&call->lock); - _leave(" = %d [aborted]", ret); - return ret; - - default: - __rxrpc_call_abort(call, ret); - _leave(" = %d", ret); - return ret; - - case -EAGAIN: - spin_unlock(&call->lock); - - if (!(flags & RXRPC_CALL_READ_BLOCK)) { - _leave(" = -EAGAIN"); - return -EAGAIN; - } - - /* wait for the data to arrive */ - _debug("blocking for data arrival"); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (!call->app_async_read || signal_pending(current)) - break; - schedule(); - } - set_current_state(TASK_RUNNING); - - if (signal_pending(current)) { - _leave(" = -EINTR"); - return -EINTR; - } - - if (call->app_call_state == RXRPC_CSTATE_ERROR) { - _leave(" = -ECONNABORTED"); - return -ECONNABORTED; - } - - _leave(" = 0"); - return 0; - } - -} /* end rxrpc_call_read_data() */ - -/*****************************************************************************/ -/* - * write data to a call - * - the data may not be sent immediately if it doesn't fill a buffer - * - if we can't queue all the data for buffering now, siov[] will have been - * adjusted to take account of what has been sent - */ -int rxrpc_call_write_data(struct rxrpc_call *call, - size_t sioc, - struct kvec *siov, - u8 rxhdr_flags, - gfp_t alloc_flags, - int dup_data, - size_t *size_sent) -{ - struct rxrpc_message *msg; - struct kvec *sptr; - size_t space, size, chunk, tmp; - char *buf; - int ret; - - _enter("%p,%Zu,%p,%02x,%x,%d,%p", - call, sioc, siov, rxhdr_flags, alloc_flags, dup_data, - size_sent); - - *size_sent = 0; - size = 0; - ret = -EINVAL; - - /* can't send more if we've sent last packet from this end */ - switch (call->app_call_state) { - case RXRPC_CSTATE_SRVR_SND_REPLY: - case RXRPC_CSTATE_CLNT_SND_ARGS: - break; - case RXRPC_CSTATE_ERROR: - ret = call->app_errno; - default: - goto out; - } - - /* calculate how much data we've been given */ - sptr = siov; - for (; sioc > 0; sptr++, sioc--) { - if (!sptr->iov_len) - continue; - - if (!sptr->iov_base) - goto out; - - size += sptr->iov_len; - } - - _debug("- size=%Zu mtu=%Zu", size, call->conn->mtu_size); - - do { - /* make sure there's a message under construction */ - if (!call->snd_nextmsg) { - /* no - allocate a message with no data yet attached */ - ret = rxrpc_conn_newmsg(call->conn, call, - RXRPC_PACKET_TYPE_DATA, - 0, NULL, alloc_flags, - &call->snd_nextmsg); - if (ret < 0) - goto out; - _debug("- allocated new message [ds=%Zu]", - call->snd_nextmsg->dsize); - } - - msg = call->snd_nextmsg; - msg->hdr.flags |= rxhdr_flags; - - /* deal with zero-length terminal packet */ - if (size == 0) { - if (rxhdr_flags & RXRPC_LAST_PACKET) { - ret = rxrpc_call_flush(call); - if (ret < 0) - goto out; - } - break; - } - - /* work out how much space current packet has available */ - space = call->conn->mtu_size - msg->dsize; - chunk = min(space, size); - - _debug("- [before] space=%Zu chunk=%Zu", space, chunk); - - while (!siov->iov_len) - siov++; - - /* if we are going to have to duplicate the data then coalesce - * it too */ - if (dup_data) { - /* don't allocate more that 1 page at a time */ - if (chunk > PAGE_SIZE) - chunk = PAGE_SIZE; - - /* allocate a data buffer and attach to the message */ - buf = kmalloc(chunk, alloc_flags); - if (unlikely(!buf)) { - if (msg->dsize == - sizeof(struct rxrpc_header)) { - /* discard an empty msg and wind back - * the seq counter */ - rxrpc_put_message(msg); - call->snd_nextmsg = NULL; - call->snd_seq_count--; - } - - ret = -ENOMEM; - goto out; - } - - tmp = msg->dcount++; - set_bit(tmp, &msg->dfree); - msg->data[tmp].iov_base = buf; - msg->data[tmp].iov_len = chunk; - msg->dsize += chunk; - *size_sent += chunk; - size -= chunk; - - /* load the buffer with data */ - while (chunk > 0) { - tmp = min(chunk, siov->iov_len); - memcpy(buf, siov->iov_base, tmp); - buf += tmp; - siov->iov_base += tmp; - siov->iov_len -= tmp; - if (!siov->iov_len) - siov++; - chunk -= tmp; - } - } - else { - /* we want to attach the supplied buffers directly */ - while (chunk > 0 && - msg->dcount < RXRPC_MSG_MAX_IOCS) { - tmp = msg->dcount++; - msg->data[tmp].iov_base = siov->iov_base; - msg->data[tmp].iov_len = siov->iov_len; - msg->dsize += siov->iov_len; - *size_sent += siov->iov_len; - size -= siov->iov_len; - chunk -= siov->iov_len; - siov++; - } - } - - _debug("- [loaded] chunk=%Zu size=%Zu", chunk, size); - - /* dispatch the message when full, final or requesting ACK */ - if (msg->dsize >= call->conn->mtu_size || rxhdr_flags) { - ret = rxrpc_call_flush(call); - if (ret < 0) - goto out; - } - - } while(size > 0); - - ret = 0; - out: - _leave(" = %d (%Zd queued, %Zd rem)", ret, *size_sent, size); - return ret; - -} /* end rxrpc_call_write_data() */ - -/*****************************************************************************/ -/* - * flush outstanding packets to the network - */ -static int rxrpc_call_flush(struct rxrpc_call *call) -{ - struct rxrpc_message *msg; - int ret = 0; - - _enter("%p", call); - - rxrpc_get_call(call); - - /* if there's a packet under construction, then dispatch it now */ - if (call->snd_nextmsg) { - msg = call->snd_nextmsg; - call->snd_nextmsg = NULL; - - if (msg->hdr.flags & RXRPC_LAST_PACKET) { - msg->hdr.flags &= ~RXRPC_MORE_PACKETS; - if (call->app_call_state != RXRPC_CSTATE_CLNT_SND_ARGS) - msg->hdr.flags |= RXRPC_REQUEST_ACK; - } - else { - msg->hdr.flags |= RXRPC_MORE_PACKETS; - } - - _proto("Sending DATA message { ds=%Zu dc=%u df=%02lu }", - msg->dsize, msg->dcount, msg->dfree); - - /* queue and adjust call state */ - spin_lock(&call->lock); - list_add_tail(&msg->link, &call->acks_pendq); - - /* decide what to do depending on current state and if this is - * the last packet */ - ret = -EINVAL; - switch (call->app_call_state) { - case RXRPC_CSTATE_SRVR_SND_REPLY: - if (msg->hdr.flags & RXRPC_LAST_PACKET) { - call->app_call_state = - RXRPC_CSTATE_SRVR_RCV_FINAL_ACK; - _state(call); - } - break; - - case RXRPC_CSTATE_CLNT_SND_ARGS: - if (msg->hdr.flags & RXRPC_LAST_PACKET) { - call->app_call_state = - RXRPC_CSTATE_CLNT_RCV_REPLY; - _state(call); - } - break; - - case RXRPC_CSTATE_ERROR: - ret = call->app_errno; - default: - spin_unlock(&call->lock); - goto out; - } - - call->acks_pend_cnt++; - - mod_timer(&call->acks_timeout, - __rxrpc_rtt_based_timeout(call, - rxrpc_call_acks_timeout)); - - spin_unlock(&call->lock); - - ret = rxrpc_conn_sendmsg(call->conn, msg); - if (ret == 0) - call->pkt_snd_count++; - } - - out: - rxrpc_put_call(call); - - _leave(" = %d", ret); - return ret; - -} /* end rxrpc_call_flush() */ - -/*****************************************************************************/ -/* - * resend NAK'd or unacknowledged packets up to the highest one specified - */ -static void rxrpc_call_resend(struct rxrpc_call *call, rxrpc_seq_t highest) -{ - struct rxrpc_message *msg; - struct list_head *_p; - rxrpc_seq_t seq = 0; - - _enter("%p,%u", call, highest); - - _proto("Rx Resend required"); - - /* handle too many resends */ - if (call->snd_resend_cnt >= rxrpc_call_max_resend) { - _debug("Aborting due to too many resends (rcv=%d)", - call->pkt_rcv_count); - rxrpc_call_abort(call, - call->pkt_rcv_count > 0 ? -EIO : -ETIMEDOUT); - _leave(""); - return; - } - - spin_lock(&call->lock); - call->snd_resend_cnt++; - for (;;) { - /* determine which the next packet we might need to ACK is */ - if (seq <= call->acks_dftv_seq) - seq = call->acks_dftv_seq; - seq++; - - if (seq > highest) - break; - - /* look for the packet in the pending-ACK queue */ - list_for_each(_p, &call->acks_pendq) { - msg = list_entry(_p, struct rxrpc_message, link); - if (msg->seq == seq) - goto found_msg; - } - - panic("%s(%p,%d):" - " Inconsistent pending-ACK queue (ds=%u sc=%u sq=%u)\n", - __FUNCTION__, call, highest, - call->acks_dftv_seq, call->snd_seq_count, seq); - - found_msg: - if (msg->state != RXRPC_MSG_SENT) - continue; /* only un-ACK'd packets */ - - rxrpc_get_message(msg); - spin_unlock(&call->lock); - - /* send each message again (and ignore any errors we might - * incur) */ - _proto("Resending DATA message { ds=%Zu dc=%u df=%02lu }", - msg->dsize, msg->dcount, msg->dfree); - - if (rxrpc_conn_sendmsg(call->conn, msg) == 0) - call->pkt_snd_count++; - - rxrpc_put_message(msg); - - spin_lock(&call->lock); - } - - /* reset the timeout */ - mod_timer(&call->acks_timeout, - __rxrpc_rtt_based_timeout(call, rxrpc_call_acks_timeout)); - - spin_unlock(&call->lock); - - _leave(""); -} /* end rxrpc_call_resend() */ - -/*****************************************************************************/ -/* - * handle an ICMP error being applied to a call - */ -void rxrpc_call_handle_error(struct rxrpc_call *call, int local, int errno) -{ - _enter("%p{%u},%d", call, ntohl(call->call_id), errno); - - /* if this call is already aborted, then just wake up any waiters */ - if (call->app_call_state == RXRPC_CSTATE_ERROR) { - call->app_error_func(call); - } - else { - /* tell the app layer what happened */ - spin_lock(&call->lock); - call->app_call_state = RXRPC_CSTATE_ERROR; - _state(call); - if (local) - call->app_err_state = RXRPC_ESTATE_LOCAL_ERROR; - else - call->app_err_state = RXRPC_ESTATE_REMOTE_ERROR; - call->app_errno = errno; - call->app_mark = RXRPC_APP_MARK_EOF; - call->app_read_buf = NULL; - call->app_async_read = 0; - - /* map the error */ - call->app_aemap_func(call); - - del_timer_sync(&call->acks_timeout); - del_timer_sync(&call->rcv_timeout); - del_timer_sync(&call->ackr_dfr_timo); - - spin_unlock(&call->lock); - - call->app_error_func(call); - } - - _leave(""); -} /* end rxrpc_call_handle_error() */ diff --git a/net/rxrpc/connection.c b/net/rxrpc/connection.c deleted file mode 100644 index 665a99952440..000000000000 --- a/net/rxrpc/connection.c +++ /dev/null @@ -1,777 +0,0 @@ -/* connection.c: Rx connection routines - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -__RXACCT_DECL(atomic_t rxrpc_connection_count); - -LIST_HEAD(rxrpc_conns); -DECLARE_RWSEM(rxrpc_conns_sem); -unsigned long rxrpc_conn_timeout = 60 * 60; - -static void rxrpc_conn_do_timeout(struct rxrpc_connection *conn); - -static void __rxrpc_conn_timeout(rxrpc_timer_t *timer) -{ - struct rxrpc_connection *conn = - list_entry(timer, struct rxrpc_connection, timeout); - - _debug("Rx CONN TIMEOUT [%p{u=%d}]", conn, atomic_read(&conn->usage)); - - rxrpc_conn_do_timeout(conn); -} - -static const struct rxrpc_timer_ops rxrpc_conn_timer_ops = { - .timed_out = __rxrpc_conn_timeout, -}; - -/*****************************************************************************/ -/* - * create a new connection record - */ -static inline int __rxrpc_create_connection(struct rxrpc_peer *peer, - struct rxrpc_connection **_conn) -{ - struct rxrpc_connection *conn; - - _enter("%p",peer); - - /* allocate and initialise a connection record */ - conn = kzalloc(sizeof(struct rxrpc_connection), GFP_KERNEL); - if (!conn) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - atomic_set(&conn->usage, 1); - - INIT_LIST_HEAD(&conn->link); - INIT_LIST_HEAD(&conn->id_link); - init_waitqueue_head(&conn->chanwait); - spin_lock_init(&conn->lock); - rxrpc_timer_init(&conn->timeout, &rxrpc_conn_timer_ops); - - do_gettimeofday(&conn->atime); - conn->mtu_size = 1024; - conn->peer = peer; - conn->trans = peer->trans; - - __RXACCT(atomic_inc(&rxrpc_connection_count)); - *_conn = conn; - _leave(" = 0 (%p)", conn); - - return 0; -} /* end __rxrpc_create_connection() */ - -/*****************************************************************************/ -/* - * create a new connection record for outgoing connections - */ -int rxrpc_create_connection(struct rxrpc_transport *trans, - __be16 port, - __be32 addr, - uint16_t service_id, - void *security, - struct rxrpc_connection **_conn) -{ - struct rxrpc_connection *candidate, *conn; - struct rxrpc_peer *peer; - struct list_head *_p; - __be32 connid; - int ret; - - _enter("%p{%hu},%u,%hu", trans, trans->port, ntohs(port), service_id); - - /* get a peer record */ - ret = rxrpc_peer_lookup(trans, addr, &peer); - if (ret < 0) { - _leave(" = %d", ret); - return ret; - } - - /* allocate and initialise a connection record */ - ret = __rxrpc_create_connection(peer, &candidate); - if (ret < 0) { - rxrpc_put_peer(peer); - _leave(" = %d", ret); - return ret; - } - - /* fill in the specific bits */ - candidate->addr.sin_family = AF_INET; - candidate->addr.sin_port = port; - candidate->addr.sin_addr.s_addr = addr; - - candidate->in_epoch = rxrpc_epoch; - candidate->out_epoch = rxrpc_epoch; - candidate->in_clientflag = 0; - candidate->out_clientflag = RXRPC_CLIENT_INITIATED; - candidate->service_id = htons(service_id); - - /* invent a unique connection ID */ - write_lock(&peer->conn_idlock); - - try_next_id: - connid = htonl(peer->conn_idcounter & RXRPC_CIDMASK); - peer->conn_idcounter += RXRPC_MAXCALLS; - - list_for_each(_p, &peer->conn_idlist) { - conn = list_entry(_p, struct rxrpc_connection, id_link); - if (connid == conn->conn_id) - goto try_next_id; - if (connid > conn->conn_id) - break; - } - - _debug("selected candidate conn ID %x.%u", - ntohl(peer->addr.s_addr), ntohl(connid)); - - candidate->conn_id = connid; - list_add_tail(&candidate->id_link, _p); - - write_unlock(&peer->conn_idlock); - - /* attach to peer */ - candidate->peer = peer; - - write_lock(&peer->conn_lock); - - /* search the peer's transport graveyard list */ - spin_lock(&peer->conn_gylock); - list_for_each(_p, &peer->conn_graveyard) { - conn = list_entry(_p, struct rxrpc_connection, link); - if (conn->addr.sin_port == candidate->addr.sin_port && - conn->security_ix == candidate->security_ix && - conn->service_id == candidate->service_id && - conn->in_clientflag == 0) - goto found_in_graveyard; - } - spin_unlock(&peer->conn_gylock); - - /* pick the new candidate */ - _debug("created connection: {%08x} [out]", ntohl(candidate->conn_id)); - atomic_inc(&peer->conn_count); - conn = candidate; - candidate = NULL; - - make_active: - list_add_tail(&conn->link, &peer->conn_active); - write_unlock(&peer->conn_lock); - - if (candidate) { - write_lock(&peer->conn_idlock); - list_del(&candidate->id_link); - write_unlock(&peer->conn_idlock); - - __RXACCT(atomic_dec(&rxrpc_connection_count)); - kfree(candidate); - } - else { - down_write(&rxrpc_conns_sem); - list_add_tail(&conn->proc_link, &rxrpc_conns); - up_write(&rxrpc_conns_sem); - } - - *_conn = conn; - _leave(" = 0 (%p)", conn); - - return 0; - - /* handle resurrecting a connection from the graveyard */ - found_in_graveyard: - _debug("resurrecting connection: {%08x} [out]", ntohl(conn->conn_id)); - rxrpc_get_connection(conn); - rxrpc_krxtimod_del_timer(&conn->timeout); - list_del_init(&conn->link); - spin_unlock(&peer->conn_gylock); - goto make_active; -} /* end rxrpc_create_connection() */ - -/*****************************************************************************/ -/* - * lookup the connection for an incoming packet - * - create a new connection record for unrecorded incoming connections - */ -int rxrpc_connection_lookup(struct rxrpc_peer *peer, - struct rxrpc_message *msg, - struct rxrpc_connection **_conn) -{ - struct rxrpc_connection *conn, *candidate = NULL; - struct list_head *_p; - struct sk_buff *pkt = msg->pkt; - int ret, fresh = 0; - __be32 x_epoch, x_connid; - __be16 x_port, x_servid; - __u32 x_secix; - u8 x_clflag; - - _enter("%p{{%hu}},%u,%hu", - peer, - peer->trans->port, - ntohs(udp_hdr(pkt)->source), - ntohs(msg->hdr.serviceId)); - - x_port = udp_hdr(pkt)->source; - x_epoch = msg->hdr.epoch; - x_clflag = msg->hdr.flags & RXRPC_CLIENT_INITIATED; - x_connid = htonl(ntohl(msg->hdr.cid) & RXRPC_CIDMASK); - x_servid = msg->hdr.serviceId; - x_secix = msg->hdr.securityIndex; - - /* [common case] search the transport's active list first */ - read_lock(&peer->conn_lock); - list_for_each(_p, &peer->conn_active) { - conn = list_entry(_p, struct rxrpc_connection, link); - if (conn->addr.sin_port == x_port && - conn->in_epoch == x_epoch && - conn->conn_id == x_connid && - conn->security_ix == x_secix && - conn->service_id == x_servid && - conn->in_clientflag == x_clflag) - goto found_active; - } - read_unlock(&peer->conn_lock); - - /* [uncommon case] not active - * - create a candidate for a new record if an inbound connection - * - only examine the graveyard for an outbound connection - */ - if (x_clflag) { - ret = __rxrpc_create_connection(peer, &candidate); - if (ret < 0) { - _leave(" = %d", ret); - return ret; - } - - /* fill in the specifics */ - candidate->addr.sin_family = AF_INET; - candidate->addr.sin_port = x_port; - candidate->addr.sin_addr.s_addr = ip_hdr(pkt)->saddr; - candidate->in_epoch = x_epoch; - candidate->out_epoch = x_epoch; - candidate->in_clientflag = RXRPC_CLIENT_INITIATED; - candidate->out_clientflag = 0; - candidate->conn_id = x_connid; - candidate->service_id = x_servid; - candidate->security_ix = x_secix; - } - - /* search the active list again, just in case it appeared whilst we - * were busy */ - write_lock(&peer->conn_lock); - list_for_each(_p, &peer->conn_active) { - conn = list_entry(_p, struct rxrpc_connection, link); - if (conn->addr.sin_port == x_port && - conn->in_epoch == x_epoch && - conn->conn_id == x_connid && - conn->security_ix == x_secix && - conn->service_id == x_servid && - conn->in_clientflag == x_clflag) - goto found_active_second_chance; - } - - /* search the transport's graveyard list */ - spin_lock(&peer->conn_gylock); - list_for_each(_p, &peer->conn_graveyard) { - conn = list_entry(_p, struct rxrpc_connection, link); - if (conn->addr.sin_port == x_port && - conn->in_epoch == x_epoch && - conn->conn_id == x_connid && - conn->security_ix == x_secix && - conn->service_id == x_servid && - conn->in_clientflag == x_clflag) - goto found_in_graveyard; - } - spin_unlock(&peer->conn_gylock); - - /* outbound connections aren't created here */ - if (!x_clflag) { - write_unlock(&peer->conn_lock); - _leave(" = -ENOENT"); - return -ENOENT; - } - - /* we can now add the new candidate to the list */ - _debug("created connection: {%08x} [in]", ntohl(candidate->conn_id)); - rxrpc_get_peer(peer); - conn = candidate; - candidate = NULL; - atomic_inc(&peer->conn_count); - fresh = 1; - - make_active: - list_add_tail(&conn->link, &peer->conn_active); - - success_uwfree: - write_unlock(&peer->conn_lock); - - if (candidate) { - write_lock(&peer->conn_idlock); - list_del(&candidate->id_link); - write_unlock(&peer->conn_idlock); - - __RXACCT(atomic_dec(&rxrpc_connection_count)); - kfree(candidate); - } - - if (fresh) { - down_write(&rxrpc_conns_sem); - list_add_tail(&conn->proc_link, &rxrpc_conns); - up_write(&rxrpc_conns_sem); - } - - success: - *_conn = conn; - _leave(" = 0 (%p)", conn); - return 0; - - /* handle the connection being found in the active list straight off */ - found_active: - rxrpc_get_connection(conn); - read_unlock(&peer->conn_lock); - goto success; - - /* handle resurrecting a connection from the graveyard */ - found_in_graveyard: - _debug("resurrecting connection: {%08x} [in]", ntohl(conn->conn_id)); - rxrpc_get_peer(peer); - rxrpc_get_connection(conn); - rxrpc_krxtimod_del_timer(&conn->timeout); - list_del_init(&conn->link); - spin_unlock(&peer->conn_gylock); - goto make_active; - - /* handle finding the connection on the second time through the active - * list */ - found_active_second_chance: - rxrpc_get_connection(conn); - goto success_uwfree; - -} /* end rxrpc_connection_lookup() */ - -/*****************************************************************************/ -/* - * finish using a connection record - * - it will be transferred to the peer's connection graveyard when refcount - * reaches 0 - */ -void rxrpc_put_connection(struct rxrpc_connection *conn) -{ - struct rxrpc_peer *peer; - - if (!conn) - return; - - _enter("%p{u=%d p=%hu}", - conn, atomic_read(&conn->usage), ntohs(conn->addr.sin_port)); - - peer = conn->peer; - spin_lock(&peer->conn_gylock); - - /* sanity check */ - if (atomic_read(&conn->usage) <= 0) - BUG(); - - if (likely(!atomic_dec_and_test(&conn->usage))) { - spin_unlock(&peer->conn_gylock); - _leave(""); - return; - } - - /* move to graveyard queue */ - _debug("burying connection: {%08x}", ntohl(conn->conn_id)); - list_move_tail(&conn->link, &peer->conn_graveyard); - - rxrpc_krxtimod_add_timer(&conn->timeout, rxrpc_conn_timeout * HZ); - - spin_unlock(&peer->conn_gylock); - - rxrpc_put_peer(conn->peer); - - _leave(" [killed]"); -} /* end rxrpc_put_connection() */ - -/*****************************************************************************/ -/* - * free a connection record - */ -static void rxrpc_conn_do_timeout(struct rxrpc_connection *conn) -{ - struct rxrpc_peer *peer; - - _enter("%p{u=%d p=%hu}", - conn, atomic_read(&conn->usage), ntohs(conn->addr.sin_port)); - - peer = conn->peer; - - if (atomic_read(&conn->usage) < 0) - BUG(); - - /* remove from graveyard if still dead */ - spin_lock(&peer->conn_gylock); - if (atomic_read(&conn->usage) == 0) { - list_del_init(&conn->link); - } - else { - conn = NULL; - } - spin_unlock(&peer->conn_gylock); - - if (!conn) { - _leave(""); - return; /* resurrected */ - } - - _debug("--- Destroying Connection %p{%08x} ---", - conn, ntohl(conn->conn_id)); - - down_write(&rxrpc_conns_sem); - list_del(&conn->proc_link); - up_write(&rxrpc_conns_sem); - - write_lock(&peer->conn_idlock); - list_del(&conn->id_link); - write_unlock(&peer->conn_idlock); - - __RXACCT(atomic_dec(&rxrpc_connection_count)); - kfree(conn); - - /* if the graveyard is now empty, wake up anyone waiting for that */ - if (atomic_dec_and_test(&peer->conn_count)) - wake_up(&peer->conn_gy_waitq); - - _leave(" [destroyed]"); -} /* end rxrpc_conn_do_timeout() */ - -/*****************************************************************************/ -/* - * clear all connection records from a peer endpoint - */ -void rxrpc_conn_clearall(struct rxrpc_peer *peer) -{ - DECLARE_WAITQUEUE(myself, current); - - struct rxrpc_connection *conn; - int err; - - _enter("%p", peer); - - /* there shouldn't be any active conns remaining */ - if (!list_empty(&peer->conn_active)) - BUG(); - - /* manually timeout all conns in the graveyard */ - spin_lock(&peer->conn_gylock); - while (!list_empty(&peer->conn_graveyard)) { - conn = list_entry(peer->conn_graveyard.next, - struct rxrpc_connection, link); - err = rxrpc_krxtimod_del_timer(&conn->timeout); - spin_unlock(&peer->conn_gylock); - - if (err == 0) - rxrpc_conn_do_timeout(conn); - - spin_lock(&peer->conn_gylock); - } - spin_unlock(&peer->conn_gylock); - - /* wait for the the conn graveyard to be completely cleared */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&peer->conn_gy_waitq, &myself); - - while (atomic_read(&peer->conn_count) != 0) { - schedule(); - set_current_state(TASK_UNINTERRUPTIBLE); - } - - remove_wait_queue(&peer->conn_gy_waitq, &myself); - set_current_state(TASK_RUNNING); - - _leave(""); -} /* end rxrpc_conn_clearall() */ - -/*****************************************************************************/ -/* - * allocate and prepare a message for sending out through the transport - * endpoint - */ -int rxrpc_conn_newmsg(struct rxrpc_connection *conn, - struct rxrpc_call *call, - uint8_t type, - int dcount, - struct kvec diov[], - gfp_t alloc_flags, - struct rxrpc_message **_msg) -{ - struct rxrpc_message *msg; - int loop; - - _enter("%p{%d},%p,%u", conn, ntohs(conn->addr.sin_port), call, type); - - if (dcount > 3) { - _leave(" = -EINVAL"); - return -EINVAL; - } - - msg = kzalloc(sizeof(struct rxrpc_message), alloc_flags); - if (!msg) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - atomic_set(&msg->usage, 1); - - INIT_LIST_HEAD(&msg->link); - - msg->state = RXRPC_MSG_PREPARED; - - msg->hdr.epoch = conn->out_epoch; - msg->hdr.cid = conn->conn_id | (call ? call->chan_ix : 0); - msg->hdr.callNumber = call ? call->call_id : 0; - msg->hdr.type = type; - msg->hdr.flags = conn->out_clientflag; - msg->hdr.securityIndex = conn->security_ix; - msg->hdr.serviceId = conn->service_id; - - /* generate sequence numbers for data packets */ - if (call) { - switch (type) { - case RXRPC_PACKET_TYPE_DATA: - msg->seq = ++call->snd_seq_count; - msg->hdr.seq = htonl(msg->seq); - break; - case RXRPC_PACKET_TYPE_ACK: - /* ACK sequence numbers are complicated. The following - * may be wrong: - * - jumbo packet ACKs should have a seq number - * - normal ACKs should not - */ - default: - break; - } - } - - msg->dcount = dcount + 1; - msg->dsize = sizeof(msg->hdr); - msg->data[0].iov_len = sizeof(msg->hdr); - msg->data[0].iov_base = &msg->hdr; - - for (loop=0; loop < dcount; loop++) { - msg->dsize += diov[loop].iov_len; - msg->data[loop+1].iov_len = diov[loop].iov_len; - msg->data[loop+1].iov_base = diov[loop].iov_base; - } - - __RXACCT(atomic_inc(&rxrpc_message_count)); - *_msg = msg; - _leave(" = 0 (%p) #%d", msg, atomic_read(&rxrpc_message_count)); - return 0; -} /* end rxrpc_conn_newmsg() */ - -/*****************************************************************************/ -/* - * free a message - */ -void __rxrpc_put_message(struct rxrpc_message *msg) -{ - int loop; - - _enter("%p #%d", msg, atomic_read(&rxrpc_message_count)); - - if (msg->pkt) - kfree_skb(msg->pkt); - rxrpc_put_connection(msg->conn); - - for (loop = 0; loop < 8; loop++) - if (test_bit(loop, &msg->dfree)) - kfree(msg->data[loop].iov_base); - - __RXACCT(atomic_dec(&rxrpc_message_count)); - kfree(msg); - - _leave(""); -} /* end __rxrpc_put_message() */ - -/*****************************************************************************/ -/* - * send a message out through the transport endpoint - */ -int rxrpc_conn_sendmsg(struct rxrpc_connection *conn, - struct rxrpc_message *msg) -{ - struct msghdr msghdr; - int ret; - - _enter("%p{%d}", conn, ntohs(conn->addr.sin_port)); - - /* fill in some fields in the header */ - spin_lock(&conn->lock); - msg->hdr.serial = htonl(++conn->serial_counter); - msg->rttdone = 0; - spin_unlock(&conn->lock); - - /* set up the message to be transmitted */ - msghdr.msg_name = &conn->addr; - msghdr.msg_namelen = sizeof(conn->addr); - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; - msghdr.msg_flags = MSG_CONFIRM | MSG_DONTWAIT; - - _net("Sending message type %d of %Zd bytes to %08x:%d", - msg->hdr.type, - msg->dsize, - ntohl(conn->addr.sin_addr.s_addr), - ntohs(conn->addr.sin_port)); - - /* send the message */ - ret = kernel_sendmsg(conn->trans->socket, &msghdr, - msg->data, msg->dcount, msg->dsize); - if (ret < 0) { - msg->state = RXRPC_MSG_ERROR; - } else { - msg->state = RXRPC_MSG_SENT; - ret = 0; - - spin_lock(&conn->lock); - do_gettimeofday(&conn->atime); - msg->stamp = conn->atime; - spin_unlock(&conn->lock); - } - - _leave(" = %d", ret); - - return ret; -} /* end rxrpc_conn_sendmsg() */ - -/*****************************************************************************/ -/* - * deal with a subsequent call packet - */ -int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn, - struct rxrpc_call *call, - struct rxrpc_message *msg) -{ - struct rxrpc_message *pmsg; - struct dst_entry *dst; - struct list_head *_p; - unsigned cix, seq; - int ret = 0; - - _enter("%p,%p,%p", conn, call, msg); - - if (!call) { - cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK; - - spin_lock(&conn->lock); - call = conn->channels[cix]; - - if (!call || call->call_id != msg->hdr.callNumber) { - spin_unlock(&conn->lock); - rxrpc_trans_immediate_abort(conn->trans, msg, -ENOENT); - goto out; - } - else { - rxrpc_get_call(call); - spin_unlock(&conn->lock); - } - } - else { - rxrpc_get_call(call); - } - - _proto("Received packet %%%u [%u] on call %hu:%u:%u", - ntohl(msg->hdr.serial), - ntohl(msg->hdr.seq), - ntohs(msg->hdr.serviceId), - ntohl(conn->conn_id), - ntohl(call->call_id)); - - call->pkt_rcv_count++; - - dst = msg->pkt->dst; - if (dst && dst->dev) - conn->peer->if_mtu = - dst->dev->mtu - dst->dev->hard_header_len; - - /* queue on the call in seq order */ - rxrpc_get_message(msg); - seq = msg->seq; - - spin_lock(&call->lock); - list_for_each(_p, &call->rcv_receiveq) { - pmsg = list_entry(_p, struct rxrpc_message, link); - if (pmsg->seq > seq) - break; - } - list_add_tail(&msg->link, _p); - - /* reset the activity timeout */ - call->flags |= RXRPC_CALL_RCV_PKT; - mod_timer(&call->rcv_timeout,jiffies + rxrpc_call_rcv_timeout * HZ); - - spin_unlock(&call->lock); - - rxrpc_krxiod_queue_call(call); - - rxrpc_put_call(call); - out: - _leave(" = %d", ret); - return ret; -} /* end rxrpc_conn_receive_call_packet() */ - -/*****************************************************************************/ -/* - * handle an ICMP error being applied to a connection - */ -void rxrpc_conn_handle_error(struct rxrpc_connection *conn, - int local, int errno) -{ - struct rxrpc_call *calls[4]; - int loop; - - _enter("%p{%d},%d", conn, ntohs(conn->addr.sin_port), errno); - - /* get a ref to all my calls in one go */ - memset(calls, 0, sizeof(calls)); - spin_lock(&conn->lock); - - for (loop = 3; loop >= 0; loop--) { - if (conn->channels[loop]) { - calls[loop] = conn->channels[loop]; - rxrpc_get_call(calls[loop]); - } - } - - spin_unlock(&conn->lock); - - /* now kick them all */ - for (loop = 3; loop >= 0; loop--) { - if (calls[loop]) { - rxrpc_call_handle_error(calls[loop], local, errno); - rxrpc_put_call(calls[loop]); - } - } - - _leave(""); -} /* end rxrpc_conn_handle_error() */ diff --git a/net/rxrpc/internal.h b/net/rxrpc/internal.h deleted file mode 100644 index cc0c5795a103..000000000000 --- a/net/rxrpc/internal.h +++ /dev/null @@ -1,106 +0,0 @@ -/* internal.h: internal Rx RPC stuff - * - * Copyright (c) 2002 David Howells (dhowells@redhat.com). - */ - -#ifndef RXRPC_INTERNAL_H -#define RXRPC_INTERNAL_H - -#include -#include - -/* - * debug accounting - */ -#if 1 -#define __RXACCT_DECL(X) X -#define __RXACCT(X) do { X; } while(0) -#else -#define __RXACCT_DECL(X) -#define __RXACCT(X) do { } while(0) -#endif - -__RXACCT_DECL(extern atomic_t rxrpc_transport_count); -__RXACCT_DECL(extern atomic_t rxrpc_peer_count); -__RXACCT_DECL(extern atomic_t rxrpc_connection_count); -__RXACCT_DECL(extern atomic_t rxrpc_call_count); -__RXACCT_DECL(extern atomic_t rxrpc_message_count); - -/* - * debug tracing - */ -#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ##a) -#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ##a) -#define kdebug(FMT, a...) printk(" "FMT"\n" , ##a) -#define kproto(FMT, a...) printk("### "FMT"\n" , ##a) -#define knet(FMT, a...) printk(" "FMT"\n" , ##a) - -#if 0 -#define _enter(FMT, a...) kenter(FMT , ##a) -#define _leave(FMT, a...) kleave(FMT , ##a) -#define _debug(FMT, a...) kdebug(FMT , ##a) -#define _proto(FMT, a...) kproto(FMT , ##a) -#define _net(FMT, a...) knet(FMT , ##a) -#else -#define _enter(FMT, a...) do { if (rxrpc_ktrace) kenter(FMT , ##a); } while(0) -#define _leave(FMT, a...) do { if (rxrpc_ktrace) kleave(FMT , ##a); } while(0) -#define _debug(FMT, a...) do { if (rxrpc_kdebug) kdebug(FMT , ##a); } while(0) -#define _proto(FMT, a...) do { if (rxrpc_kproto) kproto(FMT , ##a); } while(0) -#define _net(FMT, a...) do { if (rxrpc_knet) knet (FMT , ##a); } while(0) -#endif - -static inline void rxrpc_discard_my_signals(void) -{ - while (signal_pending(current)) { - siginfo_t sinfo; - - spin_lock_irq(¤t->sighand->siglock); - dequeue_signal(current, ¤t->blocked, &sinfo); - spin_unlock_irq(¤t->sighand->siglock); - } -} - -/* - * call.c - */ -extern struct list_head rxrpc_calls; -extern struct rw_semaphore rxrpc_calls_sem; - -/* - * connection.c - */ -extern struct list_head rxrpc_conns; -extern struct rw_semaphore rxrpc_conns_sem; -extern unsigned long rxrpc_conn_timeout; - -extern void rxrpc_conn_clearall(struct rxrpc_peer *peer); - -/* - * peer.c - */ -extern struct list_head rxrpc_peers; -extern struct rw_semaphore rxrpc_peers_sem; -extern unsigned long rxrpc_peer_timeout; - -extern void rxrpc_peer_calculate_rtt(struct rxrpc_peer *peer, - struct rxrpc_message *msg, - struct rxrpc_message *resp); - -extern void rxrpc_peer_clearall(struct rxrpc_transport *trans); - - -/* - * proc.c - */ -#ifdef CONFIG_PROC_FS -extern int rxrpc_proc_init(void); -extern void rxrpc_proc_cleanup(void); -#endif - -/* - * transport.c - */ -extern struct list_head rxrpc_proc_transports; -extern struct rw_semaphore rxrpc_proc_transports_sem; - -#endif /* RXRPC_INTERNAL_H */ diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c deleted file mode 100644 index bbbcd6c24048..000000000000 --- a/net/rxrpc/krxiod.c +++ /dev/null @@ -1,262 +0,0 @@ -/* krxiod.c: Rx I/O daemon - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxiod_sleepq); -static DECLARE_COMPLETION(rxrpc_krxiod_dead); - -static atomic_t rxrpc_krxiod_qcount = ATOMIC_INIT(0); - -static LIST_HEAD(rxrpc_krxiod_transportq); -static DEFINE_SPINLOCK(rxrpc_krxiod_transportq_lock); - -static LIST_HEAD(rxrpc_krxiod_callq); -static DEFINE_SPINLOCK(rxrpc_krxiod_callq_lock); - -static volatile int rxrpc_krxiod_die; - -/*****************************************************************************/ -/* - * Rx I/O daemon - */ -static int rxrpc_krxiod(void *arg) -{ - DECLARE_WAITQUEUE(krxiod,current); - - printk("Started krxiod %d\n",current->pid); - - daemonize("krxiod"); - - /* loop around waiting for work to do */ - do { - /* wait for work or to be told to exit */ - _debug("### Begin Wait"); - if (!atomic_read(&rxrpc_krxiod_qcount)) { - set_current_state(TASK_INTERRUPTIBLE); - - add_wait_queue(&rxrpc_krxiod_sleepq, &krxiod); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (atomic_read(&rxrpc_krxiod_qcount) || - rxrpc_krxiod_die || - signal_pending(current)) - break; - - schedule(); - } - - remove_wait_queue(&rxrpc_krxiod_sleepq, &krxiod); - set_current_state(TASK_RUNNING); - } - _debug("### End Wait"); - - /* do work if been given some to do */ - _debug("### Begin Work"); - - /* see if there's a transport in need of attention */ - if (!list_empty(&rxrpc_krxiod_transportq)) { - struct rxrpc_transport *trans = NULL; - - spin_lock_irq(&rxrpc_krxiod_transportq_lock); - - if (!list_empty(&rxrpc_krxiod_transportq)) { - trans = list_entry( - rxrpc_krxiod_transportq.next, - struct rxrpc_transport, - krxiodq_link); - - list_del_init(&trans->krxiodq_link); - atomic_dec(&rxrpc_krxiod_qcount); - - /* make sure it hasn't gone away and doesn't go - * away */ - if (atomic_read(&trans->usage)>0) - rxrpc_get_transport(trans); - else - trans = NULL; - } - - spin_unlock_irq(&rxrpc_krxiod_transportq_lock); - - if (trans) { - rxrpc_trans_receive_packet(trans); - rxrpc_put_transport(trans); - } - } - - /* see if there's a call in need of attention */ - if (!list_empty(&rxrpc_krxiod_callq)) { - struct rxrpc_call *call = NULL; - - spin_lock_irq(&rxrpc_krxiod_callq_lock); - - if (!list_empty(&rxrpc_krxiod_callq)) { - call = list_entry(rxrpc_krxiod_callq.next, - struct rxrpc_call, - rcv_krxiodq_lk); - list_del_init(&call->rcv_krxiodq_lk); - atomic_dec(&rxrpc_krxiod_qcount); - - /* make sure it hasn't gone away and doesn't go - * away */ - if (atomic_read(&call->usage) > 0) { - _debug("@@@ KRXIOD" - " Begin Attend Call %p", call); - rxrpc_get_call(call); - } - else { - call = NULL; - } - } - - spin_unlock_irq(&rxrpc_krxiod_callq_lock); - - if (call) { - rxrpc_call_do_stuff(call); - rxrpc_put_call(call); - _debug("@@@ KRXIOD End Attend Call %p", call); - } - } - - _debug("### End Work"); - - try_to_freeze(); - - /* discard pending signals */ - rxrpc_discard_my_signals(); - - } while (!rxrpc_krxiod_die); - - /* and that's all */ - complete_and_exit(&rxrpc_krxiod_dead, 0); - -} /* end rxrpc_krxiod() */ - -/*****************************************************************************/ -/* - * start up a krxiod daemon - */ -int __init rxrpc_krxiod_init(void) -{ - return kernel_thread(rxrpc_krxiod, NULL, 0); - -} /* end rxrpc_krxiod_init() */ - -/*****************************************************************************/ -/* - * kill the krxiod daemon and wait for it to complete - */ -void rxrpc_krxiod_kill(void) -{ - rxrpc_krxiod_die = 1; - wake_up_all(&rxrpc_krxiod_sleepq); - wait_for_completion(&rxrpc_krxiod_dead); - -} /* end rxrpc_krxiod_kill() */ - -/*****************************************************************************/ -/* - * queue a transport for attention by krxiod - */ -void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans) -{ - unsigned long flags; - - _enter(""); - - if (list_empty(&trans->krxiodq_link)) { - spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags); - - if (list_empty(&trans->krxiodq_link)) { - if (atomic_read(&trans->usage) > 0) { - list_add_tail(&trans->krxiodq_link, - &rxrpc_krxiod_transportq); - atomic_inc(&rxrpc_krxiod_qcount); - } - } - - spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags); - wake_up_all(&rxrpc_krxiod_sleepq); - } - - _leave(""); - -} /* end rxrpc_krxiod_queue_transport() */ - -/*****************************************************************************/ -/* - * dequeue a transport from krxiod's attention queue - */ -void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans) -{ - unsigned long flags; - - _enter(""); - - spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags); - if (!list_empty(&trans->krxiodq_link)) { - list_del_init(&trans->krxiodq_link); - atomic_dec(&rxrpc_krxiod_qcount); - } - spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags); - - _leave(""); - -} /* end rxrpc_krxiod_dequeue_transport() */ - -/*****************************************************************************/ -/* - * queue a call for attention by krxiod - */ -void rxrpc_krxiod_queue_call(struct rxrpc_call *call) -{ - unsigned long flags; - - if (list_empty(&call->rcv_krxiodq_lk)) { - spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags); - if (atomic_read(&call->usage) > 0) { - list_add_tail(&call->rcv_krxiodq_lk, - &rxrpc_krxiod_callq); - atomic_inc(&rxrpc_krxiod_qcount); - } - spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags); - } - wake_up_all(&rxrpc_krxiod_sleepq); - -} /* end rxrpc_krxiod_queue_call() */ - -/*****************************************************************************/ -/* - * dequeue a call from krxiod's attention queue - */ -void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call) -{ - unsigned long flags; - - spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags); - if (!list_empty(&call->rcv_krxiodq_lk)) { - list_del_init(&call->rcv_krxiodq_lk); - atomic_dec(&rxrpc_krxiod_qcount); - } - spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags); - -} /* end rxrpc_krxiod_dequeue_call() */ diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c deleted file mode 100644 index 9a1e7f5e034c..000000000000 --- a/net/rxrpc/krxsecd.c +++ /dev/null @@ -1,270 +0,0 @@ -/* krxsecd.c: Rx security daemon - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - * - * This daemon deals with: - * - consulting the application as to whether inbound peers and calls should be authorised - * - generating security challenges for inbound connections - * - responding to security challenges on outbound connections - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxsecd_sleepq); -static DECLARE_COMPLETION(rxrpc_krxsecd_dead); -static volatile int rxrpc_krxsecd_die; - -static atomic_t rxrpc_krxsecd_qcount; - -/* queue of unprocessed inbound messages with seqno #1 and - * RXRPC_CLIENT_INITIATED flag set */ -static LIST_HEAD(rxrpc_krxsecd_initmsgq); -static DEFINE_SPINLOCK(rxrpc_krxsecd_initmsgq_lock); - -static void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg); - -/*****************************************************************************/ -/* - * Rx security daemon - */ -static int rxrpc_krxsecd(void *arg) -{ - DECLARE_WAITQUEUE(krxsecd, current); - - int die; - - printk("Started krxsecd %d\n", current->pid); - - daemonize("krxsecd"); - - /* loop around waiting for work to do */ - do { - /* wait for work or to be told to exit */ - _debug("### Begin Wait"); - if (!atomic_read(&rxrpc_krxsecd_qcount)) { - set_current_state(TASK_INTERRUPTIBLE); - - add_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (atomic_read(&rxrpc_krxsecd_qcount) || - rxrpc_krxsecd_die || - signal_pending(current)) - break; - - schedule(); - } - - remove_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd); - set_current_state(TASK_RUNNING); - } - die = rxrpc_krxsecd_die; - _debug("### End Wait"); - - /* see if there're incoming calls in need of authenticating */ - _debug("### Begin Inbound Calls"); - - if (!list_empty(&rxrpc_krxsecd_initmsgq)) { - struct rxrpc_message *msg = NULL; - - spin_lock(&rxrpc_krxsecd_initmsgq_lock); - - if (!list_empty(&rxrpc_krxsecd_initmsgq)) { - msg = list_entry(rxrpc_krxsecd_initmsgq.next, - struct rxrpc_message, link); - list_del_init(&msg->link); - atomic_dec(&rxrpc_krxsecd_qcount); - } - - spin_unlock(&rxrpc_krxsecd_initmsgq_lock); - - if (msg) { - rxrpc_krxsecd_process_incoming_call(msg); - rxrpc_put_message(msg); - } - } - - _debug("### End Inbound Calls"); - - try_to_freeze(); - - /* discard pending signals */ - rxrpc_discard_my_signals(); - - } while (!die); - - /* and that's all */ - complete_and_exit(&rxrpc_krxsecd_dead, 0); - -} /* end rxrpc_krxsecd() */ - -/*****************************************************************************/ -/* - * start up a krxsecd daemon - */ -int __init rxrpc_krxsecd_init(void) -{ - return kernel_thread(rxrpc_krxsecd, NULL, 0); - -} /* end rxrpc_krxsecd_init() */ - -/*****************************************************************************/ -/* - * kill the krxsecd daemon and wait for it to complete - */ -void rxrpc_krxsecd_kill(void) -{ - rxrpc_krxsecd_die = 1; - wake_up_all(&rxrpc_krxsecd_sleepq); - wait_for_completion(&rxrpc_krxsecd_dead); - -} /* end rxrpc_krxsecd_kill() */ - -/*****************************************************************************/ -/* - * clear all pending incoming calls for the specified transport - */ -void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans) -{ - LIST_HEAD(tmp); - - struct rxrpc_message *msg; - struct list_head *_p, *_n; - - _enter("%p",trans); - - /* move all the messages for this transport onto a temp list */ - spin_lock(&rxrpc_krxsecd_initmsgq_lock); - - list_for_each_safe(_p, _n, &rxrpc_krxsecd_initmsgq) { - msg = list_entry(_p, struct rxrpc_message, link); - if (msg->trans == trans) { - list_move_tail(&msg->link, &tmp); - atomic_dec(&rxrpc_krxsecd_qcount); - } - } - - spin_unlock(&rxrpc_krxsecd_initmsgq_lock); - - /* zap all messages on the temp list */ - while (!list_empty(&tmp)) { - msg = list_entry(tmp.next, struct rxrpc_message, link); - list_del_init(&msg->link); - rxrpc_put_message(msg); - } - - _leave(""); -} /* end rxrpc_krxsecd_clear_transport() */ - -/*****************************************************************************/ -/* - * queue a message on the incoming calls list - */ -void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg) -{ - _enter("%p", msg); - - /* queue for processing by krxsecd */ - spin_lock(&rxrpc_krxsecd_initmsgq_lock); - - if (!rxrpc_krxsecd_die) { - rxrpc_get_message(msg); - list_add_tail(&msg->link, &rxrpc_krxsecd_initmsgq); - atomic_inc(&rxrpc_krxsecd_qcount); - } - - spin_unlock(&rxrpc_krxsecd_initmsgq_lock); - - wake_up(&rxrpc_krxsecd_sleepq); - - _leave(""); -} /* end rxrpc_krxsecd_queue_incoming_call() */ - -/*****************************************************************************/ -/* - * process the initial message of an incoming call - */ -void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg) -{ - struct rxrpc_transport *trans = msg->trans; - struct rxrpc_service *srv; - struct rxrpc_call *call; - struct list_head *_p; - unsigned short sid; - int ret; - - _enter("%p{tr=%p}", msg, trans); - - ret = rxrpc_incoming_call(msg->conn, msg, &call); - if (ret < 0) - goto out; - - /* find the matching service on the transport */ - sid = ntohs(msg->hdr.serviceId); - srv = NULL; - - spin_lock(&trans->lock); - list_for_each(_p, &trans->services) { - srv = list_entry(_p, struct rxrpc_service, link); - if (srv->service_id == sid && try_module_get(srv->owner)) { - /* found a match (made sure it won't vanish) */ - _debug("found service '%s'", srv->name); - call->owner = srv->owner; - break; - } - } - spin_unlock(&trans->lock); - - /* report the new connection - * - the func must inc the call's usage count to keep it - */ - ret = -ENOENT; - if (_p != &trans->services) { - /* attempt to accept the call */ - call->conn->service = srv; - call->app_attn_func = srv->attn_func; - call->app_error_func = srv->error_func; - call->app_aemap_func = srv->aemap_func; - - ret = srv->new_call(call); - - /* send an abort if an error occurred */ - if (ret < 0) { - rxrpc_call_abort(call, ret); - } - else { - /* formally receive and ACK the new packet */ - ret = rxrpc_conn_receive_call_packet(call->conn, - call, msg); - } - } - - rxrpc_put_call(call); - out: - if (ret < 0) - rxrpc_trans_immediate_abort(trans, msg, ret); - - _leave(" (%d)", ret); -} /* end rxrpc_krxsecd_process_incoming_call() */ diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c deleted file mode 100644 index 9a9b6132dba4..000000000000 --- a/net/rxrpc/krxtimod.c +++ /dev/null @@ -1,204 +0,0 @@ -/* krxtimod.c: RXRPC timeout daemon - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static DECLARE_COMPLETION(krxtimod_alive); -static DECLARE_COMPLETION(krxtimod_dead); -static DECLARE_WAIT_QUEUE_HEAD(krxtimod_sleepq); -static int krxtimod_die; - -static LIST_HEAD(krxtimod_list); -static DEFINE_SPINLOCK(krxtimod_lock); - -static int krxtimod(void *arg); - -/*****************************************************************************/ -/* - * start the timeout daemon - */ -int rxrpc_krxtimod_start(void) -{ - int ret; - - ret = kernel_thread(krxtimod, NULL, 0); - if (ret < 0) - return ret; - - wait_for_completion(&krxtimod_alive); - - return ret; -} /* end rxrpc_krxtimod_start() */ - -/*****************************************************************************/ -/* - * stop the timeout daemon - */ -void rxrpc_krxtimod_kill(void) -{ - /* get rid of my daemon */ - krxtimod_die = 1; - wake_up(&krxtimod_sleepq); - wait_for_completion(&krxtimod_dead); - -} /* end rxrpc_krxtimod_kill() */ - -/*****************************************************************************/ -/* - * timeout processing daemon - */ -static int krxtimod(void *arg) -{ - DECLARE_WAITQUEUE(myself, current); - - rxrpc_timer_t *timer; - - printk("Started krxtimod %d\n", current->pid); - - daemonize("krxtimod"); - - complete(&krxtimod_alive); - - /* loop around looking for things to attend to */ - loop: - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&krxtimod_sleepq, &myself); - - for (;;) { - unsigned long jif; - long timeout; - - /* deal with the server being asked to die */ - if (krxtimod_die) { - remove_wait_queue(&krxtimod_sleepq, &myself); - _leave(""); - complete_and_exit(&krxtimod_dead, 0); - } - - try_to_freeze(); - - /* discard pending signals */ - rxrpc_discard_my_signals(); - - /* work out the time to elapse before the next event */ - spin_lock(&krxtimod_lock); - if (list_empty(&krxtimod_list)) { - timeout = MAX_SCHEDULE_TIMEOUT; - } - else { - timer = list_entry(krxtimod_list.next, - rxrpc_timer_t, link); - timeout = timer->timo_jif; - jif = jiffies; - - if (time_before_eq((unsigned long) timeout, jif)) - goto immediate; - - else { - timeout = (long) timeout - (long) jiffies; - } - } - spin_unlock(&krxtimod_lock); - - schedule_timeout(timeout); - - set_current_state(TASK_INTERRUPTIBLE); - } - - /* the thing on the front of the queue needs processing - * - we come here with the lock held and timer pointing to the expired - * entry - */ - immediate: - remove_wait_queue(&krxtimod_sleepq, &myself); - set_current_state(TASK_RUNNING); - - _debug("@@@ Begin Timeout of %p", timer); - - /* dequeue the timer */ - list_del_init(&timer->link); - spin_unlock(&krxtimod_lock); - - /* call the timeout function */ - timer->ops->timed_out(timer); - - _debug("@@@ End Timeout"); - goto loop; - -} /* end krxtimod() */ - -/*****************************************************************************/ -/* - * (re-)queue a timer - */ -void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout) -{ - struct list_head *_p; - rxrpc_timer_t *ptimer; - - _enter("%p,%lu", timer, timeout); - - spin_lock(&krxtimod_lock); - - list_del(&timer->link); - - /* the timer was deferred or reset - put it back in the queue at the - * right place */ - timer->timo_jif = jiffies + timeout; - - list_for_each(_p, &krxtimod_list) { - ptimer = list_entry(_p, rxrpc_timer_t, link); - if (time_before(timer->timo_jif, ptimer->timo_jif)) - break; - } - - list_add_tail(&timer->link, _p); /* insert before stopping point */ - - spin_unlock(&krxtimod_lock); - - wake_up(&krxtimod_sleepq); - - _leave(""); -} /* end rxrpc_krxtimod_add_timer() */ - -/*****************************************************************************/ -/* - * dequeue a timer - * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued - */ -int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer) -{ - int ret = 0; - - _enter("%p", timer); - - spin_lock(&krxtimod_lock); - - if (list_empty(&timer->link)) - ret = -ENOENT; - else - list_del_init(&timer->link); - - spin_unlock(&krxtimod_lock); - - wake_up(&krxtimod_sleepq); - - _leave(" = %d", ret); - return ret; -} /* end rxrpc_krxtimod_del_timer() */ diff --git a/net/rxrpc/main.c b/net/rxrpc/main.c deleted file mode 100644 index cead31b5bdf5..000000000000 --- a/net/rxrpc/main.c +++ /dev/null @@ -1,180 +0,0 @@ -/* main.c: Rx RPC interface - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -MODULE_DESCRIPTION("Rx RPC implementation"); -MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); - -__be32 rxrpc_epoch; - -/*****************************************************************************/ -/* - * initialise the Rx module - */ -static int __init rxrpc_initialise(void) -{ - int ret; - - /* my epoch value */ - rxrpc_epoch = htonl(get_seconds()); - - /* register the /proc interface */ -#ifdef CONFIG_PROC_FS - ret = rxrpc_proc_init(); - if (ret<0) - return ret; -#endif - - /* register the sysctl files */ -#ifdef CONFIG_SYSCTL - ret = rxrpc_sysctl_init(); - if (ret<0) - goto error_proc; -#endif - - /* start the krxtimod daemon */ - ret = rxrpc_krxtimod_start(); - if (ret<0) - goto error_sysctl; - - /* start the krxiod daemon */ - ret = rxrpc_krxiod_init(); - if (ret<0) - goto error_krxtimod; - - /* start the krxsecd daemon */ - ret = rxrpc_krxsecd_init(); - if (ret<0) - goto error_krxiod; - - kdebug("\n\n"); - - return 0; - - error_krxiod: - rxrpc_krxiod_kill(); - error_krxtimod: - rxrpc_krxtimod_kill(); - error_sysctl: -#ifdef CONFIG_SYSCTL - rxrpc_sysctl_cleanup(); - error_proc: -#endif -#ifdef CONFIG_PROC_FS - rxrpc_proc_cleanup(); -#endif - return ret; -} /* end rxrpc_initialise() */ - -module_init(rxrpc_initialise); - -/*****************************************************************************/ -/* - * clean up the Rx module - */ -static void __exit rxrpc_cleanup(void) -{ - kenter(""); - - __RXACCT(printk("Outstanding Messages : %d\n", - atomic_read(&rxrpc_message_count))); - __RXACCT(printk("Outstanding Calls : %d\n", - atomic_read(&rxrpc_call_count))); - __RXACCT(printk("Outstanding Connections: %d\n", - atomic_read(&rxrpc_connection_count))); - __RXACCT(printk("Outstanding Peers : %d\n", - atomic_read(&rxrpc_peer_count))); - __RXACCT(printk("Outstanding Transports : %d\n", - atomic_read(&rxrpc_transport_count))); - - rxrpc_krxsecd_kill(); - rxrpc_krxiod_kill(); - rxrpc_krxtimod_kill(); -#ifdef CONFIG_SYSCTL - rxrpc_sysctl_cleanup(); -#endif -#ifdef CONFIG_PROC_FS - rxrpc_proc_cleanup(); -#endif - - __RXACCT(printk("Outstanding Messages : %d\n", - atomic_read(&rxrpc_message_count))); - __RXACCT(printk("Outstanding Calls : %d\n", - atomic_read(&rxrpc_call_count))); - __RXACCT(printk("Outstanding Connections: %d\n", - atomic_read(&rxrpc_connection_count))); - __RXACCT(printk("Outstanding Peers : %d\n", - atomic_read(&rxrpc_peer_count))); - __RXACCT(printk("Outstanding Transports : %d\n", - atomic_read(&rxrpc_transport_count))); - - kleave(""); -} /* end rxrpc_cleanup() */ - -module_exit(rxrpc_cleanup); - -/*****************************************************************************/ -/* - * clear the dead space between task_struct and kernel stack - * - called by supplying -finstrument-functions to gcc - */ -#if 0 -void __cyg_profile_func_enter (void *this_fn, void *call_site) -__attribute__((no_instrument_function)); - -void __cyg_profile_func_enter (void *this_fn, void *call_site) -{ - asm volatile(" movl %%esp,%%edi \n" - " andl %0,%%edi \n" - " addl %1,%%edi \n" - " movl %%esp,%%ecx \n" - " subl %%edi,%%ecx \n" - " shrl $2,%%ecx \n" - " movl $0xedededed,%%eax \n" - " rep stosl \n" - : - : "i"(~(THREAD_SIZE-1)), "i"(sizeof(struct thread_info)) - : "eax", "ecx", "edi", "memory", "cc" - ); -} - -void __cyg_profile_func_exit(void *this_fn, void *call_site) -__attribute__((no_instrument_function)); - -void __cyg_profile_func_exit(void *this_fn, void *call_site) -{ - asm volatile(" movl %%esp,%%edi \n" - " andl %0,%%edi \n" - " addl %1,%%edi \n" - " movl %%esp,%%ecx \n" - " subl %%edi,%%ecx \n" - " shrl $2,%%ecx \n" - " movl $0xdadadada,%%eax \n" - " rep stosl \n" - : - : "i"(~(THREAD_SIZE-1)), "i"(sizeof(struct thread_info)) - : "eax", "ecx", "edi", "memory", "cc" - ); -} -#endif diff --git a/net/rxrpc/peer.c b/net/rxrpc/peer.c deleted file mode 100644 index 8a275157a3bb..000000000000 --- a/net/rxrpc/peer.c +++ /dev/null @@ -1,398 +0,0 @@ -/* peer.c: Rx RPC peer management - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -__RXACCT_DECL(atomic_t rxrpc_peer_count); -LIST_HEAD(rxrpc_peers); -DECLARE_RWSEM(rxrpc_peers_sem); -unsigned long rxrpc_peer_timeout = 12 * 60 * 60; - -static void rxrpc_peer_do_timeout(struct rxrpc_peer *peer); - -static void __rxrpc_peer_timeout(rxrpc_timer_t *timer) -{ - struct rxrpc_peer *peer = - list_entry(timer, struct rxrpc_peer, timeout); - - _debug("Rx PEER TIMEOUT [%p{u=%d}]", peer, atomic_read(&peer->usage)); - - rxrpc_peer_do_timeout(peer); -} - -static const struct rxrpc_timer_ops rxrpc_peer_timer_ops = { - .timed_out = __rxrpc_peer_timeout, -}; - -/*****************************************************************************/ -/* - * create a peer record - */ -static int __rxrpc_create_peer(struct rxrpc_transport *trans, __be32 addr, - struct rxrpc_peer **_peer) -{ - struct rxrpc_peer *peer; - - _enter("%p,%08x", trans, ntohl(addr)); - - /* allocate and initialise a peer record */ - peer = kzalloc(sizeof(struct rxrpc_peer), GFP_KERNEL); - if (!peer) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - atomic_set(&peer->usage, 1); - - INIT_LIST_HEAD(&peer->link); - INIT_LIST_HEAD(&peer->proc_link); - INIT_LIST_HEAD(&peer->conn_idlist); - INIT_LIST_HEAD(&peer->conn_active); - INIT_LIST_HEAD(&peer->conn_graveyard); - spin_lock_init(&peer->conn_gylock); - init_waitqueue_head(&peer->conn_gy_waitq); - rwlock_init(&peer->conn_idlock); - rwlock_init(&peer->conn_lock); - atomic_set(&peer->conn_count, 0); - spin_lock_init(&peer->lock); - rxrpc_timer_init(&peer->timeout, &rxrpc_peer_timer_ops); - - peer->addr.s_addr = addr; - - peer->trans = trans; - peer->ops = trans->peer_ops; - - __RXACCT(atomic_inc(&rxrpc_peer_count)); - *_peer = peer; - _leave(" = 0 (%p)", peer); - - return 0; -} /* end __rxrpc_create_peer() */ - -/*****************************************************************************/ -/* - * find a peer record on the specified transport - * - returns (if successful) with peer record usage incremented - * - resurrects it from the graveyard if found there - */ -int rxrpc_peer_lookup(struct rxrpc_transport *trans, __be32 addr, - struct rxrpc_peer **_peer) -{ - struct rxrpc_peer *peer, *candidate = NULL; - struct list_head *_p; - int ret; - - _enter("%p{%hu},%08x", trans, trans->port, ntohl(addr)); - - /* [common case] search the transport's active list first */ - read_lock(&trans->peer_lock); - list_for_each(_p, &trans->peer_active) { - peer = list_entry(_p, struct rxrpc_peer, link); - if (peer->addr.s_addr == addr) - goto found_active; - } - read_unlock(&trans->peer_lock); - - /* [uncommon case] not active - create a candidate for a new record */ - ret = __rxrpc_create_peer(trans, addr, &candidate); - if (ret < 0) { - _leave(" = %d", ret); - return ret; - } - - /* search the active list again, just in case it appeared whilst we - * were busy */ - write_lock(&trans->peer_lock); - list_for_each(_p, &trans->peer_active) { - peer = list_entry(_p, struct rxrpc_peer, link); - if (peer->addr.s_addr == addr) - goto found_active_second_chance; - } - - /* search the transport's graveyard list */ - spin_lock(&trans->peer_gylock); - list_for_each(_p, &trans->peer_graveyard) { - peer = list_entry(_p, struct rxrpc_peer, link); - if (peer->addr.s_addr == addr) - goto found_in_graveyard; - } - spin_unlock(&trans->peer_gylock); - - /* we can now add the new candidate to the list - * - tell the application layer that this peer has been added - */ - rxrpc_get_transport(trans); - peer = candidate; - candidate = NULL; - - if (peer->ops && peer->ops->adding) { - ret = peer->ops->adding(peer); - if (ret < 0) { - write_unlock(&trans->peer_lock); - __RXACCT(atomic_dec(&rxrpc_peer_count)); - kfree(peer); - rxrpc_put_transport(trans); - _leave(" = %d", ret); - return ret; - } - } - - atomic_inc(&trans->peer_count); - - make_active: - list_add_tail(&peer->link, &trans->peer_active); - - success_uwfree: - write_unlock(&trans->peer_lock); - - if (candidate) { - __RXACCT(atomic_dec(&rxrpc_peer_count)); - kfree(candidate); - } - - if (list_empty(&peer->proc_link)) { - down_write(&rxrpc_peers_sem); - list_add_tail(&peer->proc_link, &rxrpc_peers); - up_write(&rxrpc_peers_sem); - } - - success: - *_peer = peer; - - _leave(" = 0 (%p{u=%d cc=%d})", - peer, - atomic_read(&peer->usage), - atomic_read(&peer->conn_count)); - return 0; - - /* handle the peer being found in the active list straight off */ - found_active: - rxrpc_get_peer(peer); - read_unlock(&trans->peer_lock); - goto success; - - /* handle resurrecting a peer from the graveyard */ - found_in_graveyard: - rxrpc_get_peer(peer); - rxrpc_get_transport(peer->trans); - rxrpc_krxtimod_del_timer(&peer->timeout); - list_del_init(&peer->link); - spin_unlock(&trans->peer_gylock); - goto make_active; - - /* handle finding the peer on the second time through the active - * list */ - found_active_second_chance: - rxrpc_get_peer(peer); - goto success_uwfree; - -} /* end rxrpc_peer_lookup() */ - -/*****************************************************************************/ -/* - * finish with a peer record - * - it gets sent to the graveyard from where it can be resurrected or timed - * out - */ -void rxrpc_put_peer(struct rxrpc_peer *peer) -{ - struct rxrpc_transport *trans = peer->trans; - - _enter("%p{cc=%d a=%08x}", - peer, - atomic_read(&peer->conn_count), - ntohl(peer->addr.s_addr)); - - /* sanity check */ - if (atomic_read(&peer->usage) <= 0) - BUG(); - - write_lock(&trans->peer_lock); - spin_lock(&trans->peer_gylock); - if (likely(!atomic_dec_and_test(&peer->usage))) { - spin_unlock(&trans->peer_gylock); - write_unlock(&trans->peer_lock); - _leave(""); - return; - } - - /* move to graveyard queue */ - list_del(&peer->link); - write_unlock(&trans->peer_lock); - - list_add_tail(&peer->link, &trans->peer_graveyard); - - BUG_ON(!list_empty(&peer->conn_active)); - - rxrpc_krxtimod_add_timer(&peer->timeout, rxrpc_peer_timeout * HZ); - - spin_unlock(&trans->peer_gylock); - - rxrpc_put_transport(trans); - - _leave(" [killed]"); -} /* end rxrpc_put_peer() */ - -/*****************************************************************************/ -/* - * handle a peer timing out in the graveyard - * - called from krxtimod - */ -static void rxrpc_peer_do_timeout(struct rxrpc_peer *peer) -{ - struct rxrpc_transport *trans = peer->trans; - - _enter("%p{u=%d cc=%d a=%08x}", - peer, - atomic_read(&peer->usage), - atomic_read(&peer->conn_count), - ntohl(peer->addr.s_addr)); - - BUG_ON(atomic_read(&peer->usage) < 0); - - /* remove from graveyard if still dead */ - spin_lock(&trans->peer_gylock); - if (atomic_read(&peer->usage) == 0) - list_del_init(&peer->link); - else - peer = NULL; - spin_unlock(&trans->peer_gylock); - - if (!peer) { - _leave(""); - return; /* resurrected */ - } - - /* clear all connections on this peer */ - rxrpc_conn_clearall(peer); - - BUG_ON(!list_empty(&peer->conn_active)); - BUG_ON(!list_empty(&peer->conn_graveyard)); - - /* inform the application layer */ - if (peer->ops && peer->ops->discarding) - peer->ops->discarding(peer); - - if (!list_empty(&peer->proc_link)) { - down_write(&rxrpc_peers_sem); - list_del(&peer->proc_link); - up_write(&rxrpc_peers_sem); - } - - __RXACCT(atomic_dec(&rxrpc_peer_count)); - kfree(peer); - - /* if the graveyard is now empty, wake up anyone waiting for that */ - if (atomic_dec_and_test(&trans->peer_count)) - wake_up(&trans->peer_gy_waitq); - - _leave(" [destroyed]"); -} /* end rxrpc_peer_do_timeout() */ - -/*****************************************************************************/ -/* - * clear all peer records from a transport endpoint - */ -void rxrpc_peer_clearall(struct rxrpc_transport *trans) -{ - DECLARE_WAITQUEUE(myself,current); - - struct rxrpc_peer *peer; - int err; - - _enter("%p",trans); - - /* there shouldn't be any active peers remaining */ - BUG_ON(!list_empty(&trans->peer_active)); - - /* manually timeout all peers in the graveyard */ - spin_lock(&trans->peer_gylock); - while (!list_empty(&trans->peer_graveyard)) { - peer = list_entry(trans->peer_graveyard.next, - struct rxrpc_peer, link); - _debug("Clearing peer %p\n", peer); - err = rxrpc_krxtimod_del_timer(&peer->timeout); - spin_unlock(&trans->peer_gylock); - - if (err == 0) - rxrpc_peer_do_timeout(peer); - - spin_lock(&trans->peer_gylock); - } - spin_unlock(&trans->peer_gylock); - - /* wait for the the peer graveyard to be completely cleared */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&trans->peer_gy_waitq, &myself); - - while (atomic_read(&trans->peer_count) != 0) { - schedule(); - set_current_state(TASK_UNINTERRUPTIBLE); - } - - remove_wait_queue(&trans->peer_gy_waitq, &myself); - set_current_state(TASK_RUNNING); - - _leave(""); -} /* end rxrpc_peer_clearall() */ - -/*****************************************************************************/ -/* - * calculate and cache the Round-Trip-Time for a message and its response - */ -void rxrpc_peer_calculate_rtt(struct rxrpc_peer *peer, - struct rxrpc_message *msg, - struct rxrpc_message *resp) -{ - unsigned long long rtt; - int loop; - - _enter("%p,%p,%p", peer, msg, resp); - - /* calculate the latest RTT */ - rtt = resp->stamp.tv_sec - msg->stamp.tv_sec; - rtt *= 1000000UL; - rtt += resp->stamp.tv_usec - msg->stamp.tv_usec; - - /* add to cache */ - peer->rtt_cache[peer->rtt_point] = rtt; - peer->rtt_point++; - peer->rtt_point %= RXRPC_RTT_CACHE_SIZE; - - if (peer->rtt_usage < RXRPC_RTT_CACHE_SIZE) - peer->rtt_usage++; - - /* recalculate RTT */ - rtt = 0; - for (loop = peer->rtt_usage - 1; loop >= 0; loop--) - rtt += peer->rtt_cache[loop]; - - do_div(rtt, peer->rtt_usage); - peer->rtt = rtt; - - _leave(" RTT=%lu.%lums", - (long) (peer->rtt / 1000), (long) (peer->rtt % 1000)); - -} /* end rxrpc_peer_calculate_rtt() */ diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c deleted file mode 100644 index 8551c879e456..000000000000 --- a/net/rxrpc/proc.c +++ /dev/null @@ -1,617 +0,0 @@ -/* proc.c: /proc interface for RxRPC - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static struct proc_dir_entry *proc_rxrpc; - -static int rxrpc_proc_transports_open(struct inode *inode, struct file *file); -static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos); -static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos); -static void rxrpc_proc_transports_stop(struct seq_file *p, void *v); -static int rxrpc_proc_transports_show(struct seq_file *m, void *v); - -static struct seq_operations rxrpc_proc_transports_ops = { - .start = rxrpc_proc_transports_start, - .next = rxrpc_proc_transports_next, - .stop = rxrpc_proc_transports_stop, - .show = rxrpc_proc_transports_show, -}; - -static const struct file_operations rxrpc_proc_transports_fops = { - .open = rxrpc_proc_transports_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int rxrpc_proc_peers_open(struct inode *inode, struct file *file); -static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos); -static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos); -static void rxrpc_proc_peers_stop(struct seq_file *p, void *v); -static int rxrpc_proc_peers_show(struct seq_file *m, void *v); - -static struct seq_operations rxrpc_proc_peers_ops = { - .start = rxrpc_proc_peers_start, - .next = rxrpc_proc_peers_next, - .stop = rxrpc_proc_peers_stop, - .show = rxrpc_proc_peers_show, -}; - -static const struct file_operations rxrpc_proc_peers_fops = { - .open = rxrpc_proc_peers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int rxrpc_proc_conns_open(struct inode *inode, struct file *file); -static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos); -static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos); -static void rxrpc_proc_conns_stop(struct seq_file *p, void *v); -static int rxrpc_proc_conns_show(struct seq_file *m, void *v); - -static struct seq_operations rxrpc_proc_conns_ops = { - .start = rxrpc_proc_conns_start, - .next = rxrpc_proc_conns_next, - .stop = rxrpc_proc_conns_stop, - .show = rxrpc_proc_conns_show, -}; - -static const struct file_operations rxrpc_proc_conns_fops = { - .open = rxrpc_proc_conns_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int rxrpc_proc_calls_open(struct inode *inode, struct file *file); -static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos); -static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos); -static void rxrpc_proc_calls_stop(struct seq_file *p, void *v); -static int rxrpc_proc_calls_show(struct seq_file *m, void *v); - -static struct seq_operations rxrpc_proc_calls_ops = { - .start = rxrpc_proc_calls_start, - .next = rxrpc_proc_calls_next, - .stop = rxrpc_proc_calls_stop, - .show = rxrpc_proc_calls_show, -}; - -static const struct file_operations rxrpc_proc_calls_fops = { - .open = rxrpc_proc_calls_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const char *rxrpc_call_states7[] = { - "complet", - "error ", - "rcv_op ", - "rcv_arg", - "got_arg", - "snd_rpl", - "fin_ack", - "snd_arg", - "rcv_rpl", - "got_rpl" -}; - -static const char *rxrpc_call_error_states7[] = { - "no_err ", - "loc_abt", - "rmt_abt", - "loc_err", - "rmt_err" -}; - -/*****************************************************************************/ -/* - * initialise the /proc/net/rxrpc/ directory - */ -int rxrpc_proc_init(void) -{ - struct proc_dir_entry *p; - - proc_rxrpc = proc_mkdir("rxrpc", proc_net); - if (!proc_rxrpc) - goto error; - proc_rxrpc->owner = THIS_MODULE; - - p = create_proc_entry("calls", 0, proc_rxrpc); - if (!p) - goto error_proc; - p->proc_fops = &rxrpc_proc_calls_fops; - p->owner = THIS_MODULE; - - p = create_proc_entry("connections", 0, proc_rxrpc); - if (!p) - goto error_calls; - p->proc_fops = &rxrpc_proc_conns_fops; - p->owner = THIS_MODULE; - - p = create_proc_entry("peers", 0, proc_rxrpc); - if (!p) - goto error_calls; - p->proc_fops = &rxrpc_proc_peers_fops; - p->owner = THIS_MODULE; - - p = create_proc_entry("transports", 0, proc_rxrpc); - if (!p) - goto error_conns; - p->proc_fops = &rxrpc_proc_transports_fops; - p->owner = THIS_MODULE; - - return 0; - - error_conns: - remove_proc_entry("connections", proc_rxrpc); - error_calls: - remove_proc_entry("calls", proc_rxrpc); - error_proc: - remove_proc_entry("rxrpc", proc_net); - error: - return -ENOMEM; -} /* end rxrpc_proc_init() */ - -/*****************************************************************************/ -/* - * clean up the /proc/net/rxrpc/ directory - */ -void rxrpc_proc_cleanup(void) -{ - remove_proc_entry("transports", proc_rxrpc); - remove_proc_entry("peers", proc_rxrpc); - remove_proc_entry("connections", proc_rxrpc); - remove_proc_entry("calls", proc_rxrpc); - - remove_proc_entry("rxrpc", proc_net); - -} /* end rxrpc_proc_cleanup() */ - -/*****************************************************************************/ -/* - * open "/proc/net/rxrpc/transports" which provides a summary of extant transports - */ -static int rxrpc_proc_transports_open(struct inode *inode, struct file *file) -{ - struct seq_file *m; - int ret; - - ret = seq_open(file, &rxrpc_proc_transports_ops); - if (ret < 0) - return ret; - - m = file->private_data; - m->private = PDE(inode)->data; - - return 0; -} /* end rxrpc_proc_transports_open() */ - -/*****************************************************************************/ -/* - * set up the iterator to start reading from the transports list and return the first item - */ -static void *rxrpc_proc_transports_start(struct seq_file *m, loff_t *_pos) -{ - struct list_head *_p; - loff_t pos = *_pos; - - /* lock the list against modification */ - down_read(&rxrpc_proc_transports_sem); - - /* allow for the header line */ - if (!pos) - return SEQ_START_TOKEN; - pos--; - - /* find the n'th element in the list */ - list_for_each(_p, &rxrpc_proc_transports) - if (!pos--) - break; - - return _p != &rxrpc_proc_transports ? _p : NULL; -} /* end rxrpc_proc_transports_start() */ - -/*****************************************************************************/ -/* - * move to next call in transports list - */ -static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos) -{ - struct list_head *_p; - - (*pos)++; - - _p = v; - _p = (v == SEQ_START_TOKEN) ? rxrpc_proc_transports.next : _p->next; - - return _p != &rxrpc_proc_transports ? _p : NULL; -} /* end rxrpc_proc_transports_next() */ - -/*****************************************************************************/ -/* - * clean up after reading from the transports list - */ -static void rxrpc_proc_transports_stop(struct seq_file *p, void *v) -{ - up_read(&rxrpc_proc_transports_sem); - -} /* end rxrpc_proc_transports_stop() */ - -/*****************************************************************************/ -/* - * display a header line followed by a load of call lines - */ -static int rxrpc_proc_transports_show(struct seq_file *m, void *v) -{ - struct rxrpc_transport *trans = - list_entry(v, struct rxrpc_transport, proc_link); - - /* display header on line 1 */ - if (v == SEQ_START_TOKEN) { - seq_puts(m, "LOCAL USE\n"); - return 0; - } - - /* display one transport per line on subsequent lines */ - seq_printf(m, "%5hu %3d\n", - trans->port, - atomic_read(&trans->usage) - ); - - return 0; -} /* end rxrpc_proc_transports_show() */ - -/*****************************************************************************/ -/* - * open "/proc/net/rxrpc/peers" which provides a summary of extant peers - */ -static int rxrpc_proc_peers_open(struct inode *inode, struct file *file) -{ - struct seq_file *m; - int ret; - - ret = seq_open(file, &rxrpc_proc_peers_ops); - if (ret < 0) - return ret; - - m = file->private_data; - m->private = PDE(inode)->data; - - return 0; -} /* end rxrpc_proc_peers_open() */ - -/*****************************************************************************/ -/* - * set up the iterator to start reading from the peers list and return the - * first item - */ -static void *rxrpc_proc_peers_start(struct seq_file *m, loff_t *_pos) -{ - struct list_head *_p; - loff_t pos = *_pos; - - /* lock the list against modification */ - down_read(&rxrpc_peers_sem); - - /* allow for the header line */ - if (!pos) - return SEQ_START_TOKEN; - pos--; - - /* find the n'th element in the list */ - list_for_each(_p, &rxrpc_peers) - if (!pos--) - break; - - return _p != &rxrpc_peers ? _p : NULL; -} /* end rxrpc_proc_peers_start() */ - -/*****************************************************************************/ -/* - * move to next conn in peers list - */ -static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos) -{ - struct list_head *_p; - - (*pos)++; - - _p = v; - _p = (v == SEQ_START_TOKEN) ? rxrpc_peers.next : _p->next; - - return _p != &rxrpc_peers ? _p : NULL; -} /* end rxrpc_proc_peers_next() */ - -/*****************************************************************************/ -/* - * clean up after reading from the peers list - */ -static void rxrpc_proc_peers_stop(struct seq_file *p, void *v) -{ - up_read(&rxrpc_peers_sem); - -} /* end rxrpc_proc_peers_stop() */ - -/*****************************************************************************/ -/* - * display a header line followed by a load of conn lines - */ -static int rxrpc_proc_peers_show(struct seq_file *m, void *v) -{ - struct rxrpc_peer *peer = list_entry(v, struct rxrpc_peer, proc_link); - long timeout; - - /* display header on line 1 */ - if (v == SEQ_START_TOKEN) { - seq_puts(m, "LOCAL REMOTE USAGE CONNS TIMEOUT" - " MTU RTT(uS)\n"); - return 0; - } - - /* display one peer per line on subsequent lines */ - timeout = 0; - if (!list_empty(&peer->timeout.link)) - timeout = (long) peer->timeout.timo_jif - - (long) jiffies; - - seq_printf(m, "%5hu %08x %5d %5d %8ld %5Zu %7lu\n", - peer->trans->port, - ntohl(peer->addr.s_addr), - atomic_read(&peer->usage), - atomic_read(&peer->conn_count), - timeout, - peer->if_mtu, - (long) peer->rtt - ); - - return 0; -} /* end rxrpc_proc_peers_show() */ - -/*****************************************************************************/ -/* - * open "/proc/net/rxrpc/connections" which provides a summary of extant - * connections - */ -static int rxrpc_proc_conns_open(struct inode *inode, struct file *file) -{ - struct seq_file *m; - int ret; - - ret = seq_open(file, &rxrpc_proc_conns_ops); - if (ret < 0) - return ret; - - m = file->private_data; - m->private = PDE(inode)->data; - - return 0; -} /* end rxrpc_proc_conns_open() */ - -/*****************************************************************************/ -/* - * set up the iterator to start reading from the conns list and return the - * first item - */ -static void *rxrpc_proc_conns_start(struct seq_file *m, loff_t *_pos) -{ - struct list_head *_p; - loff_t pos = *_pos; - - /* lock the list against modification */ - down_read(&rxrpc_conns_sem); - - /* allow for the header line */ - if (!pos) - return SEQ_START_TOKEN; - pos--; - - /* find the n'th element in the list */ - list_for_each(_p, &rxrpc_conns) - if (!pos--) - break; - - return _p != &rxrpc_conns ? _p : NULL; -} /* end rxrpc_proc_conns_start() */ - -/*****************************************************************************/ -/* - * move to next conn in conns list - */ -static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos) -{ - struct list_head *_p; - - (*pos)++; - - _p = v; - _p = (v == SEQ_START_TOKEN) ? rxrpc_conns.next : _p->next; - - return _p != &rxrpc_conns ? _p : NULL; -} /* end rxrpc_proc_conns_next() */ - -/*****************************************************************************/ -/* - * clean up after reading from the conns list - */ -static void rxrpc_proc_conns_stop(struct seq_file *p, void *v) -{ - up_read(&rxrpc_conns_sem); - -} /* end rxrpc_proc_conns_stop() */ - -/*****************************************************************************/ -/* - * display a header line followed by a load of conn lines - */ -static int rxrpc_proc_conns_show(struct seq_file *m, void *v) -{ - struct rxrpc_connection *conn; - long timeout; - - conn = list_entry(v, struct rxrpc_connection, proc_link); - - /* display header on line 1 */ - if (v == SEQ_START_TOKEN) { - seq_puts(m, - "LOCAL REMOTE RPORT SRVC CONN END SERIALNO " - "CALLNO MTU TIMEOUT" - "\n"); - return 0; - } - - /* display one conn per line on subsequent lines */ - timeout = 0; - if (!list_empty(&conn->timeout.link)) - timeout = (long) conn->timeout.timo_jif - - (long) jiffies; - - seq_printf(m, - "%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5Zu %8ld\n", - conn->trans->port, - ntohl(conn->addr.sin_addr.s_addr), - ntohs(conn->addr.sin_port), - ntohs(conn->service_id), - ntohl(conn->conn_id), - conn->out_clientflag ? "CLT" : "SRV", - conn->serial_counter, - conn->call_counter, - conn->mtu_size, - timeout - ); - - return 0; -} /* end rxrpc_proc_conns_show() */ - -/*****************************************************************************/ -/* - * open "/proc/net/rxrpc/calls" which provides a summary of extant calls - */ -static int rxrpc_proc_calls_open(struct inode *inode, struct file *file) -{ - struct seq_file *m; - int ret; - - ret = seq_open(file, &rxrpc_proc_calls_ops); - if (ret < 0) - return ret; - - m = file->private_data; - m->private = PDE(inode)->data; - - return 0; -} /* end rxrpc_proc_calls_open() */ - -/*****************************************************************************/ -/* - * set up the iterator to start reading from the calls list and return the - * first item - */ -static void *rxrpc_proc_calls_start(struct seq_file *m, loff_t *_pos) -{ - struct list_head *_p; - loff_t pos = *_pos; - - /* lock the list against modification */ - down_read(&rxrpc_calls_sem); - - /* allow for the header line */ - if (!pos) - return SEQ_START_TOKEN; - pos--; - - /* find the n'th element in the list */ - list_for_each(_p, &rxrpc_calls) - if (!pos--) - break; - - return _p != &rxrpc_calls ? _p : NULL; -} /* end rxrpc_proc_calls_start() */ - -/*****************************************************************************/ -/* - * move to next call in calls list - */ -static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos) -{ - struct list_head *_p; - - (*pos)++; - - _p = v; - _p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next; - - return _p != &rxrpc_calls ? _p : NULL; -} /* end rxrpc_proc_calls_next() */ - -/*****************************************************************************/ -/* - * clean up after reading from the calls list - */ -static void rxrpc_proc_calls_stop(struct seq_file *p, void *v) -{ - up_read(&rxrpc_calls_sem); - -} /* end rxrpc_proc_calls_stop() */ - -/*****************************************************************************/ -/* - * display a header line followed by a load of call lines - */ -static int rxrpc_proc_calls_show(struct seq_file *m, void *v) -{ - struct rxrpc_call *call = list_entry(v, struct rxrpc_call, call_link); - - /* display header on line 1 */ - if (v == SEQ_START_TOKEN) { - seq_puts(m, - "LOCAL REMOT SRVC CONN CALL DIR USE " - " L STATE OPCODE ABORT ERRNO\n" - ); - return 0; - } - - /* display one call per line on subsequent lines */ - seq_printf(m, - "%5hu %5hu %04hx %08x %08x %s %3u%c" - " %c %-7.7s %6d %08x %5d\n", - call->conn->trans->port, - ntohs(call->conn->addr.sin_port), - ntohs(call->conn->service_id), - ntohl(call->conn->conn_id), - ntohl(call->call_id), - call->conn->service ? "SVC" : "CLT", - atomic_read(&call->usage), - waitqueue_active(&call->waitq) ? 'w' : ' ', - call->app_last_rcv ? 'Y' : '-', - (call->app_call_state!=RXRPC_CSTATE_ERROR ? - rxrpc_call_states7[call->app_call_state] : - rxrpc_call_error_states7[call->app_err_state]), - call->app_opcode, - call->app_abort_code, - call->app_errno - ); - - return 0; -} /* end rxrpc_proc_calls_show() */ diff --git a/net/rxrpc/rxrpc_syms.c b/net/rxrpc/rxrpc_syms.c deleted file mode 100644 index 9896fd87a4d4..000000000000 --- a/net/rxrpc/rxrpc_syms.c +++ /dev/null @@ -1,34 +0,0 @@ -/* rxrpc_syms.c: exported Rx RPC layer interface symbols - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include - -#include -#include -#include -#include - -/* call.c */ -EXPORT_SYMBOL(rxrpc_create_call); -EXPORT_SYMBOL(rxrpc_put_call); -EXPORT_SYMBOL(rxrpc_call_abort); -EXPORT_SYMBOL(rxrpc_call_read_data); -EXPORT_SYMBOL(rxrpc_call_write_data); - -/* connection.c */ -EXPORT_SYMBOL(rxrpc_create_connection); -EXPORT_SYMBOL(rxrpc_put_connection); - -/* transport.c */ -EXPORT_SYMBOL(rxrpc_create_transport); -EXPORT_SYMBOL(rxrpc_put_transport); -EXPORT_SYMBOL(rxrpc_add_service); -EXPORT_SYMBOL(rxrpc_del_service); diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c deleted file mode 100644 index 884290754af7..000000000000 --- a/net/rxrpc/sysctl.c +++ /dev/null @@ -1,121 +0,0 @@ -/* sysctl.c: Rx RPC control - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -int rxrpc_ktrace; -int rxrpc_kdebug; -int rxrpc_kproto; -int rxrpc_knet; - -#ifdef CONFIG_SYSCTL -static struct ctl_table_header *rxrpc_sysctl = NULL; - -static ctl_table rxrpc_sysctl_table[] = { - { - .ctl_name = 1, - .procname = "kdebug", - .data = &rxrpc_kdebug, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = 2, - .procname = "ktrace", - .data = &rxrpc_ktrace, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = 3, - .procname = "kproto", - .data = &rxrpc_kproto, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = 4, - .procname = "knet", - .data = &rxrpc_knet, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = 5, - .procname = "peertimo", - .data = &rxrpc_peer_timeout, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &proc_doulongvec_minmax - }, - { - .ctl_name = 6, - .procname = "conntimo", - .data = &rxrpc_conn_timeout, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &proc_doulongvec_minmax - }, - { .ctl_name = 0 } -}; - -static ctl_table rxrpc_dir_sysctl_table[] = { - { - .ctl_name = 1, - .procname = "rxrpc", - .maxlen = 0, - .mode = 0555, - .child = rxrpc_sysctl_table - }, - { .ctl_name = 0 } -}; -#endif /* CONFIG_SYSCTL */ - -/*****************************************************************************/ -/* - * initialise the sysctl stuff for Rx RPC - */ -int rxrpc_sysctl_init(void) -{ -#ifdef CONFIG_SYSCTL - rxrpc_sysctl = register_sysctl_table(rxrpc_dir_sysctl_table); - if (!rxrpc_sysctl) - return -ENOMEM; -#endif /* CONFIG_SYSCTL */ - - return 0; -} /* end rxrpc_sysctl_init() */ - -/*****************************************************************************/ -/* - * clean up the sysctl stuff for Rx RPC - */ -void rxrpc_sysctl_cleanup(void) -{ -#ifdef CONFIG_SYSCTL - if (rxrpc_sysctl) { - unregister_sysctl_table(rxrpc_sysctl); - rxrpc_sysctl = NULL; - } -#endif /* CONFIG_SYSCTL */ - -} /* end rxrpc_sysctl_cleanup() */ diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c deleted file mode 100644 index 62398fd01f85..000000000000 --- a/net/rxrpc/transport.c +++ /dev/null @@ -1,846 +0,0 @@ -/* transport.c: Rx Transport routines - * - * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) -#include /* this should _really_ be in errqueue.h.. */ -#endif -#include -#include -#include "internal.h" - -struct errormsg { - struct cmsghdr cmsg; /* control message header */ - struct sock_extended_err ee; /* extended error information */ - struct sockaddr_in icmp_src; /* ICMP packet source address */ -}; - -static DEFINE_SPINLOCK(rxrpc_transports_lock); -static struct list_head rxrpc_transports = LIST_HEAD_INIT(rxrpc_transports); - -__RXACCT_DECL(atomic_t rxrpc_transport_count); -LIST_HEAD(rxrpc_proc_transports); -DECLARE_RWSEM(rxrpc_proc_transports_sem); - -static void rxrpc_data_ready(struct sock *sk, int count); -static void rxrpc_error_report(struct sock *sk); -static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans, - struct list_head *msgq); -static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans); - -/*****************************************************************************/ -/* - * create a new transport endpoint using the specified UDP port - */ -int rxrpc_create_transport(unsigned short port, - struct rxrpc_transport **_trans) -{ - struct rxrpc_transport *trans; - struct sockaddr_in sin; - mm_segment_t oldfs; - struct sock *sock; - int ret, opt; - - _enter("%hu", port); - - trans = kzalloc(sizeof(struct rxrpc_transport), GFP_KERNEL); - if (!trans) - return -ENOMEM; - - atomic_set(&trans->usage, 1); - INIT_LIST_HEAD(&trans->services); - INIT_LIST_HEAD(&trans->link); - INIT_LIST_HEAD(&trans->krxiodq_link); - spin_lock_init(&trans->lock); - INIT_LIST_HEAD(&trans->peer_active); - INIT_LIST_HEAD(&trans->peer_graveyard); - spin_lock_init(&trans->peer_gylock); - init_waitqueue_head(&trans->peer_gy_waitq); - rwlock_init(&trans->peer_lock); - atomic_set(&trans->peer_count, 0); - trans->port = port; - - /* create a UDP socket to be my actual transport endpoint */ - ret = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &trans->socket); - if (ret < 0) - goto error; - - /* use the specified port */ - if (port) { - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - ret = trans->socket->ops->bind(trans->socket, - (struct sockaddr *) &sin, - sizeof(sin)); - if (ret < 0) - goto error; - } - - opt = 1; - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = trans->socket->ops->setsockopt(trans->socket, SOL_IP, IP_RECVERR, - (char *) &opt, sizeof(opt)); - set_fs(oldfs); - - spin_lock(&rxrpc_transports_lock); - list_add(&trans->link, &rxrpc_transports); - spin_unlock(&rxrpc_transports_lock); - - /* set the socket up */ - sock = trans->socket->sk; - sock->sk_user_data = trans; - sock->sk_data_ready = rxrpc_data_ready; - sock->sk_error_report = rxrpc_error_report; - - down_write(&rxrpc_proc_transports_sem); - list_add_tail(&trans->proc_link, &rxrpc_proc_transports); - up_write(&rxrpc_proc_transports_sem); - - __RXACCT(atomic_inc(&rxrpc_transport_count)); - - *_trans = trans; - _leave(" = 0 (%p)", trans); - return 0; - - error: - /* finish cleaning up the transport (not really needed here, but...) */ - if (trans->socket) - trans->socket->ops->shutdown(trans->socket, 2); - - /* close the socket */ - if (trans->socket) { - trans->socket->sk->sk_user_data = NULL; - sock_release(trans->socket); - trans->socket = NULL; - } - - kfree(trans); - - - _leave(" = %d", ret); - return ret; -} /* end rxrpc_create_transport() */ - -/*****************************************************************************/ -/* - * destroy a transport endpoint - */ -void rxrpc_put_transport(struct rxrpc_transport *trans) -{ - _enter("%p{u=%d p=%hu}", - trans, atomic_read(&trans->usage), trans->port); - - BUG_ON(atomic_read(&trans->usage) <= 0); - - /* to prevent a race, the decrement and the dequeue must be - * effectively atomic */ - spin_lock(&rxrpc_transports_lock); - if (likely(!atomic_dec_and_test(&trans->usage))) { - spin_unlock(&rxrpc_transports_lock); - _leave(""); - return; - } - - list_del(&trans->link); - spin_unlock(&rxrpc_transports_lock); - - /* finish cleaning up the transport */ - if (trans->socket) - trans->socket->ops->shutdown(trans->socket, 2); - - rxrpc_krxsecd_clear_transport(trans); - rxrpc_krxiod_dequeue_transport(trans); - - /* discard all peer information */ - rxrpc_peer_clearall(trans); - - down_write(&rxrpc_proc_transports_sem); - list_del(&trans->proc_link); - up_write(&rxrpc_proc_transports_sem); - __RXACCT(atomic_dec(&rxrpc_transport_count)); - - /* close the socket */ - if (trans->socket) { - trans->socket->sk->sk_user_data = NULL; - sock_release(trans->socket); - trans->socket = NULL; - } - - kfree(trans); - - _leave(""); -} /* end rxrpc_put_transport() */ - -/*****************************************************************************/ -/* - * add a service to a transport to be listened upon - */ -int rxrpc_add_service(struct rxrpc_transport *trans, - struct rxrpc_service *newsrv) -{ - struct rxrpc_service *srv; - struct list_head *_p; - int ret = -EEXIST; - - _enter("%p{%hu},%p{%hu}", - trans, trans->port, newsrv, newsrv->service_id); - - /* verify that the service ID is not already present */ - spin_lock(&trans->lock); - - list_for_each(_p, &trans->services) { - srv = list_entry(_p, struct rxrpc_service, link); - if (srv->service_id == newsrv->service_id) - goto out; - } - - /* okay - add the transport to the list */ - list_add_tail(&newsrv->link, &trans->services); - rxrpc_get_transport(trans); - ret = 0; - - out: - spin_unlock(&trans->lock); - - _leave("= %d", ret); - return ret; -} /* end rxrpc_add_service() */ - -/*****************************************************************************/ -/* - * remove a service from a transport - */ -void rxrpc_del_service(struct rxrpc_transport *trans, struct rxrpc_service *srv) -{ - _enter("%p{%hu},%p{%hu}", trans, trans->port, srv, srv->service_id); - - spin_lock(&trans->lock); - list_del(&srv->link); - spin_unlock(&trans->lock); - - rxrpc_put_transport(trans); - - _leave(""); -} /* end rxrpc_del_service() */ - -/*****************************************************************************/ -/* - * INET callback when data has been received on the socket. - */ -static void rxrpc_data_ready(struct sock *sk, int count) -{ - struct rxrpc_transport *trans; - - _enter("%p{t=%p},%d", sk, sk->sk_user_data, count); - - /* queue the transport for attention by krxiod */ - trans = (struct rxrpc_transport *) sk->sk_user_data; - if (trans) - rxrpc_krxiod_queue_transport(trans); - - /* wake up anyone waiting on the socket */ - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); - - _leave(""); -} /* end rxrpc_data_ready() */ - -/*****************************************************************************/ -/* - * INET callback when an ICMP error packet is received - * - sk->err is error (EHOSTUNREACH, EPROTO or EMSGSIZE) - */ -static void rxrpc_error_report(struct sock *sk) -{ - struct rxrpc_transport *trans; - - _enter("%p{t=%p}", sk, sk->sk_user_data); - - /* queue the transport for attention by krxiod */ - trans = (struct rxrpc_transport *) sk->sk_user_data; - if (trans) { - trans->error_rcvd = 1; - rxrpc_krxiod_queue_transport(trans); - } - - /* wake up anyone waiting on the socket */ - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) - wake_up_interruptible(sk->sk_sleep); - - _leave(""); -} /* end rxrpc_error_report() */ - -/*****************************************************************************/ -/* - * split a message up, allocating message records and filling them in - * from the contents of a socket buffer - */ -static int rxrpc_incoming_msg(struct rxrpc_transport *trans, - struct sk_buff *pkt, - struct list_head *msgq) -{ - struct rxrpc_message *msg; - int ret; - - _enter(""); - - msg = kzalloc(sizeof(struct rxrpc_message), GFP_KERNEL); - if (!msg) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - atomic_set(&msg->usage, 1); - list_add_tail(&msg->link,msgq); - - /* dig out the Rx routing parameters */ - if (skb_copy_bits(pkt, sizeof(struct udphdr), - &msg->hdr, sizeof(msg->hdr)) < 0) { - ret = -EBADMSG; - goto error; - } - - msg->trans = trans; - msg->state = RXRPC_MSG_RECEIVED; - skb_get_timestamp(pkt, &msg->stamp); - if (msg->stamp.tv_sec == 0) { - do_gettimeofday(&msg->stamp); - if (pkt->sk) - sock_enable_timestamp(pkt->sk); - } - msg->seq = ntohl(msg->hdr.seq); - - /* attach the packet */ - skb_get(pkt); - msg->pkt = pkt; - - msg->offset = sizeof(struct udphdr) + sizeof(struct rxrpc_header); - msg->dsize = msg->pkt->len - msg->offset; - - _net("Rx Received packet from %s (%08x;%08x,%1x,%d,%s,%02x,%d,%d)", - msg->hdr.flags & RXRPC_CLIENT_INITIATED ? "client" : "server", - ntohl(msg->hdr.epoch), - (ntohl(msg->hdr.cid) & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT, - ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK, - ntohl(msg->hdr.callNumber), - rxrpc_pkts[msg->hdr.type], - msg->hdr.flags, - ntohs(msg->hdr.serviceId), - msg->hdr.securityIndex); - - __RXACCT(atomic_inc(&rxrpc_message_count)); - - /* split off jumbo packets */ - while (msg->hdr.type == RXRPC_PACKET_TYPE_DATA && - msg->hdr.flags & RXRPC_JUMBO_PACKET - ) { - struct rxrpc_jumbo_header jumbo; - struct rxrpc_message *jumbomsg = msg; - - _debug("split jumbo packet"); - - /* quick sanity check */ - ret = -EBADMSG; - if (msg->dsize < - RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header)) - goto error; - if (msg->hdr.flags & RXRPC_LAST_PACKET) - goto error; - - /* dig out the secondary header */ - if (skb_copy_bits(pkt, msg->offset + RXRPC_JUMBO_DATALEN, - &jumbo, sizeof(jumbo)) < 0) - goto error; - - /* allocate a new message record */ - ret = -ENOMEM; - msg = kmemdup(jumbomsg, sizeof(struct rxrpc_message), GFP_KERNEL); - if (!msg) - goto error; - - list_add_tail(&msg->link, msgq); - - /* adjust the jumbo packet */ - jumbomsg->dsize = RXRPC_JUMBO_DATALEN; - - /* attach the packet here too */ - skb_get(pkt); - - /* adjust the parameters */ - msg->seq++; - msg->hdr.seq = htonl(msg->seq); - msg->hdr.serial = htonl(ntohl(msg->hdr.serial) + 1); - msg->offset += RXRPC_JUMBO_DATALEN + - sizeof(struct rxrpc_jumbo_header); - msg->dsize -= RXRPC_JUMBO_DATALEN + - sizeof(struct rxrpc_jumbo_header); - msg->hdr.flags = jumbo.flags; - msg->hdr._rsvd = jumbo._rsvd; - - _net("Rx Split jumbo packet from %s" - " (%08x;%08x,%1x,%d,%s,%02x,%d,%d)", - msg->hdr.flags & RXRPC_CLIENT_INITIATED ? "client" : "server", - ntohl(msg->hdr.epoch), - (ntohl(msg->hdr.cid) & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT, - ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK, - ntohl(msg->hdr.callNumber), - rxrpc_pkts[msg->hdr.type], - msg->hdr.flags, - ntohs(msg->hdr.serviceId), - msg->hdr.securityIndex); - - __RXACCT(atomic_inc(&rxrpc_message_count)); - } - - _leave(" = 0 #%d", atomic_read(&rxrpc_message_count)); - return 0; - - error: - while (!list_empty(msgq)) { - msg = list_entry(msgq->next, struct rxrpc_message, link); - list_del_init(&msg->link); - - rxrpc_put_message(msg); - } - - _leave(" = %d", ret); - return ret; -} /* end rxrpc_incoming_msg() */ - -/*****************************************************************************/ -/* - * accept a new call - * - called from krxiod in process context - */ -void rxrpc_trans_receive_packet(struct rxrpc_transport *trans) -{ - struct rxrpc_message *msg; - struct rxrpc_peer *peer; - struct sk_buff *pkt; - int ret; - __be32 addr; - __be16 port; - - LIST_HEAD(msgq); - - _enter("%p{%d}", trans, trans->port); - - for (;;) { - /* deal with outstanting errors first */ - if (trans->error_rcvd) - rxrpc_trans_receive_error_report(trans); - - /* attempt to receive a packet */ - pkt = skb_recv_datagram(trans->socket->sk, 0, 1, &ret); - if (!pkt) { - if (ret == -EAGAIN) { - _leave(" EAGAIN"); - return; - } - - /* an icmp error may have occurred */ - rxrpc_krxiod_queue_transport(trans); - _leave(" error %d\n", ret); - return; - } - - /* we'll probably need to checksum it (didn't call - * sock_recvmsg) */ - if (skb_checksum_complete(pkt)) { - kfree_skb(pkt); - rxrpc_krxiod_queue_transport(trans); - _leave(" CSUM failed"); - return; - } - - addr = ip_hdr(pkt)->saddr; - port = udp_hdr(pkt)->source; - - _net("Rx Received UDP packet from %08x:%04hu", - ntohl(addr), ntohs(port)); - - /* unmarshall the Rx parameters and split jumbo packets */ - ret = rxrpc_incoming_msg(trans, pkt, &msgq); - if (ret < 0) { - kfree_skb(pkt); - rxrpc_krxiod_queue_transport(trans); - _leave(" bad packet"); - return; - } - - BUG_ON(list_empty(&msgq)); - - msg = list_entry(msgq.next, struct rxrpc_message, link); - - /* locate the record for the peer from which it - * originated */ - ret = rxrpc_peer_lookup(trans, addr, &peer); - if (ret < 0) { - kdebug("Rx No connections from that peer"); - rxrpc_trans_immediate_abort(trans, msg, -EINVAL); - goto finished_msg; - } - - /* try and find a matching connection */ - ret = rxrpc_connection_lookup(peer, msg, &msg->conn); - if (ret < 0) { - kdebug("Rx Unknown Connection"); - rxrpc_trans_immediate_abort(trans, msg, -EINVAL); - rxrpc_put_peer(peer); - goto finished_msg; - } - rxrpc_put_peer(peer); - - /* deal with the first packet of a new call */ - if (msg->hdr.flags & RXRPC_CLIENT_INITIATED && - msg->hdr.type == RXRPC_PACKET_TYPE_DATA && - ntohl(msg->hdr.seq) == 1 - ) { - _debug("Rx New server call"); - rxrpc_trans_receive_new_call(trans, &msgq); - goto finished_msg; - } - - /* deal with subsequent packet(s) of call */ - _debug("Rx Call packet"); - while (!list_empty(&msgq)) { - msg = list_entry(msgq.next, struct rxrpc_message, link); - list_del_init(&msg->link); - - ret = rxrpc_conn_receive_call_packet(msg->conn, NULL, msg); - if (ret < 0) { - rxrpc_trans_immediate_abort(trans, msg, ret); - rxrpc_put_message(msg); - goto finished_msg; - } - - rxrpc_put_message(msg); - } - - goto finished_msg; - - /* dispose of the packets */ - finished_msg: - while (!list_empty(&msgq)) { - msg = list_entry(msgq.next, struct rxrpc_message, link); - list_del_init(&msg->link); - - rxrpc_put_message(msg); - } - kfree_skb(pkt); - } - - _leave(""); - -} /* end rxrpc_trans_receive_packet() */ - -/*****************************************************************************/ -/* - * accept a new call from a client trying to connect to one of my services - * - called in process context - */ -static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans, - struct list_head *msgq) -{ - struct rxrpc_message *msg; - - _enter(""); - - /* only bother with the first packet */ - msg = list_entry(msgq->next, struct rxrpc_message, link); - list_del_init(&msg->link); - rxrpc_krxsecd_queue_incoming_call(msg); - rxrpc_put_message(msg); - - _leave(" = 0"); - - return 0; -} /* end rxrpc_trans_receive_new_call() */ - -/*****************************************************************************/ -/* - * perform an immediate abort without connection or call structures - */ -int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans, - struct rxrpc_message *msg, - int error) -{ - struct rxrpc_header ahdr; - struct sockaddr_in sin; - struct msghdr msghdr; - struct kvec iov[2]; - __be32 _error; - int len, ret; - - _enter("%p,%p,%d", trans, msg, error); - - /* don't abort an abort packet */ - if (msg->hdr.type == RXRPC_PACKET_TYPE_ABORT) { - _leave(" = 0"); - return 0; - } - - _error = htonl(-error); - - /* set up the message to be transmitted */ - memcpy(&ahdr, &msg->hdr, sizeof(ahdr)); - ahdr.epoch = msg->hdr.epoch; - ahdr.serial = htonl(1); - ahdr.seq = 0; - ahdr.type = RXRPC_PACKET_TYPE_ABORT; - ahdr.flags = RXRPC_LAST_PACKET; - ahdr.flags |= ~msg->hdr.flags & RXRPC_CLIENT_INITIATED; - - iov[0].iov_len = sizeof(ahdr); - iov[0].iov_base = &ahdr; - iov[1].iov_len = sizeof(_error); - iov[1].iov_base = &_error; - - len = sizeof(ahdr) + sizeof(_error); - - memset(&sin,0,sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = udp_hdr(msg->pkt)->source; - sin.sin_addr.s_addr = ip_hdr(msg->pkt)->saddr; - - msghdr.msg_name = &sin; - msghdr.msg_namelen = sizeof(sin); - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; - msghdr.msg_flags = MSG_DONTWAIT; - - _net("Sending message type %d of %d bytes to %08x:%d", - ahdr.type, - len, - ntohl(sin.sin_addr.s_addr), - ntohs(sin.sin_port)); - - /* send the message */ - ret = kernel_sendmsg(trans->socket, &msghdr, iov, 2, len); - - _leave(" = %d", ret); - return ret; -} /* end rxrpc_trans_immediate_abort() */ - -/*****************************************************************************/ -/* - * receive an ICMP error report and percolate it to all connections - * heading to the affected host or port - */ -static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans) -{ - struct rxrpc_connection *conn; - struct sockaddr_in sin; - struct rxrpc_peer *peer; - struct list_head connq, *_p; - struct errormsg emsg; - struct msghdr msg; - __be16 port; - int local, err; - - _enter("%p", trans); - - for (;;) { - trans->error_rcvd = 0; - - /* try and receive an error message */ - msg.msg_name = &sin; - msg.msg_namelen = sizeof(sin); - msg.msg_control = &emsg; - msg.msg_controllen = sizeof(emsg); - msg.msg_flags = 0; - - err = kernel_recvmsg(trans->socket, &msg, NULL, 0, 0, - MSG_ERRQUEUE | MSG_DONTWAIT | MSG_TRUNC); - - if (err == -EAGAIN) { - _leave(""); - return; - } - - if (err < 0) { - printk("%s: unable to recv an error report: %d\n", - __FUNCTION__, err); - _leave(""); - return; - } - - msg.msg_controllen = (char *) msg.msg_control - (char *) &emsg; - - if (msg.msg_controllen < sizeof(emsg.cmsg) || - msg.msg_namelen < sizeof(sin)) { - printk("%s: short control message" - " (nlen=%u clen=%Zu fl=%x)\n", - __FUNCTION__, - msg.msg_namelen, - msg.msg_controllen, - msg.msg_flags); - continue; - } - - _net("Rx Received control message" - " { len=%Zu level=%u type=%u }", - emsg.cmsg.cmsg_len, - emsg.cmsg.cmsg_level, - emsg.cmsg.cmsg_type); - - if (sin.sin_family != AF_INET) { - printk("Rx Ignoring error report with non-INET address" - " (fam=%u)", - sin.sin_family); - continue; - } - - _net("Rx Received message pertaining to host addr=%x port=%hu", - ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); - - if (emsg.cmsg.cmsg_level != SOL_IP || - emsg.cmsg.cmsg_type != IP_RECVERR) { - printk("Rx Ignoring unknown error report" - " { level=%u type=%u }", - emsg.cmsg.cmsg_level, - emsg.cmsg.cmsg_type); - continue; - } - - if (msg.msg_controllen < sizeof(emsg.cmsg) + sizeof(emsg.ee)) { - printk("%s: short error message (%Zu)\n", - __FUNCTION__, msg.msg_controllen); - _leave(""); - return; - } - - port = sin.sin_port; - - switch (emsg.ee.ee_origin) { - case SO_EE_ORIGIN_ICMP: - local = 0; - switch (emsg.ee.ee_type) { - case ICMP_DEST_UNREACH: - switch (emsg.ee.ee_code) { - case ICMP_NET_UNREACH: - _net("Rx Received ICMP Network Unreachable"); - port = 0; - err = -ENETUNREACH; - break; - case ICMP_HOST_UNREACH: - _net("Rx Received ICMP Host Unreachable"); - port = 0; - err = -EHOSTUNREACH; - break; - case ICMP_PORT_UNREACH: - _net("Rx Received ICMP Port Unreachable"); - err = -ECONNREFUSED; - break; - case ICMP_NET_UNKNOWN: - _net("Rx Received ICMP Unknown Network"); - port = 0; - err = -ENETUNREACH; - break; - case ICMP_HOST_UNKNOWN: - _net("Rx Received ICMP Unknown Host"); - port = 0; - err = -EHOSTUNREACH; - break; - default: - _net("Rx Received ICMP DestUnreach { code=%u }", - emsg.ee.ee_code); - err = emsg.ee.ee_errno; - break; - } - break; - - case ICMP_TIME_EXCEEDED: - _net("Rx Received ICMP TTL Exceeded"); - err = emsg.ee.ee_errno; - break; - - default: - _proto("Rx Received ICMP error { type=%u code=%u }", - emsg.ee.ee_type, emsg.ee.ee_code); - err = emsg.ee.ee_errno; - break; - } - break; - - case SO_EE_ORIGIN_LOCAL: - _proto("Rx Received local error { error=%d }", - emsg.ee.ee_errno); - local = 1; - err = emsg.ee.ee_errno; - break; - - case SO_EE_ORIGIN_NONE: - case SO_EE_ORIGIN_ICMP6: - default: - _proto("Rx Received error report { orig=%u }", - emsg.ee.ee_origin); - local = 0; - err = emsg.ee.ee_errno; - break; - } - - /* find all the connections between this transport and the - * affected destination */ - INIT_LIST_HEAD(&connq); - - if (rxrpc_peer_lookup(trans, sin.sin_addr.s_addr, - &peer) == 0) { - read_lock(&peer->conn_lock); - list_for_each(_p, &peer->conn_active) { - conn = list_entry(_p, struct rxrpc_connection, - link); - if (port && conn->addr.sin_port != port) - continue; - if (!list_empty(&conn->err_link)) - continue; - - rxrpc_get_connection(conn); - list_add_tail(&conn->err_link, &connq); - } - read_unlock(&peer->conn_lock); - - /* service all those connections */ - while (!list_empty(&connq)) { - conn = list_entry(connq.next, - struct rxrpc_connection, - err_link); - list_del(&conn->err_link); - - rxrpc_conn_handle_error(conn, local, err); - - rxrpc_put_connection(conn); - } - - rxrpc_put_peer(peer); - } - } - - _leave(""); - return; -} /* end rxrpc_trans_receive_error_report() */ -- cgit v1.2.3-59-g8ed1b