diff options
Diffstat (limited to 'net/x25/af_x25.c')
-rw-r--r-- | net/x25/af_x25.c | 96 |
1 files changed, 59 insertions, 37 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index b5c80b18990..e62ba41b05c 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -3,7 +3,7 @@ * * This is ALPHA test software. This code may break your machine, * randomly fail to work with new releases, misbehave and/or generally - * screw up. It might even work. + * screw up. It might even work. * * This code REQUIRES 2.1.15 or higher * @@ -18,11 +18,11 @@ * X.25 002 Jonathan Naylor Centralised disconnect handling. * New timer architecture. * 2000-03-11 Henner Eisen MSG_EOR handling more POSIX compliant. - * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of - * facilities negotiation and increased + * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of + * facilities negotiation and increased * the throughput upper limit. * 2000-08-27 Arnaldo C. Melo s/suser/capable/ + micro cleanups - * 2000-09-04 Henner Eisen Set sock->state in x25_accept(). + * 2000-09-04 Henner Eisen Set sock->state in x25_accept(). * Fixed x25_output() related skb leakage. * 2000-10-02 Henner Eisen Made x25_kick() single threaded per socket. * 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation. @@ -63,6 +63,7 @@ int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; +int sysctl_x25_forward = 0; HLIST_HEAD(x25_list); DEFINE_RWLOCK(x25_list_lock); @@ -255,8 +256,8 @@ static struct sock *x25_find_listener(struct x25_address *addr, * call user data vs this sockets call user data */ if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) { - if((memcmp(x25_sk(s)->calluserdata.cuddata, - skb->data, + if((memcmp(x25_sk(s)->calluserdata.cuddata, + skb->data, x25_sk(s)->cudmatchlength)) == 0) { sock_hold(s); goto found; @@ -420,7 +421,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; int val, len, rc = -ENOPROTOOPT; - + if (level != SOL_X25 || optname != X25_QBITINCL) goto out; @@ -433,7 +434,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, rc = -EINVAL; if (len < 0) goto out; - + rc = -EFAULT; if (put_user(len, optlen)) goto out; @@ -522,12 +523,12 @@ static int x25_create(struct socket *sock, int protocol) x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; x25->facilities.reverse = X25_DEFAULT_REVERSE; - x25->dte_facilities.calling_len = 0; - x25->dte_facilities.called_len = 0; - memset(x25->dte_facilities.called_ae, '\0', - sizeof(x25->dte_facilities.called_ae)); - memset(x25->dte_facilities.calling_ae, '\0', - sizeof(x25->dte_facilities.calling_ae)); + x25->dte_facilities.calling_len = 0; + x25->dte_facilities.called_len = 0; + memset(x25->dte_facilities.called_ae, '\0', + sizeof(x25->dte_facilities.called_ae)); + memset(x25->dte_facilities.calling_ae, '\0', + sizeof(x25->dte_facilities.calling_ae)); rc = 0; out: @@ -607,7 +608,7 @@ static int x25_release(struct socket *sock) break; } - sock->sk = NULL; + sock->sk = NULL; sk->sk_socket = NULL; /* Not used, but we should do this */ out: return 0; @@ -634,7 +635,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) static int x25_wait_for_connection_establishment(struct sock *sk) { DECLARE_WAITQUEUE(wait, current); - int rc; + int rc; add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { @@ -685,7 +686,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, if (sk->sk_state == TCP_ESTABLISHED) goto out; - sk->sk_state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; rc = -EINVAL; @@ -777,7 +778,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout) remove_wait_queue(sk->sk_sleep, &wait); return rc; } - + static int x25_accept(struct socket *sock, struct socket *newsock, int flags) { struct sock *sk = sock->sk; @@ -836,7 +837,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, return 0; } - + int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, unsigned int lci) { @@ -846,7 +847,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, struct x25_address source_addr, dest_addr; struct x25_facilities facilities; struct x25_dte_facilities dte_facilities; - int len, rc; + int len, addr_len, rc; /* * Remove the LCI and frame type. @@ -857,7 +858,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, * Extract the X.25 addresses and convert them to ASCII strings, * and remove them. */ - skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); + addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr); + skb_pull(skb, addr_len); /* * Get the length of the facilities, skip past them for the moment @@ -873,11 +875,28 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, sk = x25_find_listener(&source_addr,skb); skb_push(skb,len); + if (sk != NULL && sk_acceptq_is_full(sk)) { + goto out_sock_put; + } + /* - * We can't accept the Call Request. + * We dont have any listeners for this incoming call. + * Try forwarding it. */ - if (sk == NULL || sk_acceptq_is_full(sk)) - goto out_clear_request; + if (sk == NULL) { + skb_push(skb, addr_len + X25_STD_MIN_LEN); + if (sysctl_x25_forward && + x25_forward_call(&dest_addr, nb, skb, lci) > 0) + { + /* Call was forwarded, dont process it any more */ + kfree_skb(skb); + rc = 1; + goto out; + } else { + /* No listeners, can't forward, clear the call */ + goto out_clear_request; + } + } /* * Try to reach a compromise on the requested facilities. @@ -1101,7 +1120,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_flags & MSG_OOB) skb_queue_tail(&x25->interrupt_out_queue, skb); else { - len = x25_output(sk, skb); + len = x25_output(sk, skb); if (len < 0) kfree_skb(skb); else if (x25->qbitincl) @@ -1200,7 +1219,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, msg->msg_flags |= MSG_TRUNC; } - /* Currently, each datagram always contains a complete record */ + /* Currently, each datagram always contains a complete record */ msg->msg_flags |= MSG_EOR; rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); @@ -1258,8 +1277,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCGSTAMP: rc = -EINVAL; if (sk) - rc = sock_get_timestamp(sk, - (struct timeval __user *)argp); + rc = sock_get_timestamp(sk, + (struct timeval __user *)argp); break; case SIOCGIFADDR: case SIOCSIFADDR: @@ -1327,17 +1346,17 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } case SIOCX25GDTEFACILITIES: { - rc = copy_to_user(argp, &x25->dte_facilities, + rc = copy_to_user(argp, &x25->dte_facilities, sizeof(x25->dte_facilities)); if (rc) rc = -EFAULT; - break; - } + break; + } - case SIOCX25SDTEFACILITIES: { - struct x25_dte_facilities dtefacs; - rc = -EFAULT; - if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) + case SIOCX25SDTEFACILITIES: { + struct x25_dte_facilities dtefacs; + rc = -EFAULT; + if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) break; rc = -EINVAL; if (sk->sk_state != TCP_LISTEN && @@ -1395,7 +1414,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (copy_from_user(&sub_addr, argp, sizeof(sub_addr))) break; - rc = -EINVAL; + rc = -EINVAL; if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) break; x25->cudmatchlength = sub_addr.cudmatchlength; @@ -1424,7 +1443,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; } - default: + default: rc = -ENOIOCTLCMD; break; } @@ -1598,6 +1617,9 @@ void x25_kill_by_neigh(struct x25_neigh *nb) x25_disconnect(s, ENETUNREACH, 0, 0); write_unlock_bh(&x25_list_lock); + + /* Remove any related forwards */ + x25_clear_forward_by_dev(nb->dev); } static int __init x25_init(void) |