*
* 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
*
* 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.
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);
* 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;
{
struct sock *sk = sock->sk;
int val, len, rc = -ENOPROTOOPT;
-
+
if (level != SOL_X25 || optname != X25_QBITINCL)
goto out;
rc = -EINVAL;
if (len < 0)
goto out;
-
+
rc = -EFAULT;
if (put_user(len, optlen))
goto out;
return sk;
}
-void x25_init_timers(struct sock *sk);
-
static int x25_create(struct socket *sock, int protocol)
{
struct sock *sk;
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:
break;
}
- sock->sk = NULL;
+ sock->sk = NULL;
sk->sk_socket = NULL; /* Not used, but we should do this */
out:
return 0;
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 (;;) {
if (sk->sk_state == TCP_ESTABLISHED)
goto out;
- sk->sk_state = TCP_CLOSE;
+ sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
rc = -EINVAL;
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;
return 0;
}
-
+
int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
unsigned int lci)
{
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.
* 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
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.
* Incoming Call User Data.
*/
if (skb->len >= 0) {
- memcpy(makex25->calluserdata.cuddata, skb->data, skb->len);
+ skb_copy_from_linear_data(skb, makex25->calluserdata.cuddata, skb->len);
makex25->calluserdata.cudlength = skb->len;
}
*/
SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n");
- asmptr = skb->h.raw = skb_put(skb, len);
+ skb_reset_transport_header(skb);
+ skb_put(skb, len);
- rc = memcpy_fromiovec(asmptr, msg->msg_iov, len);
+ rc = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
if (rc)
goto out_kfree_skb;
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)
}
}
- skb->h.raw = skb->data;
-
+ skb_reset_transport_header(skb);
copied = skb->len;
if (copied > size) {
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);
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 SIOCGSTAMPNS:
+ rc = -EINVAL;
+ if (sk)
+ rc = sock_get_timestampns(sk,
+ (struct timespec __user *)argp);
break;
case SIOCGIFADDR:
case SIOCSIFADDR:
}
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 &&
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;
break;
}
- default:
+ default:
rc = -ENOIOCTLCMD;
break;
}
rc = compat_sock_get_timestamp(sk,
(struct timeval __user*)argp);
break;
+ case SIOCGSTAMPNS:
+ rc = -EINVAL;
+ if (sk)
+ rc = compat_sock_get_timestampns(sk,
+ (struct timespec __user*)argp);
+ break;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
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)