diff options
Diffstat (limited to 'net/x25/af_x25.c')
-rw-r--r-- | net/x25/af_x25.c | 173 |
1 files changed, 171 insertions, 2 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 72b6ff3299ba..282ce4e40d7b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -54,7 +54,10 @@ | |||
54 | #include <linux/termios.h> /* For TIOCINQ/OUTQ */ | 54 | #include <linux/termios.h> /* For TIOCINQ/OUTQ */ |
55 | #include <linux/notifier.h> | 55 | #include <linux/notifier.h> |
56 | #include <linux/init.h> | 56 | #include <linux/init.h> |
57 | #include <linux/compat.h> | ||
58 | |||
57 | #include <net/x25.h> | 59 | #include <net/x25.h> |
60 | #include <net/compat.h> | ||
58 | 61 | ||
59 | int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20; | 62 | int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20; |
60 | int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; | 63 | int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; |
@@ -69,6 +72,14 @@ static const struct proto_ops x25_proto_ops; | |||
69 | 72 | ||
70 | static struct x25_address null_x25_address = {" "}; | 73 | static struct x25_address null_x25_address = {" "}; |
71 | 74 | ||
75 | #ifdef CONFIG_COMPAT | ||
76 | struct compat_x25_subscrip_struct { | ||
77 | char device[200-sizeof(compat_ulong_t)]; | ||
78 | compat_ulong_t global_facil_mask; | ||
79 | compat_uint_t extended; | ||
80 | }; | ||
81 | #endif | ||
82 | |||
72 | int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr, | 83 | int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr, |
73 | struct x25_address *calling_addr) | 84 | struct x25_address *calling_addr) |
74 | { | 85 | { |
@@ -514,6 +525,13 @@ static int x25_create(struct socket *sock, int protocol) | |||
514 | x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; | 525 | x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; |
515 | x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; | 526 | x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; |
516 | x25->facilities.reverse = X25_DEFAULT_REVERSE; | 527 | x25->facilities.reverse = X25_DEFAULT_REVERSE; |
528 | x25->dte_facilities.calling_len = 0; | ||
529 | x25->dte_facilities.called_len = 0; | ||
530 | memset(x25->dte_facilities.called_ae, '\0', | ||
531 | sizeof(x25->dte_facilities.called_ae)); | ||
532 | memset(x25->dte_facilities.calling_ae, '\0', | ||
533 | sizeof(x25->dte_facilities.calling_ae)); | ||
534 | |||
517 | rc = 0; | 535 | rc = 0; |
518 | out: | 536 | out: |
519 | return rc; | 537 | return rc; |
@@ -550,6 +568,7 @@ static struct sock *x25_make_new(struct sock *osk) | |||
550 | x25->t2 = ox25->t2; | 568 | x25->t2 = ox25->t2; |
551 | x25->facilities = ox25->facilities; | 569 | x25->facilities = ox25->facilities; |
552 | x25->qbitincl = ox25->qbitincl; | 570 | x25->qbitincl = ox25->qbitincl; |
571 | x25->dte_facilities = ox25->dte_facilities; | ||
553 | x25->cudmatchlength = ox25->cudmatchlength; | 572 | x25->cudmatchlength = ox25->cudmatchlength; |
554 | x25->accptapprv = ox25->accptapprv; | 573 | x25->accptapprv = ox25->accptapprv; |
555 | 574 | ||
@@ -733,7 +752,7 @@ out: | |||
733 | return rc; | 752 | return rc; |
734 | } | 753 | } |
735 | 754 | ||
736 | static int x25_wait_for_data(struct sock *sk, int timeout) | 755 | static int x25_wait_for_data(struct sock *sk, long timeout) |
737 | { | 756 | { |
738 | DECLARE_WAITQUEUE(wait, current); | 757 | DECLARE_WAITQUEUE(wait, current); |
739 | int rc = 0; | 758 | int rc = 0; |
@@ -829,6 +848,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
829 | struct x25_sock *makex25; | 848 | struct x25_sock *makex25; |
830 | struct x25_address source_addr, dest_addr; | 849 | struct x25_address source_addr, dest_addr; |
831 | struct x25_facilities facilities; | 850 | struct x25_facilities facilities; |
851 | struct x25_dte_facilities dte_facilities; | ||
832 | int len, rc; | 852 | int len, rc; |
833 | 853 | ||
834 | /* | 854 | /* |
@@ -865,7 +885,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
865 | /* | 885 | /* |
866 | * Try to reach a compromise on the requested facilities. | 886 | * Try to reach a compromise on the requested facilities. |
867 | */ | 887 | */ |
868 | if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) | 888 | len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities); |
889 | if (len == -1) | ||
869 | goto out_sock_put; | 890 | goto out_sock_put; |
870 | 891 | ||
871 | /* | 892 | /* |
@@ -896,9 +917,12 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
896 | makex25->source_addr = source_addr; | 917 | makex25->source_addr = source_addr; |
897 | makex25->neighbour = nb; | 918 | makex25->neighbour = nb; |
898 | makex25->facilities = facilities; | 919 | makex25->facilities = facilities; |
920 | makex25->dte_facilities= dte_facilities; | ||
899 | makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; | 921 | makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; |
900 | /* ensure no reverse facil on accept */ | 922 | /* ensure no reverse facil on accept */ |
901 | makex25->vc_facil_mask &= ~X25_MASK_REVERSE; | 923 | makex25->vc_facil_mask &= ~X25_MASK_REVERSE; |
924 | /* ensure no calling address extension on accept */ | ||
925 | makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE; | ||
902 | makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; | 926 | makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; |
903 | 927 | ||
904 | /* Normally all calls are accepted immediatly */ | 928 | /* Normally all calls are accepted immediatly */ |
@@ -1305,6 +1329,36 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1305 | break; | 1329 | break; |
1306 | } | 1330 | } |
1307 | 1331 | ||
1332 | case SIOCX25GDTEFACILITIES: { | ||
1333 | rc = copy_to_user(argp, &x25->dte_facilities, | ||
1334 | sizeof(x25->dte_facilities)); | ||
1335 | if (rc) | ||
1336 | rc = -EFAULT; | ||
1337 | break; | ||
1338 | } | ||
1339 | |||
1340 | case SIOCX25SDTEFACILITIES: { | ||
1341 | struct x25_dte_facilities dtefacs; | ||
1342 | rc = -EFAULT; | ||
1343 | if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) | ||
1344 | break; | ||
1345 | rc = -EINVAL; | ||
1346 | if (sk->sk_state != TCP_LISTEN && | ||
1347 | sk->sk_state != TCP_CLOSE) | ||
1348 | break; | ||
1349 | if (dtefacs.calling_len > X25_MAX_AE_LEN) | ||
1350 | break; | ||
1351 | if (dtefacs.calling_ae == NULL) | ||
1352 | break; | ||
1353 | if (dtefacs.called_len > X25_MAX_AE_LEN) | ||
1354 | break; | ||
1355 | if (dtefacs.called_ae == NULL) | ||
1356 | break; | ||
1357 | x25->dte_facilities = dtefacs; | ||
1358 | rc = 0; | ||
1359 | break; | ||
1360 | } | ||
1361 | |||
1308 | case SIOCX25GCALLUSERDATA: { | 1362 | case SIOCX25GCALLUSERDATA: { |
1309 | struct x25_calluserdata cud = x25->calluserdata; | 1363 | struct x25_calluserdata cud = x25->calluserdata; |
1310 | rc = copy_to_user(argp, &cud, | 1364 | rc = copy_to_user(argp, &cud, |
@@ -1387,6 +1441,118 @@ static struct net_proto_family x25_family_ops = { | |||
1387 | .owner = THIS_MODULE, | 1441 | .owner = THIS_MODULE, |
1388 | }; | 1442 | }; |
1389 | 1443 | ||
1444 | #ifdef CONFIG_COMPAT | ||
1445 | static int compat_x25_subscr_ioctl(unsigned int cmd, | ||
1446 | struct compat_x25_subscrip_struct __user *x25_subscr32) | ||
1447 | { | ||
1448 | struct compat_x25_subscrip_struct x25_subscr; | ||
1449 | struct x25_neigh *nb; | ||
1450 | struct net_device *dev; | ||
1451 | int rc = -EINVAL; | ||
1452 | |||
1453 | rc = -EFAULT; | ||
1454 | if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32))) | ||
1455 | goto out; | ||
1456 | |||
1457 | rc = -EINVAL; | ||
1458 | dev = x25_dev_get(x25_subscr.device); | ||
1459 | if (dev == NULL) | ||
1460 | goto out; | ||
1461 | |||
1462 | nb = x25_get_neigh(dev); | ||
1463 | if (nb == NULL) | ||
1464 | goto out_dev_put; | ||
1465 | |||
1466 | dev_put(dev); | ||
1467 | |||
1468 | if (cmd == SIOCX25GSUBSCRIP) { | ||
1469 | x25_subscr.extended = nb->extended; | ||
1470 | x25_subscr.global_facil_mask = nb->global_facil_mask; | ||
1471 | rc = copy_to_user(x25_subscr32, &x25_subscr, | ||
1472 | sizeof(*x25_subscr32)) ? -EFAULT : 0; | ||
1473 | } else { | ||
1474 | rc = -EINVAL; | ||
1475 | if (x25_subscr.extended == 0 || x25_subscr.extended == 1) { | ||
1476 | rc = 0; | ||
1477 | nb->extended = x25_subscr.extended; | ||
1478 | nb->global_facil_mask = x25_subscr.global_facil_mask; | ||
1479 | } | ||
1480 | } | ||
1481 | x25_neigh_put(nb); | ||
1482 | out: | ||
1483 | return rc; | ||
1484 | out_dev_put: | ||
1485 | dev_put(dev); | ||
1486 | goto out; | ||
1487 | } | ||
1488 | |||
1489 | static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, | ||
1490 | unsigned long arg) | ||
1491 | { | ||
1492 | void __user *argp = compat_ptr(arg); | ||
1493 | struct sock *sk = sock->sk; | ||
1494 | |||
1495 | int rc = -ENOIOCTLCMD; | ||
1496 | |||
1497 | switch(cmd) { | ||
1498 | case TIOCOUTQ: | ||
1499 | case TIOCINQ: | ||
1500 | rc = x25_ioctl(sock, cmd, (unsigned long)argp); | ||
1501 | break; | ||
1502 | case SIOCGSTAMP: | ||
1503 | rc = -EINVAL; | ||
1504 | if (sk) | ||
1505 | rc = compat_sock_get_timestamp(sk, | ||
1506 | (struct timeval __user*)argp); | ||
1507 | break; | ||
1508 | case SIOCGIFADDR: | ||
1509 | case SIOCSIFADDR: | ||
1510 | case SIOCGIFDSTADDR: | ||
1511 | case SIOCSIFDSTADDR: | ||
1512 | case SIOCGIFBRDADDR: | ||
1513 | case SIOCSIFBRDADDR: | ||
1514 | case SIOCGIFNETMASK: | ||
1515 | case SIOCSIFNETMASK: | ||
1516 | case SIOCGIFMETRIC: | ||
1517 | case SIOCSIFMETRIC: | ||
1518 | rc = -EINVAL; | ||
1519 | break; | ||
1520 | case SIOCADDRT: | ||
1521 | case SIOCDELRT: | ||
1522 | rc = -EPERM; | ||
1523 | if (!capable(CAP_NET_ADMIN)) | ||
1524 | break; | ||
1525 | rc = x25_route_ioctl(cmd, argp); | ||
1526 | break; | ||
1527 | case SIOCX25GSUBSCRIP: | ||
1528 | rc = compat_x25_subscr_ioctl(cmd, argp); | ||
1529 | break; | ||
1530 | case SIOCX25SSUBSCRIP: | ||
1531 | rc = -EPERM; | ||
1532 | if (!capable(CAP_NET_ADMIN)) | ||
1533 | break; | ||
1534 | rc = compat_x25_subscr_ioctl(cmd, argp); | ||
1535 | break; | ||
1536 | case SIOCX25GFACILITIES: | ||
1537 | case SIOCX25SFACILITIES: | ||
1538 | case SIOCX25GDTEFACILITIES: | ||
1539 | case SIOCX25SDTEFACILITIES: | ||
1540 | case SIOCX25GCALLUSERDATA: | ||
1541 | case SIOCX25SCALLUSERDATA: | ||
1542 | case SIOCX25GCAUSEDIAG: | ||
1543 | case SIOCX25SCUDMATCHLEN: | ||
1544 | case SIOCX25CALLACCPTAPPRV: | ||
1545 | case SIOCX25SENDCALLACCPT: | ||
1546 | rc = x25_ioctl(sock, cmd, (unsigned long)argp); | ||
1547 | break; | ||
1548 | default: | ||
1549 | rc = -ENOIOCTLCMD; | ||
1550 | break; | ||
1551 | } | ||
1552 | return rc; | ||
1553 | } | ||
1554 | #endif | ||
1555 | |||
1390 | static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { | 1556 | static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { |
1391 | .family = AF_X25, | 1557 | .family = AF_X25, |
1392 | .owner = THIS_MODULE, | 1558 | .owner = THIS_MODULE, |
@@ -1398,6 +1564,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { | |||
1398 | .getname = x25_getname, | 1564 | .getname = x25_getname, |
1399 | .poll = datagram_poll, | 1565 | .poll = datagram_poll, |
1400 | .ioctl = x25_ioctl, | 1566 | .ioctl = x25_ioctl, |
1567 | #ifdef CONFIG_COMPAT | ||
1568 | .compat_ioctl = compat_x25_ioctl, | ||
1569 | #endif | ||
1401 | .listen = x25_listen, | 1570 | .listen = x25_listen, |
1402 | .shutdown = sock_no_shutdown, | 1571 | .shutdown = sock_no_shutdown, |
1403 | .setsockopt = x25_setsockopt, | 1572 | .setsockopt = x25_setsockopt, |