diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-02-13 01:43:25 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-02-13 01:43:25 -0500 |
commit | d9bc125caf592b7d081021f32ce5b717efdf70c8 (patch) | |
tree | 263b7066ba22ddce21db610c0300f6eaac6f2064 /net/x25 | |
parent | 43d78ef2ba5bec26d0315859e8324bfc0be23766 (diff) | |
parent | ec2f9d1331f658433411c58077871e1eef4ee1b4 (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/Makefile | 2 | ||||
-rw-r--r-- | net/x25/af_x25.c | 96 | ||||
-rw-r--r-- | net/x25/sysctl_net_x25.c | 18 | ||||
-rw-r--r-- | net/x25/x25_dev.c | 19 | ||||
-rw-r--r-- | net/x25/x25_facilities.c | 10 | ||||
-rw-r--r-- | net/x25/x25_forward.c | 163 | ||||
-rw-r--r-- | net/x25/x25_in.c | 8 | ||||
-rw-r--r-- | net/x25/x25_link.c | 6 | ||||
-rw-r--r-- | net/x25/x25_out.c | 10 | ||||
-rw-r--r-- | net/x25/x25_proc.c | 110 | ||||
-rw-r--r-- | net/x25/x25_route.c | 5 | ||||
-rw-r--r-- | net/x25/x25_timer.c | 6 |
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 | ||
7 | x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \ | 7 | x25-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 |
10 | x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o | 10 | x25-$(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; | |||
63 | int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; | 63 | int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; |
64 | int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; | 64 | int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; |
65 | int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; | 65 | int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; |
66 | int sysctl_x25_forward = 0; | ||
66 | 67 | ||
67 | HLIST_HEAD(x25_list); | 68 | HLIST_HEAD(x25_list); |
68 | DEFINE_RWLOCK(x25_list_lock); | 69 | DEFINE_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; |
533 | out: | 534 | out: |
@@ -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 */ |
612 | out: | 613 | out: |
613 | return 0; | 614 | return 0; |
@@ -634,7 +635,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
634 | static int x25_wait_for_connection_establishment(struct sock *sk) | 635 | static 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 | ||
781 | static int x25_accept(struct socket *sock, struct socket *newsock, int flags) | 782 | static 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 | ||
840 | int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | 841 | int 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 | ||
1603 | static int __init x25_init(void) | 1625 | static 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 }; | |||
18 | static struct ctl_table_header *x25_table_header; | 18 | static struct ctl_table_header *x25_table_header; |
19 | 19 | ||
20 | static struct ctl_table x25_table[] = { | 20 | static 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 | */ |
299 | void x25_limit_facilities(struct x25_facilities *facilities, | 299 | void 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 | |||
15 | struct list_head x25_forward_list = LIST_HEAD_INIT(x25_forward_list); | ||
16 | DEFINE_RWLOCK(x25_forward_list_lock); | ||
17 | |||
18 | int 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 | |||
82 | out_put_nb: | ||
83 | x25_neigh_put(neigh_new); | ||
84 | |||
85 | out_put_route: | ||
86 | x25_route_put(rt); | ||
87 | return rc; | ||
88 | } | ||
89 | |||
90 | |||
91 | int 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; | ||
126 | out: | ||
127 | return rc; | ||
128 | } | ||
129 | |||
130 | void 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 | |||
148 | void 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 | ||
137 | void x25_kick(struct sock *sk) | 137 | void 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; |
67 | out: | 67 | out: |
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 : "???"); |
89 | out: | 89 | out: |
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | static __inline__ struct sock *x25_get_socket_idx(loff_t pos) | 93 | static __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); |
164 | out: | 164 | out: |
165 | return 0; | 165 | return 0; |
166 | } | 166 | } |
167 | |||
168 | static __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; | ||
180 | found: | ||
181 | return f; | ||
182 | } | ||
183 | |||
184 | static 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 | |||
192 | static 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; | ||
209 | out: | ||
210 | return f; | ||
211 | |||
212 | } | ||
213 | |||
214 | static void x25_seq_forward_stop(struct seq_file *seq, void *v) | ||
215 | { | ||
216 | read_unlock_bh(&x25_forward_list_lock); | ||
217 | } | ||
218 | |||
219 | static 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 | |||
233 | out: | ||
234 | return 0; | ||
235 | } | ||
167 | 236 | ||
168 | static struct seq_operations x25_seq_route_ops = { | 237 | static 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 | ||
251 | static 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 | |||
182 | static int x25_seq_socket_open(struct inode *inode, struct file *file) | 258 | static 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 | ||
192 | static struct file_operations x25_seq_socket_fops = { | 268 | static int x25_seq_forward_open(struct inode *inode, struct file *file) |
269 | { | ||
270 | return seq_open(file, &x25_seq_forward_ops); | ||
271 | } | ||
272 | |||
273 | static 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 | ||
200 | static struct file_operations x25_seq_route_fops = { | 281 | static 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 | ||
289 | static 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 | |||
208 | static struct proc_dir_entry *x25_proc_dir; | 297 | static struct proc_dir_entry *x25_proc_dir; |
209 | 298 | ||
210 | int __init x25_proc_init(void) | 299 | int __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 | |||
229 | out: | 324 | out: |
230 | return rc; | 325 | return rc; |
326 | out_forward: | ||
327 | remove_proc_entry("socket", x25_proc_dir); | ||
231 | out_socket: | 328 | out_socket: |
232 | remove_proc_entry("route", x25_proc_dir); | 329 | remove_proc_entry("route", x25_proc_dir); |
233 | out_route: | 330 | out_route: |
@@ -237,6 +334,7 @@ out_route: | |||
237 | 334 | ||
238 | void __exit x25_proc_exit(void) | 335 | void __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) { |