Commit d28e0e20 authored by David S. Miller's avatar David S. Miller

SPX updates from Arnaldo Carvalho de Melo:

- CodingStyle cleanups
- Adds MODULE_LICENSE
- Fix missing release_sock calls
- Remove leftovers from sock cleanup patches
- Use skb_queue_purge
parent 04c1e5a1
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Developers: * Developers:
* Jay Schulist <jschlst@samba.org> * Jay Schulist <jschlst@samba.org>
* Jim Freeman <jfree@caldera.com> * Jim Freeman <jfree@caldera.com>
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* *
* Changes: * Changes:
* Alan Cox : Fixed an skb_unshare check for NULL * Alan Cox : Fixed an skb_unshare check for NULL
...@@ -22,6 +23,8 @@ ...@@ -22,6 +23,8 @@
* of the alloc count to follow rmt_seq. * of the alloc count to follow rmt_seq.
* Arnaldo C. Melo : Use a private slabcache for the old tp_pinfo * Arnaldo C. Melo : Use a private slabcache for the old tp_pinfo
* struct sock member, use spx_sk and ipx_sk * struct sock member, use spx_sk and ipx_sk
* Arnaldo C. Melo : Big CodingStyle cleanup, fixes some lock leaks,
* removes a leftover of the slabcache patch.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -44,7 +47,7 @@ ...@@ -44,7 +47,7 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/poll.h> #include <linux/poll.h>
static struct proto_ops *ipx_operations; static struct proto_ops *ipx_ops;
static struct proto_ops spx_ops; static struct proto_ops spx_ops;
static __u16 connids; static __u16 connids;
...@@ -60,7 +63,8 @@ extern void ipx_remove_socket(struct sock *sk); ...@@ -60,7 +63,8 @@ extern void ipx_remove_socket(struct sock *sk);
but the right spx buffers are looked at and but the right spx buffers are looked at and
there is no question on the type of the socket there is no question on the type of the socket
*/ */
static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, poll_table *wait) static unsigned int spx_datagram_poll(struct file * file, struct socket *sock,
poll_table *wait)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
...@@ -84,15 +88,14 @@ static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, p ...@@ -84,15 +88,14 @@ static unsigned int spx_datagram_poll(struct file * file, struct socket *sock, p
mask |= POLLHUP; mask |= POLLHUP;
/* connection hasn't started yet? */ /* connection hasn't started yet? */
if (sk->state == TCP_SYN_SENT) if (sk->state == TCP_SYN_SENT)
return mask; goto out;
/* writable? */ /* writable? */
if (sock_writeable(sk)) if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND; mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else else
set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags); set_bit(SOCK_ASYNC_NOSPACE,&sk->socket->flags);
out: return mask;
return mask;
} }
/* Create the SPX specific data */ /* Create the SPX specific data */
...@@ -123,43 +126,42 @@ static int spx_sock_init(struct sock *sk) ...@@ -123,43 +126,42 @@ static int spx_sock_init(struct sock *sk)
skb_queue_head_init(&pdata->transmit_queue); skb_queue_head_init(&pdata->transmit_queue);
skb_queue_head_init(&pdata->retransmit_queue); skb_queue_head_init(&pdata->retransmit_queue);
return (0); return 0;
} }
static int spx_create(struct socket *sock, int protocol) static int spx_create(struct socket *sock, int protocol)
{ {
struct sock *sk; struct sock *sk;
int rc = -ENOMEM;
MOD_INC_USE_COUNT;
/* /* Called on connection receive so cannot be GFP_KERNEL */
* Called on connection receive so cannot be GFP_KERNEL
*/
sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1); sk = sk_alloc(PF_IPX, GFP_ATOMIC, 1);
if(sk == NULL) if (!sk)
return (-ENOMEM); goto decmod;
switch(sock->type) rc = -ESOCKTNOSUPPORT;
{ switch (sock->type) {
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
sock->ops = &spx_ops; sock->ops = &spx_ops;
break; break;
default: default:
sk_free(sk); sk_free(sk);
return (-ESOCKTNOSUPPORT); goto out;
} }
rc = 0;
sock_init_data(sock, sk); sock_init_data(sock, sk);
spx_sock_init(sk); spx_sock_init(sk);
sk->data_ready = spx_rcv; sk->data_ready = spx_rcv;
sk->destruct = NULL; sk->destruct = NULL;
sk->no_check = 1; sk->no_check = 1;
out: return rc;
MOD_INC_USE_COUNT; decmod: MOD_DEC_USE_COUNT;
goto out;
return (0);
} }
void spx_close_socket(struct sock *sk) void spx_close_socket(struct sock *sk)
{ {
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
...@@ -173,18 +175,12 @@ void spx_close_socket(struct sock *sk) ...@@ -173,18 +175,12 @@ void spx_close_socket(struct sock *sk)
void spx_destroy_socket(struct sock *sk) void spx_destroy_socket(struct sock *sk)
{ {
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
struct sk_buff *skb;
ipx_remove_socket(sk); ipx_remove_socket(sk);
while((skb = skb_dequeue(&sk->receive_queue)) != NULL) skb_queue_purge(&sk->receive_queue);
kfree_skb(skb); skb_queue_purge(&pdata->transmit_queue);
while((skb = skb_dequeue(&pdata->transmit_queue)) != NULL) skb_queue_purge(&pdata->retransmit_queue);
kfree_skb(skb); skb_queue_purge(&pdata->rcv_queue);
while((skb = skb_dequeue(&pdata->retransmit_queue)) != NULL)
kfree_skb(skb);
while((skb = skb_dequeue(&pdata->rcv_queue)) != NULL)
kfree_skb(skb);
sk_free(sk); sk_free(sk);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
...@@ -195,14 +191,13 @@ static int spx_release(struct socket *sock) ...@@ -195,14 +191,13 @@ static int spx_release(struct socket *sock)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
if(sk == NULL) if (!sk)
return (0); goto out;
if(!sk->dead) if (!sk->dead)
sk->state_change(sk); sk->state_change(sk);
sk->dead = 1; sk->dead = 1;
if(pdata->state != SPX_CLOSED) if (pdata->state != SPX_CLOSED) {
{
spx_transmit(sk, NULL, DISCON, 0); spx_transmit(sk, NULL, DISCON, 0);
spx_close_socket(sk); spx_close_socket(sk);
} }
...@@ -210,111 +205,101 @@ static int spx_release(struct socket *sock) ...@@ -210,111 +205,101 @@ static int spx_release(struct socket *sock)
sock->sk = NULL; sock->sk = NULL;
sk->socket = NULL; sk->socket = NULL;
spx_destroy_socket(sk); spx_destroy_socket(sk);
out: return 0;
return (0);
} }
/* Move a socket into listening state. */ /* Move a socket into listening state. */
static int spx_listen(struct socket *sock, int backlog) static int spx_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int rc = -EINVAL;
if(sock->state != SS_UNCONNECTED)
return (-EINVAL); if (sock->state != SS_UNCONNECTED)
if(sock->type != SOCK_SEQPACKET) goto out;
return (-EOPNOTSUPP); rc = -EOPNOTSUPP;
if(sk->zapped != 0) if (sock->type != SOCK_SEQPACKET)
return (-EAGAIN); goto out;
rc = -EAGAIN;
if (sk->zapped)
goto out;
rc = 0;
sk->max_ack_backlog = backlog; sk->max_ack_backlog = backlog;
if(sk->state != TCP_LISTEN) if (sk->state != TCP_LISTEN) {
{
sk->ack_backlog = 0; sk->ack_backlog = 0;
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
} }
sk->socket->flags |= __SO_ACCEPTCON; sk->socket->flags |= __SO_ACCEPTCON;
out: return rc;
return (0);
} }
/* Accept a pending SPX connection */ /* Accept a pending SPX connection */
static int spx_accept(struct socket *sock, struct socket *newsock, int flags) static int spx_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
struct sock *sk; struct sock *sk = sock->sk;
struct sock *newsk; struct sock *newsk;
struct sk_buff *skb; struct sk_buff *skb;
int err; int rc = -EINVAL;
if(sock->sk == NULL) if (!sk || sk->state != TCP_LISTEN ||
return (-EINVAL); sock->state != SS_UNCONNECTED || !(sock->flags & __SO_ACCEPTCON))
sk = sock->sk; goto out;
rc = -EOPNOTSUPP;
if((sock->state != SS_UNCONNECTED) || !(sock->flags & __SO_ACCEPTCON)) if (sock->type != SOCK_SEQPACKET)
return (-EINVAL); goto out;
if(sock->type != SOCK_SEQPACKET)
return (-EOPNOTSUPP);
if(sk->state != TCP_LISTEN)
return (-EINVAL);
cli(); cli();
do { do {
skb = skb_dequeue(&sk->receive_queue); skb = skb_dequeue(&sk->receive_queue);
if(skb == NULL) if (!skb) {
{ rc = -EWOULDBLOCK;
if(flags & O_NONBLOCK) if (flags & O_NONBLOCK)
{ goto out_unlock;
sti();
return (-EWOULDBLOCK);
}
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if(signal_pending(current)) rc = -ERESTARTSYS;
{ if (signal_pending(current))
sti(); goto out_unlock;
return (-ERESTARTSYS);
}
} }
} while (skb == NULL); } while (!skb);
newsk = skb->sk; newsk = skb->sk;
newsk->pair = NULL; newsk->pair = NULL;
sti(); sti();
err = spx_transmit(newsk, skb, CONACK, 0); /* Connection ACK */ rc = spx_transmit(newsk, skb, CONACK, 0); /* Connection ACK */
if(err) if (rc)
return (err); goto out;
/* Now attach up the new socket */ /* Now attach up the new socket */
sock->sk = NULL; sock->sk = NULL;
sk->ack_backlog--; sk->ack_backlog--;
newsock->sk = newsk; newsock->sk = newsk;
newsk->state = TCP_ESTABLISHED; newsk->state = TCP_ESTABLISHED;
ipx_sk(newsk)->dest_addr = spx_sk(newsk)->dest_addr; ipx_sk(newsk)->dest_addr = spx_sk(newsk)->dest_addr;
out: return rc;
return (0); out_unlock:
sti();
goto out;
} }
/* Build a connection to an SPX socket */ /* Build a connection to an SPX socket */
static int spx_connect(struct socket *sock, struct sockaddr *uaddr, static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags) int addr_len, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
struct sockaddr_ipx src; struct sockaddr_ipx src;
struct sk_buff *skb; struct sk_buff *skb;
int size, err; int size = sizeof(src);
int rc = ipx_ops->getname(sock, (struct sockaddr *)&src, &size, 0);
size = sizeof(src); if (rc)
err = ipx_operations->getname(sock, (struct sockaddr *)&src, &size, 0); goto out;
if(err)
return (err);
pdata->source_addr.net = src.sipx_network; pdata->source_addr.net = src.sipx_network;
memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN); memcpy(pdata->source_addr.node, src.sipx_node, IPX_NODE_LEN);
pdata->source_addr.sock = (unsigned short)src.sipx_port; pdata->source_addr.sock = (unsigned short)src.sipx_port;
err = ipx_operations->connect(sock, uaddr, addr_len, flags); rc = ipx_ops->connect(sock, uaddr, addr_len, flags);
if(err) if (rc)
return (err); goto out;
pdata->dest_addr = ipx_sk(sk)->dest_addr; pdata->dest_addr = ipx_sk(sk)->dest_addr;
pdata->state = SPX_CONNECTING; pdata->state = SPX_CONNECTING;
...@@ -322,42 +307,36 @@ static int spx_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -322,42 +307,36 @@ static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
sk->state = TCP_SYN_SENT; sk->state = TCP_SYN_SENT;
/* Send Connection request */ /* Send Connection request */
err = spx_transmit(sk, NULL, CONREQ, 0); rc = spx_transmit(sk, NULL, CONREQ, 0);
if(err) if (rc)
return (err); goto out;
cli(); cli();
do { do {
skb = skb_dequeue(&sk->receive_queue); skb = skb_dequeue(&sk->receive_queue);
if(skb == NULL) if (!skb) {
{ rc = -EWOULDBLOCK;
if(flags & O_NONBLOCK) if (flags & O_NONBLOCK)
{ goto unlock;
sti();
return (-EWOULDBLOCK);
}
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if(signal_pending(current)) rc = -ERESTARTSYS;
{ if (signal_pending(current))
sti(); goto unlock;
return (-ERESTARTSYS);
}
} }
} while (skb == NULL); } while (!skb);
if(pdata->state == SPX_CLOSED) rc = -ETIMEDOUT;
{ if (pdata->state == SPX_CLOSED) {
sti();
del_timer(&pdata->watchdog); del_timer(&pdata->watchdog);
return (-ETIMEDOUT); goto unlock;
} }
rc = 0;
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED; sk->state = TCP_ESTABLISHED;
kfree_skb(skb); kfree_skb(skb);
sti(); unlock: sti();
out: return rc;
return (0);
} }
/* /*
...@@ -371,56 +350,59 @@ static int spx_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -371,56 +350,59 @@ static int spx_connect(struct socket *sock, struct sockaddr *uaddr,
*/ */
static inline unsigned long spx_calc_rtt(int tries) static inline unsigned long spx_calc_rtt(int tries)
{ {
if(tries < 1) int rc;
return (RETRY_TIME);
if(tries > 5) if (tries < 1)
return (MAX_RETRY_DELAY); rc = RETRY_TIME;
return (tries * HZ); else if (tries > 5)
rc = MAX_RETRY_DELAY;
else
rc = tries * HZ;
return rc;
} }
static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type) static int spx_route_skb(struct spx_opt *pdata, struct sk_buff *skb, int type)
{ {
struct sk_buff *skb2; int rc = -ENOBUFS;
int err = 0;
skb = skb_unshare(skb, GFP_ATOMIC); skb = skb_unshare(skb, GFP_ATOMIC);
if(skb == NULL) if (!skb)
return (-ENOBUFS); goto out;
rc = 0;
switch(type)
{ switch (type) {
case (CONREQ): case CONREQ:
case (DATA): case DATA:
if(!skb_queue_empty(&pdata->retransmit_queue)) if (!skb_queue_empty(&pdata->retransmit_queue)) {
{
skb_queue_tail(&pdata->transmit_queue, skb); skb_queue_tail(&pdata->transmit_queue, skb);
return 0; goto out;
} }
case TQUEUE: {
case (TQUEUE): struct sk_buff *skb2;
pdata->retransmit.expires = jiffies + spx_calc_rtt(0); pdata->retransmit.expires = jiffies + spx_calc_rtt(0);
add_timer(&pdata->retransmit); add_timer(&pdata->retransmit);
skb2 = skb_clone(skb, GFP_NOIO); skb2 = skb_clone(skb, GFP_NOIO);
if(skb2 == NULL) if (!skb2) {
return -ENOBUFS; rc = -ENOBUFS;
goto out;
}
skb_queue_tail(&pdata->retransmit_queue, skb2); skb_queue_tail(&pdata->retransmit_queue, skb2);
/* Fall thru */
case (ACK): }
case (CONACK): case ACK:
case (WDREQ): case CONACK:
case (WDACK): case WDREQ:
case (DISCON): case WDACK:
case (DISACK): case DISCON:
case (RETRAN): case DISACK:
default: case RETRAN:
/* Send data */ default: /* Send data */
err = ipxrtr_route_skb(skb); rc = ipxrtr_route_skb(skb);
if(err) if (rc)
kfree_skb(skb); kfree_skb(skb);
} }
out: return rc;
return (err);
} }
/* SPX packet transmit engine */ /* SPX packet transmit engine */
...@@ -429,25 +411,27 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len) ...@@ -429,25 +411,27 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
struct ipxspxhdr *ipxh; struct ipxspxhdr *ipxh;
unsigned long flags; unsigned long flags;
int err; int rc;
if(skb == NULL) if (!skb) {
{
int offset = ipx_if_offset(pdata->dest_addr.net); int offset = ipx_if_offset(pdata->dest_addr.net);
int size = offset + sizeof(struct ipxspxhdr); int size = offset + sizeof(struct ipxspxhdr);
if (offset < 0) /* ENETUNREACH */ rc = -ENETUNREACH;
return(-ENETUNREACH); if (offset < 0)
goto out;
save_flags(flags); save_flags(flags);
cli(); cli();
skb = sock_alloc_send_skb(sk, size, 0, &err); skb = sock_alloc_send_skb(sk, size, 0, &err);
if(skb == NULL) { rc = -ENOMEM;
if (!skb) {
restore_flags(flags); restore_flags(flags);
return (-ENOMEM); goto out;
} }
skb_reserve(skb, offset); skb_reserve(skb, offset);
skb->h.raw = skb->nh.raw = skb_put(skb,sizeof(struct ipxspxhdr)); skb->h.raw = skb->nh.raw =
skb_put(skb, sizeof(struct ipxspxhdr));
restore_flags(flags); restore_flags(flags);
} }
...@@ -471,40 +455,39 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len) ...@@ -471,40 +455,39 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
/* Reset/Set WD timer */ /* Reset/Set WD timer */
mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT); mod_timer(&pdata->watchdog, jiffies+VERIFY_TIMEOUT);
switch(type) switch (type) {
{ case DATA: /* Data */
case (DATA): /* Data */
ipxh->ipx.ipx_pktsize = htons(SPX_SYS_PKT_LEN + len); ipxh->ipx.ipx_pktsize = htons(SPX_SYS_PKT_LEN + len);
ipxh->spx.cctl = (CCTL_ACK | CCTL_EOM); ipxh->spx.cctl = (CCTL_ACK | CCTL_EOM);
pdata->sequence++; pdata->sequence++;
break; break;
case (ACK): /* ACK */ case ACK: /* ACK */
pdata->rmt_seq++; pdata->rmt_seq++;
case (WDACK): /* WD ACK */ case WDACK: /* WD ACK */
case (CONACK): /* Connection ACK */ case CONACK: /* Connection ACK */
ipxh->spx.cctl = CCTL_SYS; ipxh->spx.cctl = CCTL_SYS;
ipxh->spx.ackseq = htons(pdata->rmt_seq); ipxh->spx.ackseq = htons(pdata->rmt_seq);
break; break;
case (CONREQ): /* Connection Request */ case CONREQ: /* Connection Request */
del_timer(&pdata->watchdog); del_timer(&pdata->watchdog);
case (WDREQ): /* WD Request */ case WDREQ: /* WD Request */
pdata->source_connid = htons(connids++); pdata->source_connid = htons(connids++);
pdata->dest_connid = 0xFFFF; pdata->dest_connid = 0xFFFF;
pdata->alloc = 3 + pdata->rmt_seq; pdata->alloc = 3 + pdata->rmt_seq;
ipxh->spx.cctl = (CCTL_ACK | CCTL_SYS); ipxh->spx.cctl = CCTL_ACK | CCTL_SYS;
ipxh->spx.sconn = pdata->source_connid; ipxh->spx.sconn = pdata->source_connid;
ipxh->spx.dconn = pdata->dest_connid; ipxh->spx.dconn = pdata->dest_connid;
ipxh->spx.allocseq = htons(pdata->alloc); ipxh->spx.allocseq = htons(pdata->alloc);
break; break;
case (DISCON): /* Informed Disconnect */ case DISCON: /* Informed Disconnect */
ipxh->spx.cctl = CCTL_ACK; ipxh->spx.cctl = CCTL_ACK;
ipxh->spx.dtype = SPX_DTYPE_ECONN; ipxh->spx.dtype = SPX_DTYPE_ECONN;
break; break;
case (DISACK): /* Informed Disconnect ACK */ case DISACK: /* Informed Disconnect ACK */
ipxh->spx.cctl = 0; ipxh->spx.cctl = 0;
ipxh->spx.dtype = SPX_DTYPE_ECACK; ipxh->spx.dtype = SPX_DTYPE_ECACK;
ipxh->spx.sequence = 0; ipxh->spx.sequence = 0;
...@@ -512,11 +495,13 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len) ...@@ -512,11 +495,13 @@ static int spx_transmit(struct sock *sk, struct sk_buff *skb, int type, int len)
break; break;
default: default:
return (-EOPNOTSUPP); rc = -EOPNOTSUPP;
goto out;
} }
/* Send data */ /* Send data */
return (spx_route_skb(pdata, skb, type)); rc = spx_route_skb(pdata, skb, type);
out: return rc;
} }
/* Check the state of the connection and send a WD request if needed. */ /* Check the state of the connection and send a WD request if needed. */
...@@ -526,19 +511,16 @@ static void spx_watchdog(unsigned long data) ...@@ -526,19 +511,16 @@ static void spx_watchdog(unsigned long data)
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
del_timer(&pdata->watchdog); del_timer(&pdata->watchdog);
if(pdata->state == SPX_CLOSED) if (pdata->state == SPX_CLOSED)
return; goto out;
if(pdata->retries > pdata->max_retries) if (pdata->retries > pdata->max_retries) {
{
spx_close_socket(sk); /* Unilateral Abort */ spx_close_socket(sk); /* Unilateral Abort */
return; goto out;
} }
/* Send WD request */ /* Send WD request */
spx_transmit(sk, NULL, WDREQ, 0); spx_transmit(sk, NULL, WDREQ, 0);
pdata->retries++; pdata->retries++;
out:;
return;
} }
static void spx_retransmit(unsigned long data) static void spx_retransmit(unsigned long data)
...@@ -547,22 +529,19 @@ static void spx_retransmit(unsigned long data) ...@@ -547,22 +529,19 @@ static void spx_retransmit(unsigned long data)
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags; unsigned long flags;
int err;
del_timer(&pdata->retransmit); del_timer(&pdata->retransmit);
if(pdata->state == SPX_CLOSED) if (pdata->state == SPX_CLOSED)
return; goto out;
if(pdata->retransmits > RETRY_COUNT) if (pdata->retransmits > RETRY_COUNT) {
{
spx_close_socket(sk); /* Unilateral Abort */ spx_close_socket(sk); /* Unilateral Abort */
return; goto out;
} }
/* Need to leave skb on the queue, aye the fear */ /* Need to leave skb on the queue, aye the fear */
save_flags(flags); save_flags(flags);
cli(); cli();
skb = skb_peek(&pdata->retransmit_queue); skb = skb_peek(&pdata->retransmit_queue);
if(skb_cloned(skb)) if (skb_cloned(skb))
skb = skb_copy(skb, GFP_ATOMIC); skb = skb_copy(skb, GFP_ATOMIC);
else else
skb = skb_clone(skb, GFP_ATOMIC); skb = skb_clone(skb, GFP_ATOMIC);
...@@ -571,67 +550,60 @@ static void spx_retransmit(unsigned long data) ...@@ -571,67 +550,60 @@ static void spx_retransmit(unsigned long data)
pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits); pdata->retransmit.expires = jiffies + spx_calc_rtt(pdata->retransmits);
add_timer(&pdata->retransmit); add_timer(&pdata->retransmit);
err = spx_route_skb(pdata, skb, RETRAN); spx_route_skb(pdata, skb, RETRAN);
pdata->retransmits++; pdata->retransmits++;
out:;
return;
} }
/* Check packet for retransmission, ConReqAck aware */ /* Check packet for retransmission, ConReqAck aware */
static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type) static int spx_retransmit_chk(struct spx_opt *pdata, int ackseq, int type)
{ {
struct ipxspxhdr *ipxh; struct ipxspxhdr *ipxh;
struct sk_buff *skb; int rc = -ENOENT;
struct sk_buff *skb = skb_dequeue(&pdata->retransmit_queue);
skb = skb_dequeue(&pdata->retransmit_queue);
if(!skb)
return (-ENOENT);
if (!skb)
goto out;
rc = 0;
/* Check Data/ACK seq */ /* Check Data/ACK seq */
switch(type) switch (type) {
{
case ACK: /* Check Sequence, Should == 1 */ case ACK: /* Check Sequence, Should == 1 */
ipxh = (struct ipxspxhdr *)skb->nh.raw; ipxh = (struct ipxspxhdr *)skb->nh.raw;
if(!(ntohs(ipxh->spx.sequence) - htons(ackseq))) if (!(ntohs(ipxh->spx.sequence) - htons(ackseq)))
break; break;
case CONACK: case CONACK:
del_timer(&pdata->retransmit); del_timer(&pdata->retransmit);
pdata->retransmits = 0; pdata->retransmits = 0;
kfree_skb(skb); kfree_skb(skb);
if(skb_queue_empty(&pdata->retransmit_queue)) if (skb_queue_empty(&pdata->retransmit_queue)) {
{
skb = skb_dequeue(&pdata->transmit_queue); skb = skb_dequeue(&pdata->transmit_queue);
if(skb != NULL) if (skb)
spx_route_skb(pdata, skb, TQUEUE); spx_route_skb(pdata, skb, TQUEUE);
} }
return (0); goto out;
} }
skb_queue_head(&pdata->retransmit_queue, skb); skb_queue_head(&pdata->retransmit_queue, skb);
return (-1); rc = -1;
out: return rc;
} }
/* SPX packet receive engine */ /* SPX packet receive engine */
void spx_rcv(struct sock *sk, int bytes) void spx_rcv(struct sock *sk, int bytes)
{ {
struct sk_buff *skb;
struct ipxspxhdr *ipxh; struct ipxspxhdr *ipxh;
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
struct sk_buff *skb = skb_dequeue(&sk->receive_queue);
skb = skb_dequeue(&sk->receive_queue); if (!skb)
if(skb == NULL) goto out;
return;
ipxh = (struct ipxspxhdr *)skb->nh.raw; ipxh = (struct ipxspxhdr *)skb->nh.raw;
/* Can't receive on a closed connection */ /* Can't receive on a closed connection */
if((pdata->state == SPX_CLOSED) && (ipxh->spx.sequence != 0)) if ((pdata->state == SPX_CLOSED && ipxh->spx.sequence) ||
goto toss_skb; ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN ||
if(ntohs(ipxh->ipx.ipx_pktsize) < SPX_SYS_PKT_LEN) ipxh->ipx.ipx_type != IPX_TYPE_SPX ||
goto toss_skb; ntohs(ipxh->spx.ackseq) > pdata->sequence)
if(ipxh->ipx.ipx_type != IPX_TYPE_SPX)
goto toss_skb;
if(ntohs(ipxh->spx.ackseq) > pdata->sequence)
goto toss_skb; goto toss_skb;
/* Reset WD timer on any received packet */ /* Reset WD timer on any received packet */
...@@ -640,13 +612,11 @@ void spx_rcv(struct sock *sk, int bytes) ...@@ -640,13 +612,11 @@ void spx_rcv(struct sock *sk, int bytes)
pdata->watchdog.expires = jiffies + ABORT_TIMEOUT; pdata->watchdog.expires = jiffies + ABORT_TIMEOUT;
add_timer(&pdata->watchdog); add_timer(&pdata->watchdog);
switch(ipxh->spx.cctl) switch (ipxh->spx.cctl) {
{
case (CCTL_SYS | CCTL_ACK): case (CCTL_SYS | CCTL_ACK):
if((ipxh->spx.sequence == 0) /* ConReq */ if (!ipxh->spx.sequence && /* ConReq */
&& (ipxh->spx.ackseq == 0) !ipxh->spx.ackseq &&
&& (ipxh->spx.dconn == 0xFFFF)) ipxh->spx.dconn == 0xFFFF) {
{
pdata->state = SPX_CONNECTED; pdata->state = SPX_CONNECTED;
pdata->dest_addr = ipxh->ipx.ipx_source; pdata->dest_addr = ipxh->ipx.ipx_source;
pdata->source_addr = ipxh->ipx.ipx_dest; pdata->source_addr = ipxh->ipx.ipx_dest;
...@@ -655,63 +625,57 @@ void spx_rcv(struct sock *sk, int bytes) ...@@ -655,63 +625,57 @@ void spx_rcv(struct sock *sk, int bytes)
skb_queue_tail(&sk->receive_queue, skb); skb_queue_tail(&sk->receive_queue, skb);
wake_up_interruptible(sk->sleep); wake_up_interruptible(sk->sleep);
} } else /* WD Request */
else /* WD Request */
spx_transmit(sk, skb, WDACK, 0); spx_transmit(sk, skb, WDACK, 0);
goto finish; goto out;
case CCTL_SYS: /* ACK */ case CCTL_SYS: /* ACK */
if((ipxh->spx.dtype == 0) /* ConReq ACK */ if (!ipxh->spx.dtype && /* ConReq ACK */
&& (ipxh->spx.sconn != 0xFFFF) ipxh->spx.sconn != 0xFFFF &&
&& (ipxh->spx.dconn != 0xFFFF) ipxh->spx.dconn != 0xFFFF &&
&& (ipxh->spx.sequence == 0) !ipxh->spx.sequence &&
&& (ipxh->spx.ackseq == 0) !ipxh->spx.ackseq &&
&& (pdata->state != SPX_CONNECTED)) pdata->state != SPX_CONNECTED) {
{
pdata->state = SPX_CONNECTED; pdata->state = SPX_CONNECTED;
pdata->dest_connid = ipxh->spx.sconn; pdata->dest_connid = ipxh->spx.sconn;
if(spx_retransmit_chk(pdata, 0, CONACK) < 0) if (spx_retransmit_chk(pdata, 0, CONACK) < 0)
goto toss_skb; goto toss_skb;
skb_queue_tail(&sk->receive_queue, skb); skb_queue_tail(&sk->receive_queue, skb);
wake_up_interruptible(sk->sleep); wake_up_interruptible(sk->sleep);
goto finish; goto out;
} }
spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK); spx_retransmit_chk(pdata, ipxh->spx.ackseq, ACK);
goto toss_skb; goto toss_skb;
case (CCTL_ACK): case CCTL_ACK:
/* Informed Disconnect */ /* Informed Disconnect */
if(ipxh->spx.dtype == SPX_DTYPE_ECONN) if (ipxh->spx.dtype == SPX_DTYPE_ECONN) {
{
spx_transmit(sk, skb, DISACK, 0); spx_transmit(sk, skb, DISACK, 0);
spx_close_socket(sk); spx_close_socket(sk);
goto finish; goto out;
} }
/* Fall through */ /* Fall through */
default: default:
if(ntohs(ipxh->spx.sequence) == pdata->rmt_seq) if (ntohs(ipxh->spx.sequence) == pdata->rmt_seq) {
{
pdata->rmt_seq = ntohs(ipxh->spx.sequence); pdata->rmt_seq = ntohs(ipxh->spx.sequence);
pdata->rmt_ack = ntohs(ipxh->spx.ackseq); pdata->rmt_ack = ntohs(ipxh->spx.ackseq);
pdata->alloc = pdata->rmt_seq + 3; pdata->alloc = pdata->rmt_seq + 3;
if(pdata->rmt_ack > 0 || pdata->rmt_ack == 0) if (pdata->rmt_ack > 0 || !pdata->rmt_ack)
spx_retransmit_chk(pdata,pdata->rmt_ack, ACK); spx_retransmit_chk(pdata,
pdata->rmt_ack, ACK);
skb_queue_tail(&pdata->rcv_queue, skb); skb_queue_tail(&pdata->rcv_queue, skb);
wake_up_interruptible(sk->sleep); wake_up_interruptible(sk->sleep);
if(ipxh->spx.cctl&CCTL_ACK) if (ipxh->spx.cctl&CCTL_ACK)
spx_transmit(sk, NULL, ACK, 0); spx_transmit(sk, NULL, ACK, 0);
goto finish; goto out;
} }
if(ipxh->spx.dtype == SPX_DTYPE_ECACK) if (ipxh->spx.dtype == SPX_DTYPE_ECACK) {
{ if (pdata->state != SPX_CLOSED)
if(pdata->state != SPX_CLOSED)
spx_close_socket(sk); spx_close_socket(sk);
goto toss_skb; goto toss_skb;
} }
...@@ -719,51 +683,48 @@ void spx_rcv(struct sock *sk, int bytes) ...@@ -719,51 +683,48 @@ void spx_rcv(struct sock *sk, int bytes)
toss_skb: /* Catch All */ toss_skb: /* Catch All */
kfree_skb(skb); kfree_skb(skb);
finish: out:;
return;
} }
/* Get message/packet data from user-land */ /* Get message/packet data from user-land */
static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len, static int spx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm) struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int flags = msg->msg_flags; int flags = msg->msg_flags;
struct sk_buff *skb; struct sk_buff *skb;
int err, offset, size; int offset, size, rc = -EMSGSIZE;
if(len > 534) if (len > 534)
return (-EMSGSIZE); goto out;
if(sk->zapped) rc = -ENOTCONN; /* Socket not bound */
return (-ENOTCONN); /* Socket not bound */ if (sk->zapped)
if(flags&~MSG_DONTWAIT) goto out;
return (-EINVAL); rc = -EINVAL;
if (flags & ~MSG_DONTWAIT)
goto out;
offset = ipx_if_offset(spx_sk(sk)->dest_addr.net); offset = ipx_if_offset(spx_sk(sk)->dest_addr.net);
size = offset + sizeof(struct ipxspxhdr) + len; size = offset + sizeof(struct ipxspxhdr) + len;
cli(); cli();
skb = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &err); skb = sock_alloc_send_skb(sk, size, flags&MSG_DONTWAIT, &rc);
sti(); sti();
if(skb == NULL) if (!skb)
return (err); goto out;
skb->sk = sk; skb->sk = sk;
skb_reserve(skb, offset); skb_reserve(skb, offset);
skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr)); skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxspxhdr));
err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); rc = -EFAULT;
if(err) if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
{
kfree_skb(skb); kfree_skb(skb);
return (-EFAULT); goto out;
} }
rc = len;
err = spx_transmit(sk, skb, DATA, len); if (!spx_transmit(sk, skb, DATA, len))
if(err) rc = -EAGAIN;
return (-EAGAIN); out: return rc;
return (len);
} }
/* Send message/packet data to user-land */ /* Send message/packet data to user-land */
...@@ -775,70 +736,67 @@ static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size, ...@@ -775,70 +736,67 @@ static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct spx_opt *pdata = spx_sk(sk); struct spx_opt *pdata = spx_sk(sk);
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
int copied, err; int copied, rc = -ENOTCONN;
if(sk->zapped)
return (-ENOTCONN); /* Socket not bound */
if (sk->zapped) /* Socket not bound */
goto out;
lock_sock(sk); lock_sock(sk);
restart: restart:
while(skb_queue_empty(&pdata->rcv_queue)) /* No data */ while (skb_queue_empty(&pdata->rcv_queue)) { /* No data */
{
/* Socket errors? */ /* Socket errors? */
err = sock_error(sk); rc = sock_error(sk);
if(err) if (rc)
return (err); goto out_release_sock;
/* Socket shut down? */ /* Socket shut down? */
if(sk->shutdown & RCV_SHUTDOWN) rc = -ESHUTDOWN;
return (-ESHUTDOWN); if (sk->shutdown & RCV_SHUTDOWN)
goto out_release_sock;
/* handle signals */ /* handle signals */
if(signal_pending(current)) rc = -ERESTARTSYS;
return (-ERESTARTSYS); if (signal_pending(current))
goto out_release_sock;
/* User doesn't want to wait */ /* User doesn't want to wait */
if(flags&MSG_DONTWAIT) rc = -EAGAIN;
return (-EAGAIN); if (flags & MSG_DONTWAIT)
goto out_release_sock;
release_sock(sk); release_sock(sk);
save_flags(flags); save_flags(flags);
cli(); cli();
if(skb_peek(&pdata->rcv_queue) == NULL) if (!skb_peek(&pdata->rcv_queue))
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
restore_flags(flags); restore_flags(flags);
lock_sock(sk); lock_sock(sk);
} }
skb = skb_dequeue(&pdata->rcv_queue); skb = skb_dequeue(&pdata->rcv_queue);
if(skb == NULL) if (!skb)
goto restart; goto restart;
ispxh = (struct ipxspxhdr *)skb->nh.raw; ispxh = (struct ipxspxhdr *)skb->nh.raw;
copied = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN; copied = ntohs(ispxh->ipx.ipx_pktsize) - SPX_SYS_PKT_LEN;
if(copied > size) if (copied > size) {
{
copied = size; copied = size;
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
} }
err = memcpy_toiovec(msg->msg_iov, skb->nh.raw+SPX_SYS_PKT_LEN, copied); rc = -EFAULT;
if(err) if (memcpy_toiovec(msg->msg_iov, skb->nh.raw + SPX_SYS_PKT_LEN, copied))
return (-EFAULT); goto out_kfree_skb;
msg->msg_namelen = sizeof(*sipx); msg->msg_namelen = sizeof(*sipx);
if(sipx) if (sipx) {
{
sipx->sipx_family = AF_IPX; sipx->sipx_family = AF_IPX;
sipx->sipx_port = ispxh->ipx.ipx_source.sock; sipx->sipx_port = ispxh->ipx.ipx_source.sock;
memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN); memcpy(sipx->sipx_node,ispxh->ipx.ipx_source.node,IPX_NODE_LEN);
sipx->sipx_network = ispxh->ipx.ipx_source.net; sipx->sipx_network = ispxh->ipx.ipx_source.net;
sipx->sipx_type = ispxh->ipx.ipx_type; sipx->sipx_type = ispxh->ipx.ipx_type;
} }
rc = copied;
out_kfree_skb:
kfree_skb(skb); kfree_skb(skb);
release_sock(sk); out_release_sock:
release_sock(sk);
return (copied); out: return rc;
} }
/* /*
...@@ -847,41 +805,31 @@ static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size, ...@@ -847,41 +805,31 @@ static int spx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) static int spx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{ {
int err; return ipx_ops->bind(sock, uaddr, addr_len);
err = ipx_operations->bind(sock, uaddr, addr_len);
return (err);
} }
static int spx_getname (struct socket *sock, struct sockaddr *uaddr, static int spx_getname (struct socket *sock, struct sockaddr *uaddr,
int *usockaddr_len, int peer) int *usockaddr_len, int peer)
{ {
int err; return ipx_ops->getname(sock, uaddr, usockaddr_len, peer);
err = ipx_operations->getname(sock, uaddr, usockaddr_len, peer);
return (err);
} }
static int spx_ioctl (struct socket *sock, unsigned int cmd, static int spx_ioctl (struct socket *sock, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
int err; return ipx_ops->ioctl(sock, cmd, arg);
err = ipx_operations->ioctl(sock, cmd, arg);
return (err);
} }
static int spx_setsockopt(struct socket *sock, int level, int optname, static int spx_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
int err; return ipx_ops->setsockopt(sock, level, optname, optval, optlen);
err = ipx_operations->setsockopt(sock, level, optname, optval, optlen);
return (err);
} }
static int spx_getsockopt(struct socket *sock, int level, int optname, static int spx_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
int err; return ipx_ops->getsockopt(sock, level, optname, optval, optlen);
err = ipx_operations->getsockopt(sock, level, optname, optval, optlen);
return (err);
} }
static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = { static struct proto_ops SOCKOPS_WRAPPED(spx_ops) = {
...@@ -911,16 +859,13 @@ SOCKOPS_WRAP(spx, PF_IPX); ...@@ -911,16 +859,13 @@ SOCKOPS_WRAP(spx, PF_IPX);
static struct net_proto_family spx_family_ops = { static struct net_proto_family spx_family_ops = {
family: PF_IPX, family: PF_IPX,
create: spx_create, create: spx_create,
sk_size: sizeof(struct sock) + sizeof(struct ipx_opt) +
sizeof(struct spx_opt),
}; };
static char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n"; static char banner[] __initdata =
KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.03\n";
static int __init spx_proto_init(void) static int __init spx_proto_init(void)
{ {
int error;
connids = (__u16)jiffies; /* initalize random */ connids = (__u16)jiffies; /* initalize random */
/* allocate our sock slab cache */ /* allocate our sock slab cache */
...@@ -933,8 +878,7 @@ static int __init spx_proto_init(void) ...@@ -933,8 +878,7 @@ static int __init spx_proto_init(void)
printk(KERN_CRIT __FUNCTION__ printk(KERN_CRIT __FUNCTION__
": Cannot create spx_sock SLAB cache!\n"); ": Cannot create spx_sock SLAB cache!\n");
error = ipx_register_spx(&ipx_operations, &spx_family_ops); if (ipx_register_spx(&ipx_ops, &spx_family_ops))
if (error)
printk(KERN_ERR "SPX: unable to register with IPX.\n"); printk(KERN_ERR "SPX: unable to register with IPX.\n");
/* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */ /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
...@@ -942,11 +886,12 @@ static int __init spx_proto_init(void) ...@@ -942,11 +886,12 @@ static int __init spx_proto_init(void)
printk(banner); printk(banner);
return 0; return 0;
} }
module_init(spx_proto_init);
static void __exit spx_proto_finito(void) static void __exit spx_proto_finito(void)
{ {
ipx_unregister_spx(); ipx_unregister_spx();
return;
} }
module_init(spx_proto_init);
module_exit(spx_proto_finito); module_exit(spx_proto_finito);
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment