aboutsummaryrefslogtreecommitdiffstats
path: root/net/x25
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-02-13 01:43:25 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-02-13 01:43:25 -0500
commitd9bc125caf592b7d081021f32ce5b717efdf70c8 (patch)
tree263b7066ba22ddce21db610c0300f6eaac6f2064 /net/x25
parent43d78ef2ba5bec26d0315859e8324bfc0be23766 (diff)
parentec2f9d1331f658433411c58077871e1eef4ee1b4 (diff)
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Conflicts: net/sunrpc/auth_gss/gss_krb5_crypto.c net/sunrpc/auth_gss/gss_spkm3_token.c net/sunrpc/clnt.c Merge with mainline and fix conflicts.
Diffstat (limited to 'net/x25')
-rw-r--r--net/x25/Makefile2
-rw-r--r--net/x25/af_x25.c96
-rw-r--r--net/x25/sysctl_net_x25.c18
-rw-r--r--net/x25/x25_dev.c19
-rw-r--r--net/x25/x25_facilities.c10
-rw-r--r--net/x25/x25_forward.c163
-rw-r--r--net/x25/x25_in.c8
-rw-r--r--net/x25/x25_link.c6
-rw-r--r--net/x25/x25_out.c10
-rw-r--r--net/x25/x25_proc.c110
-rw-r--r--net/x25/x25_route.c5
-rw-r--r--net/x25/x25_timer.c6
12 files changed, 378 insertions, 75 deletions
diff --git a/net/x25/Makefile b/net/x25/Makefile
index 587a71aa411d..a2c34ab6f194 100644
--- a/net/x25/Makefile
+++ b/net/x25/Makefile
@@ -6,5 +6,5 @@ obj-$(CONFIG_X25) += x25.o
6 6
7x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \ 7x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \
8 x25_link.o x25_out.o x25_route.o x25_subr.o \ 8 x25_link.o x25_out.o x25_route.o x25_subr.o \
9 x25_timer.o x25_proc.o 9 x25_timer.o x25_proc.o x25_forward.o
10x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o 10x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index b5c80b189902..e62ba41b05c5 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -18,11 +18,11 @@
18 * X.25 002 Jonathan Naylor Centralised disconnect handling. 18 * X.25 002 Jonathan Naylor Centralised disconnect handling.
19 * New timer architecture. 19 * New timer architecture.
20 * 2000-03-11 Henner Eisen MSG_EOR handling more POSIX compliant. 20 * 2000-03-11 Henner Eisen MSG_EOR handling more POSIX compliant.
21 * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of 21 * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of
22 * facilities negotiation and increased 22 * facilities negotiation and increased
23 * the throughput upper limit. 23 * the throughput upper limit.
24 * 2000-08-27 Arnaldo C. Melo s/suser/capable/ + micro cleanups 24 * 2000-08-27 Arnaldo C. Melo s/suser/capable/ + micro cleanups
25 * 2000-09-04 Henner Eisen Set sock->state in x25_accept(). 25 * 2000-09-04 Henner Eisen Set sock->state in x25_accept().
26 * Fixed x25_output() related skb leakage. 26 * Fixed x25_output() related skb leakage.
27 * 2000-10-02 Henner Eisen Made x25_kick() single threaded per socket. 27 * 2000-10-02 Henner Eisen Made x25_kick() single threaded per socket.
28 * 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation. 28 * 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation.
@@ -63,6 +63,7 @@ int sysctl_x25_call_request_timeout = X25_DEFAULT_T21;
63int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; 63int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22;
64int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; 64int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23;
65int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; 65int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2;
66int sysctl_x25_forward = 0;
66 67
67HLIST_HEAD(x25_list); 68HLIST_HEAD(x25_list);
68DEFINE_RWLOCK(x25_list_lock); 69DEFINE_RWLOCK(x25_list_lock);
@@ -255,8 +256,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
255 * call user data vs this sockets call user data 256 * call user data vs this sockets call user data
256 */ 257 */
257 if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) { 258 if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
258 if((memcmp(x25_sk(s)->calluserdata.cuddata, 259 if((memcmp(x25_sk(s)->calluserdata.cuddata,
259 skb->data, 260 skb->data,
260 x25_sk(s)->cudmatchlength)) == 0) { 261 x25_sk(s)->cudmatchlength)) == 0) {
261 sock_hold(s); 262 sock_hold(s);
262 goto found; 263 goto found;
@@ -420,7 +421,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
420{ 421{
421 struct sock *sk = sock->sk; 422 struct sock *sk = sock->sk;
422 int val, len, rc = -ENOPROTOOPT; 423 int val, len, rc = -ENOPROTOOPT;
423 424
424 if (level != SOL_X25 || optname != X25_QBITINCL) 425 if (level != SOL_X25 || optname != X25_QBITINCL)
425 goto out; 426 goto out;
426 427
@@ -433,7 +434,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
433 rc = -EINVAL; 434 rc = -EINVAL;
434 if (len < 0) 435 if (len < 0)
435 goto out; 436 goto out;
436 437
437 rc = -EFAULT; 438 rc = -EFAULT;
438 if (put_user(len, optlen)) 439 if (put_user(len, optlen))
439 goto out; 440 goto out;
@@ -522,12 +523,12 @@ static int x25_create(struct socket *sock, int protocol)
522 x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; 523 x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
523 x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; 524 x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
524 x25->facilities.reverse = X25_DEFAULT_REVERSE; 525 x25->facilities.reverse = X25_DEFAULT_REVERSE;
525 x25->dte_facilities.calling_len = 0; 526 x25->dte_facilities.calling_len = 0;
526 x25->dte_facilities.called_len = 0; 527 x25->dte_facilities.called_len = 0;
527 memset(x25->dte_facilities.called_ae, '\0', 528 memset(x25->dte_facilities.called_ae, '\0',
528 sizeof(x25->dte_facilities.called_ae)); 529 sizeof(x25->dte_facilities.called_ae));
529 memset(x25->dte_facilities.calling_ae, '\0', 530 memset(x25->dte_facilities.calling_ae, '\0',
530 sizeof(x25->dte_facilities.calling_ae)); 531 sizeof(x25->dte_facilities.calling_ae));
531 532
532 rc = 0; 533 rc = 0;
533out: 534out:
@@ -607,7 +608,7 @@ static int x25_release(struct socket *sock)
607 break; 608 break;
608 } 609 }
609 610
610 sock->sk = NULL; 611 sock->sk = NULL;
611 sk->sk_socket = NULL; /* Not used, but we should do this */ 612 sk->sk_socket = NULL; /* Not used, but we should do this */
612out: 613out:
613 return 0; 614 return 0;
@@ -634,7 +635,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
634static int x25_wait_for_connection_establishment(struct sock *sk) 635static int x25_wait_for_connection_establishment(struct sock *sk)
635{ 636{
636 DECLARE_WAITQUEUE(wait, current); 637 DECLARE_WAITQUEUE(wait, current);
637 int rc; 638 int rc;
638 639
639 add_wait_queue_exclusive(sk->sk_sleep, &wait); 640 add_wait_queue_exclusive(sk->sk_sleep, &wait);
640 for (;;) { 641 for (;;) {
@@ -685,7 +686,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
685 if (sk->sk_state == TCP_ESTABLISHED) 686 if (sk->sk_state == TCP_ESTABLISHED)
686 goto out; 687 goto out;
687 688
688 sk->sk_state = TCP_CLOSE; 689 sk->sk_state = TCP_CLOSE;
689 sock->state = SS_UNCONNECTED; 690 sock->state = SS_UNCONNECTED;
690 691
691 rc = -EINVAL; 692 rc = -EINVAL;
@@ -777,7 +778,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout)
777 remove_wait_queue(sk->sk_sleep, &wait); 778 remove_wait_queue(sk->sk_sleep, &wait);
778 return rc; 779 return rc;
779} 780}
780 781
781static int x25_accept(struct socket *sock, struct socket *newsock, int flags) 782static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
782{ 783{
783 struct sock *sk = sock->sk; 784 struct sock *sk = sock->sk;
@@ -836,7 +837,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
836 837
837 return 0; 838 return 0;
838} 839}
839 840
840int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, 841int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
841 unsigned int lci) 842 unsigned int lci)
842{ 843{
@@ -846,7 +847,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
846 struct x25_address source_addr, dest_addr; 847 struct x25_address source_addr, dest_addr;
847 struct x25_facilities facilities; 848 struct x25_facilities facilities;
848 struct x25_dte_facilities dte_facilities; 849 struct x25_dte_facilities dte_facilities;
849 int len, rc; 850 int len, addr_len, rc;
850 851
851 /* 852 /*
852 * Remove the LCI and frame type. 853 * Remove the LCI and frame type.
@@ -857,7 +858,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
857 * Extract the X.25 addresses and convert them to ASCII strings, 858 * Extract the X.25 addresses and convert them to ASCII strings,
858 * and remove them. 859 * and remove them.
859 */ 860 */
860 skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); 861 addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
862 skb_pull(skb, addr_len);
861 863
862 /* 864 /*
863 * Get the length of the facilities, skip past them for the moment 865 * 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,
873 sk = x25_find_listener(&source_addr,skb); 875 sk = x25_find_listener(&source_addr,skb);
874 skb_push(skb,len); 876 skb_push(skb,len);
875 877
878 if (sk != NULL && sk_acceptq_is_full(sk)) {
879 goto out_sock_put;
880 }
881
876 /* 882 /*
877 * We can't accept the Call Request. 883 * We dont have any listeners for this incoming call.
884 * Try forwarding it.
878 */ 885 */
879 if (sk == NULL || sk_acceptq_is_full(sk)) 886 if (sk == NULL) {
880 goto out_clear_request; 887 skb_push(skb, addr_len + X25_STD_MIN_LEN);
888 if (sysctl_x25_forward &&
889 x25_forward_call(&dest_addr, nb, skb, lci) > 0)
890 {
891 /* Call was forwarded, dont process it any more */
892 kfree_skb(skb);
893 rc = 1;
894 goto out;
895 } else {
896 /* No listeners, can't forward, clear the call */
897 goto out_clear_request;
898 }
899 }
881 900
882 /* 901 /*
883 * Try to reach a compromise on the requested facilities. 902 * Try to reach a compromise on the requested facilities.
@@ -1101,7 +1120,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
1101 if (msg->msg_flags & MSG_OOB) 1120 if (msg->msg_flags & MSG_OOB)
1102 skb_queue_tail(&x25->interrupt_out_queue, skb); 1121 skb_queue_tail(&x25->interrupt_out_queue, skb);
1103 else { 1122 else {
1104 len = x25_output(sk, skb); 1123 len = x25_output(sk, skb);
1105 if (len < 0) 1124 if (len < 0)
1106 kfree_skb(skb); 1125 kfree_skb(skb);
1107 else if (x25->qbitincl) 1126 else if (x25->qbitincl)
@@ -1200,7 +1219,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
1200 msg->msg_flags |= MSG_TRUNC; 1219 msg->msg_flags |= MSG_TRUNC;
1201 } 1220 }
1202 1221
1203 /* Currently, each datagram always contains a complete record */ 1222 /* Currently, each datagram always contains a complete record */
1204 msg->msg_flags |= MSG_EOR; 1223 msg->msg_flags |= MSG_EOR;
1205 1224
1206 rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 1225 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)
1258 case SIOCGSTAMP: 1277 case SIOCGSTAMP:
1259 rc = -EINVAL; 1278 rc = -EINVAL;
1260 if (sk) 1279 if (sk)
1261 rc = sock_get_timestamp(sk, 1280 rc = sock_get_timestamp(sk,
1262 (struct timeval __user *)argp); 1281 (struct timeval __user *)argp);
1263 break; 1282 break;
1264 case SIOCGIFADDR: 1283 case SIOCGIFADDR:
1265 case SIOCSIFADDR: 1284 case SIOCSIFADDR:
@@ -1327,17 +1346,17 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
1327 } 1346 }
1328 1347
1329 case SIOCX25GDTEFACILITIES: { 1348 case SIOCX25GDTEFACILITIES: {
1330 rc = copy_to_user(argp, &x25->dte_facilities, 1349 rc = copy_to_user(argp, &x25->dte_facilities,
1331 sizeof(x25->dte_facilities)); 1350 sizeof(x25->dte_facilities));
1332 if (rc) 1351 if (rc)
1333 rc = -EFAULT; 1352 rc = -EFAULT;
1334 break; 1353 break;
1335 } 1354 }
1336 1355
1337 case SIOCX25SDTEFACILITIES: { 1356 case SIOCX25SDTEFACILITIES: {
1338 struct x25_dte_facilities dtefacs; 1357 struct x25_dte_facilities dtefacs;
1339 rc = -EFAULT; 1358 rc = -EFAULT;
1340 if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) 1359 if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
1341 break; 1360 break;
1342 rc = -EINVAL; 1361 rc = -EINVAL;
1343 if (sk->sk_state != TCP_LISTEN && 1362 if (sk->sk_state != TCP_LISTEN &&
@@ -1395,7 +1414,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
1395 if (copy_from_user(&sub_addr, argp, 1414 if (copy_from_user(&sub_addr, argp,
1396 sizeof(sub_addr))) 1415 sizeof(sub_addr)))
1397 break; 1416 break;
1398 rc = -EINVAL; 1417 rc = -EINVAL;
1399 if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) 1418 if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
1400 break; 1419 break;
1401 x25->cudmatchlength = sub_addr.cudmatchlength; 1420 x25->cudmatchlength = sub_addr.cudmatchlength;
@@ -1424,7 +1443,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
1424 break; 1443 break;
1425 } 1444 }
1426 1445
1427 default: 1446 default:
1428 rc = -ENOIOCTLCMD; 1447 rc = -ENOIOCTLCMD;
1429 break; 1448 break;
1430 } 1449 }
@@ -1598,6 +1617,9 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
1598 x25_disconnect(s, ENETUNREACH, 0, 0); 1617 x25_disconnect(s, ENETUNREACH, 0, 0);
1599 1618
1600 write_unlock_bh(&x25_list_lock); 1619 write_unlock_bh(&x25_list_lock);
1620
1621 /* Remove any related forwards */
1622 x25_clear_forward_by_dev(nb->dev);
1601} 1623}
1602 1624
1603static int __init x25_init(void) 1625static int __init x25_init(void)
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index aabda59c824e..5f631061c229 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -18,7 +18,7 @@ static int max_timer[] = { 300 * HZ };
18static struct ctl_table_header *x25_table_header; 18static struct ctl_table_header *x25_table_header;
19 19
20static struct ctl_table x25_table[] = { 20static struct ctl_table x25_table[] = {
21 { 21 {
22 .ctl_name = NET_X25_RESTART_REQUEST_TIMEOUT, 22 .ctl_name = NET_X25_RESTART_REQUEST_TIMEOUT,
23 .procname = "restart_request_timeout", 23 .procname = "restart_request_timeout",
24 .data = &sysctl_x25_restart_request_timeout, 24 .data = &sysctl_x25_restart_request_timeout,
@@ -29,7 +29,7 @@ static struct ctl_table x25_table[] = {
29 .extra1 = &min_timer, 29 .extra1 = &min_timer,
30 .extra2 = &max_timer, 30 .extra2 = &max_timer,
31 }, 31 },
32 { 32 {
33 .ctl_name = NET_X25_CALL_REQUEST_TIMEOUT, 33 .ctl_name = NET_X25_CALL_REQUEST_TIMEOUT,
34 .procname = "call_request_timeout", 34 .procname = "call_request_timeout",
35 .data = &sysctl_x25_call_request_timeout, 35 .data = &sysctl_x25_call_request_timeout,
@@ -40,7 +40,7 @@ static struct ctl_table x25_table[] = {
40 .extra1 = &min_timer, 40 .extra1 = &min_timer,
41 .extra2 = &max_timer, 41 .extra2 = &max_timer,
42 }, 42 },
43 { 43 {
44 .ctl_name = NET_X25_RESET_REQUEST_TIMEOUT, 44 .ctl_name = NET_X25_RESET_REQUEST_TIMEOUT,
45 .procname = "reset_request_timeout", 45 .procname = "reset_request_timeout",
46 .data = &sysctl_x25_reset_request_timeout, 46 .data = &sysctl_x25_reset_request_timeout,
@@ -51,7 +51,7 @@ static struct ctl_table x25_table[] = {
51 .extra1 = &min_timer, 51 .extra1 = &min_timer,
52 .extra2 = &max_timer, 52 .extra2 = &max_timer,
53 }, 53 },
54 { 54 {
55 .ctl_name = NET_X25_CLEAR_REQUEST_TIMEOUT, 55 .ctl_name = NET_X25_CLEAR_REQUEST_TIMEOUT,
56 .procname = "clear_request_timeout", 56 .procname = "clear_request_timeout",
57 .data = &sysctl_x25_clear_request_timeout, 57 .data = &sysctl_x25_clear_request_timeout,
@@ -62,7 +62,7 @@ static struct ctl_table x25_table[] = {
62 .extra1 = &min_timer, 62 .extra1 = &min_timer,
63 .extra2 = &max_timer, 63 .extra2 = &max_timer,
64 }, 64 },
65 { 65 {
66 .ctl_name = NET_X25_ACK_HOLD_BACK_TIMEOUT, 66 .ctl_name = NET_X25_ACK_HOLD_BACK_TIMEOUT,
67 .procname = "acknowledgement_hold_back_timeout", 67 .procname = "acknowledgement_hold_back_timeout",
68 .data = &sysctl_x25_ack_holdback_timeout, 68 .data = &sysctl_x25_ack_holdback_timeout,
@@ -73,6 +73,14 @@ static struct ctl_table x25_table[] = {
73 .extra1 = &min_timer, 73 .extra1 = &min_timer,
74 .extra2 = &max_timer, 74 .extra2 = &max_timer,
75 }, 75 },
76 {
77 .ctl_name = NET_X25_FORWARD,
78 .procname = "x25_forward",
79 .data = &sysctl_x25_forward,
80 .maxlen = sizeof(int),
81 .mode = 0644,
82 .proc_handler = &proc_dointvec,
83 },
76 { 0, }, 84 { 0, },
77}; 85};
78 86
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index 328d80f000ad..c7221de98a95 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * X.25 Packet Layer release 002 2 * X.25 Packet Layer release 002
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, randomly fail to work with new 4 * This is ALPHA test software. This code may break your machine, randomly fail to work with new
5 * releases, misbehave and/or generally screw up. It might even work. 5 * releases, misbehave and/or generally screw up. It might even work.
6 * 6 *
7 * This code REQUIRES 2.1.15 or higher 7 * This code REQUIRES 2.1.15 or higher
8 * 8 *
@@ -31,7 +31,7 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
31 unsigned int lci; 31 unsigned int lci;
32 32
33 frametype = skb->data[2]; 33 frametype = skb->data[2];
34 lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); 34 lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
35 35
36 /* 36 /*
37 * LCI of zero is always for us, and its always a link control 37 * LCI of zero is always for us, and its always a link control
@@ -67,9 +67,18 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
67 return x25_rx_call_request(skb, nb, lci); 67 return x25_rx_call_request(skb, nb, lci);
68 68
69 /* 69 /*
70 * Its not a Call Request, nor is it a control frame. 70 * Its not a Call Request, nor is it a control frame.
71 * Let caller throw it away. 71 * Can we forward it?
72 */ 72 */
73
74 if (x25_forward_data(lci, nb, skb)) {
75 if (frametype == X25_CLEAR_CONFIRMATION) {
76 x25_clear_forward_by_lci(lci);
77 }
78 kfree_skb(skb);
79 return 1;
80 }
81
73/* 82/*
74 x25_transmit_clear_request(nb, lci, 0x0D); 83 x25_transmit_clear_request(nb, lci, 0x0D);
75*/ 84*/
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
index 27f5cc7966f6..dec404afa113 100644
--- a/net/x25/x25_facilities.c
+++ b/net/x25/x25_facilities.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -15,7 +15,7 @@
15 * 15 *
16 * History 16 * History
17 * X.25 001 Split from x25_subr.c 17 * X.25 001 Split from x25_subr.c
18 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 18 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
19 * negotiation. 19 * negotiation.
20 * apr/14/05 Shaun Pereira - Allow fast select with no restriction 20 * apr/14/05 Shaun Pereira - Allow fast select with no restriction
21 * on response. 21 * on response.
@@ -125,8 +125,8 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
125 break; 125 break;
126 case X25_FAC_CLASS_D: 126 case X25_FAC_CLASS_D:
127 switch (*p) { 127 switch (*p) {
128 case X25_FAC_CALLING_AE: 128 case X25_FAC_CALLING_AE:
129 if (p[1] > X25_MAX_DTE_FACIL_LEN) 129 if (p[1] > X25_MAX_DTE_FACIL_LEN)
130 break; 130 break;
131 dte_facs->calling_len = p[2]; 131 dte_facs->calling_len = p[2];
132 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); 132 memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
@@ -293,7 +293,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
293} 293}
294 294
295/* 295/*
296 * Limit values of certain facilities according to the capability of the 296 * Limit values of certain facilities according to the capability of the
297 * currently attached x25 link. 297 * currently attached x25 link.
298 */ 298 */
299void x25_limit_facilities(struct x25_facilities *facilities, 299void x25_limit_facilities(struct x25_facilities *facilities,
diff --git a/net/x25/x25_forward.c b/net/x25/x25_forward.c
new file mode 100644
index 000000000000..d339e0c810a8
--- /dev/null
+++ b/net/x25/x25_forward.c
@@ -0,0 +1,163 @@
1/*
2 * This module:
3 * This module is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
7 *
8 * History
9 * 03-01-2007 Added forwarding for x.25 Andrew Hendry
10 */
11#include <linux/if_arp.h>
12#include <linux/init.h>
13#include <net/x25.h>
14
15struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list);
16DEFINE_RWLOCK(x25_forward_list_lock);
17
18int x25_forward_call(struct x25_address *dest_addr, struct x25_neigh *from,
19 struct sk_buff *skb, int lci)
20{
21 struct x25_route *rt;
22 struct x25_neigh *neigh_new = NULL;
23 struct list_head *entry;
24 struct x25_forward *x25_frwd, *new_frwd;
25 struct sk_buff *skbn;
26 short same_lci = 0;
27 int rc = 0;
28
29 if ((rt = x25_get_route(dest_addr)) != NULL) {
30
31 if ((neigh_new = x25_get_neigh(rt->dev)) == NULL) {
32 /* This shouldnt happen, if it occurs somehow
33 * do something sensible
34 */
35 goto out_put_route;
36 }
37
38 /* Avoid a loop. This is the normal exit path for a
39 * system with only one x.25 iface and default route
40 */
41 if (rt->dev == from->dev) {
42 goto out_put_nb;
43 }
44
45 /* Remote end sending a call request on an already
46 * established LCI? It shouldnt happen, just in case..
47 */
48 read_lock_bh(&x25_forward_list_lock);
49 list_for_each(entry, &x25_forward_list) {
50 x25_frwd = list_entry(entry, struct x25_forward, node);
51 if (x25_frwd->lci == lci) {
52 printk(KERN_WARNING "X.25: call request for lci which is already registered!, transmitting but not registering new pair\n");
53 same_lci = 1;
54 }
55 }
56 read_unlock_bh(&x25_forward_list_lock);
57
58 /* Save the forwarding details for future traffic */
59 if (!same_lci){
60 if ((new_frwd = kmalloc(sizeof(struct x25_forward),
61 GFP_ATOMIC)) == NULL){
62 rc = -ENOMEM;
63 goto out_put_nb;
64 }
65 new_frwd->lci = lci;
66 new_frwd->dev1 = rt->dev;
67 new_frwd->dev2 = from->dev;
68 write_lock_bh(&x25_forward_list_lock);
69 list_add(&new_frwd->node, &x25_forward_list);
70 write_unlock_bh(&x25_forward_list_lock);
71 }
72
73 /* Forward the call request */
74 if ( (skbn = skb_clone(skb, GFP_ATOMIC)) == NULL){
75 goto out_put_nb;
76 }
77 x25_transmit_link(skbn, neigh_new);
78 rc = 1;
79 }
80
81
82out_put_nb:
83 x25_neigh_put(neigh_new);
84
85out_put_route:
86 x25_route_put(rt);
87 return rc;
88}
89
90
91int x25_forward_data(int lci, struct x25_neigh *from, struct sk_buff *skb) {
92
93 struct x25_forward *frwd;
94 struct list_head *entry;
95 struct net_device *peer = NULL;
96 struct x25_neigh *nb;
97 struct sk_buff *skbn;
98 int rc = 0;
99
100 read_lock_bh(&x25_forward_list_lock);
101 list_for_each(entry, &x25_forward_list) {
102 frwd = list_entry(entry, struct x25_forward, node);
103 if (frwd->lci == lci) {
104 /* The call is established, either side can send */
105 if (from->dev == frwd->dev1) {
106 peer = frwd->dev2;
107 } else {
108 peer = frwd->dev1;
109 }
110 break;
111 }
112 }
113 read_unlock_bh(&x25_forward_list_lock);
114
115 if ( (nb = x25_get_neigh(peer)) == NULL)
116 goto out;
117
118 if ( (skbn = pskb_copy(skb, GFP_ATOMIC)) == NULL){
119 goto out;
120
121 }
122 x25_transmit_link(skbn, nb);
123
124 x25_neigh_put(nb);
125 rc = 1;
126out:
127 return rc;
128}
129
130void x25_clear_forward_by_lci(unsigned int lci)
131{
132 struct x25_forward *fwd;
133 struct list_head *entry, *tmp;
134
135 write_lock_bh(&x25_forward_list_lock);
136
137 list_for_each_safe(entry, tmp, &x25_forward_list) {
138 fwd = list_entry(entry, struct x25_forward, node);
139 if (fwd->lci == lci) {
140 list_del(&fwd->node);
141 kfree(fwd);
142 }
143 }
144 write_unlock_bh(&x25_forward_list_lock);
145}
146
147
148void x25_clear_forward_by_dev(struct net_device *dev)
149{
150 struct x25_forward *fwd;
151 struct list_head *entry, *tmp;
152
153 write_lock_bh(&x25_forward_list_lock);
154
155 list_for_each_safe(entry, tmp, &x25_forward_list) {
156 fwd = list_entry(entry, struct x25_forward, node);
157 if ((fwd->dev1 == dev) || (fwd->dev2 == dev)){
158 list_del(&fwd->node);
159 kfree(fwd);
160 }
161 }
162 write_unlock_bh(&x25_forward_list_lock);
163}
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index eed50e10f09b..c5239fcdefa0 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -17,7 +17,7 @@
17 * X.25 001 Jonathan Naylor Started coding. 17 * X.25 001 Jonathan Naylor Started coding.
18 * X.25 002 Jonathan Naylor Centralised disconnection code. 18 * X.25 002 Jonathan Naylor Centralised disconnection code.
19 * New timer architecture. 19 * New timer architecture.
20 * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities 20 * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities
21 * negotiation. 21 * negotiation.
22 * 2000-11-10 Henner Eisen Check and reset for out-of-sequence 22 * 2000-11-10 Henner Eisen Check and reset for out-of-sequence
23 * i-frames. 23 * i-frames.
@@ -67,7 +67,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
67 kfree_skb(skbo); 67 kfree_skb(skbo);
68 } 68 }
69 69
70 x25->fraglen = 0; 70 x25->fraglen = 0;
71 } 71 }
72 72
73 skb_set_owner_r(skbn, sk); 73 skb_set_owner_r(skbn, sk);
@@ -167,7 +167,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
167 int queued = 0; 167 int queued = 0;
168 int modulus; 168 int modulus;
169 struct x25_sock *x25 = x25_sk(sk); 169 struct x25_sock *x25 = x25_sk(sk);
170 170
171 modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS; 171 modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
172 172
173 switch (frametype) { 173 switch (frametype) {
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
index 0a760fe66843..741ce95d4ad1 100644
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -16,7 +16,7 @@
16 * History 16 * History
17 * X.25 001 Jonathan Naylor Started coding. 17 * X.25 001 Jonathan Naylor Started coding.
18 * X.25 002 Jonathan Naylor New timer architecture. 18 * X.25 002 Jonathan Naylor New timer architecture.
19 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities 19 * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
20 * negotiation. 20 * negotiation.
21 * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh. 21 * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh.
22 */ 22 */
@@ -94,7 +94,7 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
94 skb->data[3], skb->data[4], 94 skb->data[3], skb->data[4],
95 skb->data[5], skb->data[6]); 95 skb->data[5], skb->data[6]);
96 break; 96 break;
97 97
98 default: 98 default:
99 printk(KERN_WARNING "x25: received unknown %02X " 99 printk(KERN_WARNING "x25: received unknown %02X "
100 "with LCI 000\n", frametype); 100 "with LCI 000\n", frametype);
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index a2e62cea819a..6f5737853912 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -78,7 +78,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
78 "sent\n", err, sent); 78 "sent\n", err, sent);
79 return err; 79 return err;
80 } 80 }
81 81
82 skb_reserve(skbn, frontlen); 82 skb_reserve(skbn, frontlen);
83 83
84 len = max_len > skb->len ? skb->len : max_len; 84 len = max_len > skb->len ? skb->len : max_len;
@@ -101,7 +101,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
101 skb_queue_tail(&sk->sk_write_queue, skbn); 101 skb_queue_tail(&sk->sk_write_queue, skbn);
102 sent += len; 102 sent += len;
103 } 103 }
104 104
105 kfree_skb(skb); 105 kfree_skb(skb);
106 } else { 106 } else {
107 skb_queue_tail(&sk->sk_write_queue, skb); 107 skb_queue_tail(&sk->sk_write_queue, skb);
@@ -110,7 +110,7 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
110 return sent; 110 return sent;
111} 111}
112 112
113/* 113/*
114 * This procedure is passed a buffer descriptor for an iframe. It builds 114 * This procedure is passed a buffer descriptor for an iframe. It builds
115 * the rest of the control part of the frame and then writes it out. 115 * the rest of the control part of the frame and then writes it out.
116 */ 116 */
@@ -131,7 +131,7 @@ static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
131 skb->data[2] |= (x25->vr << 5) & 0xE0; 131 skb->data[2] |= (x25->vr << 5) & 0xE0;
132 } 132 }
133 133
134 x25_transmit_link(skb, x25->neighbour); 134 x25_transmit_link(skb, x25->neighbour);
135} 135}
136 136
137void x25_kick(struct sock *sk) 137void x25_kick(struct sock *sk)
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index a11837d361d2..96001f0c64fc 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.4 with seq_file support 8 * This code REQUIRES 2.4 with seq_file support
9 * 9 *
@@ -62,7 +62,7 @@ static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
62 rt = v; 62 rt = v;
63 if (rt->node.next != &x25_route_list) 63 if (rt->node.next != &x25_route_list)
64 rt = list_entry(rt->node.next, struct x25_route, node); 64 rt = list_entry(rt->node.next, struct x25_route, node);
65 else 65 else
66 rt = NULL; 66 rt = NULL;
67out: 67out:
68 return rt; 68 return rt;
@@ -88,7 +88,7 @@ static int x25_seq_route_show(struct seq_file *seq, void *v)
88 rt->dev ? rt->dev->name : "???"); 88 rt->dev ? rt->dev->name : "???");
89out: 89out:
90 return 0; 90 return 0;
91} 91}
92 92
93static __inline__ struct sock *x25_get_socket_idx(loff_t pos) 93static __inline__ struct sock *x25_get_socket_idx(loff_t pos)
94{ 94{
@@ -163,7 +163,76 @@ static int x25_seq_socket_show(struct seq_file *seq, void *v)
163 s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); 163 s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);
164out: 164out:
165 return 0; 165 return 0;
166} 166}
167
168static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos)
169{
170 struct x25_forward *f;
171 struct list_head *entry;
172
173 list_for_each(entry, &x25_forward_list) {
174 f = list_entry(entry, struct x25_forward, node);
175 if (!pos--)
176 goto found;
177 }
178
179 f = NULL;
180found:
181 return f;
182}
183
184static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos)
185{
186 loff_t l = *pos;
187
188 read_lock_bh(&x25_forward_list_lock);
189 return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN;
190}
191
192static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos)
193{
194 struct x25_forward *f;
195
196 ++*pos;
197 if (v == SEQ_START_TOKEN) {
198 f = NULL;
199 if (!list_empty(&x25_forward_list))
200 f = list_entry(x25_forward_list.next,
201 struct x25_forward, node);
202 goto out;
203 }
204 f = v;
205 if (f->node.next != &x25_forward_list)
206 f = list_entry(f->node.next, struct x25_forward, node);
207 else
208 f = NULL;
209out:
210 return f;
211
212}
213
214static void x25_seq_forward_stop(struct seq_file *seq, void *v)
215{
216 read_unlock_bh(&x25_forward_list_lock);
217}
218
219static int x25_seq_forward_show(struct seq_file *seq, void *v)
220{
221 struct x25_forward *f;
222
223 if (v == SEQ_START_TOKEN) {
224 seq_printf(seq, "lci dev1 dev2\n");
225 goto out;
226 }
227
228 f = v;
229
230 seq_printf(seq, "%d %-10s %-10s\n",
231 f->lci, f->dev1->name, f->dev2->name);
232
233out:
234 return 0;
235}
167 236
168static struct seq_operations x25_seq_route_ops = { 237static struct seq_operations x25_seq_route_ops = {
169 .start = x25_seq_route_start, 238 .start = x25_seq_route_start,
@@ -179,6 +248,13 @@ static struct seq_operations x25_seq_socket_ops = {
179 .show = x25_seq_socket_show, 248 .show = x25_seq_socket_show,
180}; 249};
181 250
251static struct seq_operations x25_seq_forward_ops = {
252 .start = x25_seq_forward_start,
253 .next = x25_seq_forward_next,
254 .stop = x25_seq_forward_stop,
255 .show = x25_seq_forward_show,
256};
257
182static int x25_seq_socket_open(struct inode *inode, struct file *file) 258static int x25_seq_socket_open(struct inode *inode, struct file *file)
183{ 259{
184 return seq_open(file, &x25_seq_socket_ops); 260 return seq_open(file, &x25_seq_socket_ops);
@@ -189,7 +265,12 @@ static int x25_seq_route_open(struct inode *inode, struct file *file)
189 return seq_open(file, &x25_seq_route_ops); 265 return seq_open(file, &x25_seq_route_ops);
190} 266}
191 267
192static struct file_operations x25_seq_socket_fops = { 268static int x25_seq_forward_open(struct inode *inode, struct file *file)
269{
270 return seq_open(file, &x25_seq_forward_ops);
271}
272
273static const struct file_operations x25_seq_socket_fops = {
193 .owner = THIS_MODULE, 274 .owner = THIS_MODULE,
194 .open = x25_seq_socket_open, 275 .open = x25_seq_socket_open,
195 .read = seq_read, 276 .read = seq_read,
@@ -197,7 +278,7 @@ static struct file_operations x25_seq_socket_fops = {
197 .release = seq_release, 278 .release = seq_release,
198}; 279};
199 280
200static struct file_operations x25_seq_route_fops = { 281static const struct file_operations x25_seq_route_fops = {
201 .owner = THIS_MODULE, 282 .owner = THIS_MODULE,
202 .open = x25_seq_route_open, 283 .open = x25_seq_route_open,
203 .read = seq_read, 284 .read = seq_read,
@@ -205,6 +286,14 @@ static struct file_operations x25_seq_route_fops = {
205 .release = seq_release, 286 .release = seq_release,
206}; 287};
207 288
289static struct file_operations x25_seq_forward_fops = {
290 .owner = THIS_MODULE,
291 .open = x25_seq_forward_open,
292 .read = seq_read,
293 .llseek = seq_lseek,
294 .release = seq_release,
295};
296
208static struct proc_dir_entry *x25_proc_dir; 297static struct proc_dir_entry *x25_proc_dir;
209 298
210int __init x25_proc_init(void) 299int __init x25_proc_init(void)
@@ -225,9 +314,17 @@ int __init x25_proc_init(void)
225 if (!p) 314 if (!p)
226 goto out_socket; 315 goto out_socket;
227 p->proc_fops = &x25_seq_socket_fops; 316 p->proc_fops = &x25_seq_socket_fops;
317
318 p = create_proc_entry("forward", S_IRUGO, x25_proc_dir);
319 if (!p)
320 goto out_forward;
321 p->proc_fops = &x25_seq_forward_fops;
228 rc = 0; 322 rc = 0;
323
229out: 324out:
230 return rc; 325 return rc;
326out_forward:
327 remove_proc_entry("socket", x25_proc_dir);
231out_socket: 328out_socket:
232 remove_proc_entry("route", x25_proc_dir); 329 remove_proc_entry("route", x25_proc_dir);
233out_route: 330out_route:
@@ -237,6 +334,7 @@ out_route:
237 334
238void __exit x25_proc_exit(void) 335void __exit x25_proc_exit(void)
239{ 336{
337 remove_proc_entry("forward", x25_proc_dir);
240 remove_proc_entry("route", x25_proc_dir); 338 remove_proc_entry("route", x25_proc_dir);
241 remove_proc_entry("socket", x25_proc_dir); 339 remove_proc_entry("socket", x25_proc_dir);
242 remove_proc_entry("x25", proc_net); 340 remove_proc_entry("x25", proc_net);
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
index 2a3fe986b245..060fcfaa2f47 100644
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -119,6 +119,9 @@ void x25_route_device_down(struct net_device *dev)
119 __x25_remove_route(rt); 119 __x25_remove_route(rt);
120 } 120 }
121 write_unlock_bh(&x25_route_list_lock); 121 write_unlock_bh(&x25_route_list_lock);
122
123 /* Remove any related forwarding */
124 x25_clear_forward_by_dev(dev);
122} 125}
123 126
124/* 127/*
diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c
index 71ff3088f6fe..2af190dc5b01 100644
--- a/net/x25/x25_timer.c
+++ b/net/x25/x25_timer.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * This is ALPHA test software. This code may break your machine, 4 * This is ALPHA test software. This code may break your machine,
5 * randomly fail to work with new releases, misbehave and/or generally 5 * randomly fail to work with new releases, misbehave and/or generally
6 * screw up. It might even work. 6 * screw up. It might even work.
7 * 7 *
8 * This code REQUIRES 2.1.15 or higher 8 * This code REQUIRES 2.1.15 or higher
9 * 9 *
@@ -99,8 +99,8 @@ static void x25_heartbeat_expiry(unsigned long param)
99{ 99{
100 struct sock *sk = (struct sock *)param; 100 struct sock *sk = (struct sock *)param;
101 101
102 bh_lock_sock(sk); 102 bh_lock_sock(sk);
103 if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */ 103 if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */
104 goto restart_heartbeat; 104 goto restart_heartbeat;
105 105
106 switch (x25_sk(sk)->state) { 106 switch (x25_sk(sk)->state) {