diff options
Diffstat (limited to 'net/x25')
-rw-r--r-- | net/x25/af_x25.c | 511 | ||||
-rw-r--r-- | net/x25/x25_dev.c | 50 | ||||
-rw-r--r-- | net/x25/x25_facilities.c | 10 | ||||
-rw-r--r-- | net/x25/x25_in.c | 151 | ||||
-rw-r--r-- | net/x25/x25_link.c | 84 | ||||
-rw-r--r-- | net/x25/x25_subr.c | 92 |
6 files changed, 486 insertions, 412 deletions
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 4680b1e4c79..5f03e4ea65b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -91,7 +91,7 @@ int x25_parse_address_block(struct sk_buff *skb, | |||
91 | int needed; | 91 | int needed; |
92 | int rc; | 92 | int rc; |
93 | 93 | ||
94 | if (skb->len < 1) { | 94 | if (!pskb_may_pull(skb, 1)) { |
95 | /* packet has no address block */ | 95 | /* packet has no address block */ |
96 | rc = 0; | 96 | rc = 0; |
97 | goto empty; | 97 | goto empty; |
@@ -100,7 +100,7 @@ int x25_parse_address_block(struct sk_buff *skb, | |||
100 | len = *skb->data; | 100 | len = *skb->data; |
101 | needed = 1 + (len >> 4) + (len & 0x0f); | 101 | needed = 1 + (len >> 4) + (len & 0x0f); |
102 | 102 | ||
103 | if (skb->len < needed) { | 103 | if (!pskb_may_pull(skb, needed)) { |
104 | /* packet is too short to hold the addresses it claims | 104 | /* packet is too short to hold the addresses it claims |
105 | to hold */ | 105 | to hold */ |
106 | rc = -1; | 106 | rc = -1; |
@@ -237,21 +237,21 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, | |||
237 | #endif | 237 | #endif |
238 | ) { | 238 | ) { |
239 | switch (event) { | 239 | switch (event) { |
240 | case NETDEV_UP: | 240 | case NETDEV_UP: |
241 | x25_link_device_up(dev); | 241 | x25_link_device_up(dev); |
242 | break; | 242 | break; |
243 | case NETDEV_GOING_DOWN: | 243 | case NETDEV_GOING_DOWN: |
244 | nb = x25_get_neigh(dev); | 244 | nb = x25_get_neigh(dev); |
245 | if (nb) { | 245 | if (nb) { |
246 | x25_terminate_link(nb); | 246 | x25_terminate_link(nb); |
247 | x25_neigh_put(nb); | 247 | x25_neigh_put(nb); |
248 | } | 248 | } |
249 | break; | 249 | break; |
250 | case NETDEV_DOWN: | 250 | case NETDEV_DOWN: |
251 | x25_kill_by_device(dev); | 251 | x25_kill_by_device(dev); |
252 | x25_route_device_down(dev); | 252 | x25_route_device_down(dev); |
253 | x25_link_device_down(dev); | 253 | x25_link_device_down(dev); |
254 | break; | 254 | break; |
255 | } | 255 | } |
256 | } | 256 | } |
257 | 257 | ||
@@ -295,7 +295,8 @@ static struct sock *x25_find_listener(struct x25_address *addr, | |||
295 | * Found a listening socket, now check the incoming | 295 | * Found a listening socket, now check the incoming |
296 | * call user data vs this sockets call user data | 296 | * call user data vs this sockets call user data |
297 | */ | 297 | */ |
298 | if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) { | 298 | if (x25_sk(s)->cudmatchlength > 0 && |
299 | skb->len >= x25_sk(s)->cudmatchlength) { | ||
299 | if((memcmp(x25_sk(s)->calluserdata.cuddata, | 300 | if((memcmp(x25_sk(s)->calluserdata.cuddata, |
300 | skb->data, | 301 | skb->data, |
301 | x25_sk(s)->cudmatchlength)) == 0) { | 302 | x25_sk(s)->cudmatchlength)) == 0) { |
@@ -951,14 +952,27 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
951 | * | 952 | * |
952 | * Facilities length is mandatory in call request packets | 953 | * Facilities length is mandatory in call request packets |
953 | */ | 954 | */ |
954 | if (skb->len < 1) | 955 | if (!pskb_may_pull(skb, 1)) |
955 | goto out_clear_request; | 956 | goto out_clear_request; |
956 | len = skb->data[0] + 1; | 957 | len = skb->data[0] + 1; |
957 | if (skb->len < len) | 958 | if (!pskb_may_pull(skb, len)) |
958 | goto out_clear_request; | 959 | goto out_clear_request; |
959 | skb_pull(skb,len); | 960 | skb_pull(skb,len); |
960 | 961 | ||
961 | /* | 962 | /* |
963 | * Ensure that the amount of call user data is valid. | ||
964 | */ | ||
965 | if (skb->len > X25_MAX_CUD_LEN) | ||
966 | goto out_clear_request; | ||
967 | |||
968 | /* | ||
969 | * Get all the call user data so it can be used in | ||
970 | * x25_find_listener and skb_copy_from_linear_data up ahead. | ||
971 | */ | ||
972 | if (!pskb_may_pull(skb, skb->len)) | ||
973 | goto out_clear_request; | ||
974 | |||
975 | /* | ||
962 | * Find a listener for the particular address/cud pair. | 976 | * Find a listener for the particular address/cud pair. |
963 | */ | 977 | */ |
964 | sk = x25_find_listener(&source_addr,skb); | 978 | sk = x25_find_listener(&source_addr,skb); |
@@ -1166,6 +1180,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1166 | * byte of the user data is the logical value of the Q Bit. | 1180 | * byte of the user data is the logical value of the Q Bit. |
1167 | */ | 1181 | */ |
1168 | if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { | 1182 | if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { |
1183 | if (!pskb_may_pull(skb, 1)) | ||
1184 | goto out_kfree_skb; | ||
1185 | |||
1169 | qbit = skb->data[0]; | 1186 | qbit = skb->data[0]; |
1170 | skb_pull(skb, 1); | 1187 | skb_pull(skb, 1); |
1171 | } | 1188 | } |
@@ -1244,7 +1261,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1244 | struct x25_sock *x25 = x25_sk(sk); | 1261 | struct x25_sock *x25 = x25_sk(sk); |
1245 | struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; | 1262 | struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; |
1246 | size_t copied; | 1263 | size_t copied; |
1247 | int qbit; | 1264 | int qbit, header_len = x25->neighbour->extended ? |
1265 | X25_EXT_MIN_LEN : X25_STD_MIN_LEN; | ||
1266 | |||
1248 | struct sk_buff *skb; | 1267 | struct sk_buff *skb; |
1249 | unsigned char *asmptr; | 1268 | unsigned char *asmptr; |
1250 | int rc = -ENOTCONN; | 1269 | int rc = -ENOTCONN; |
@@ -1265,6 +1284,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1265 | 1284 | ||
1266 | skb = skb_dequeue(&x25->interrupt_in_queue); | 1285 | skb = skb_dequeue(&x25->interrupt_in_queue); |
1267 | 1286 | ||
1287 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) | ||
1288 | goto out_free_dgram; | ||
1289 | |||
1268 | skb_pull(skb, X25_STD_MIN_LEN); | 1290 | skb_pull(skb, X25_STD_MIN_LEN); |
1269 | 1291 | ||
1270 | /* | 1292 | /* |
@@ -1285,10 +1307,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1285 | if (!skb) | 1307 | if (!skb) |
1286 | goto out; | 1308 | goto out; |
1287 | 1309 | ||
1310 | if (!pskb_may_pull(skb, header_len)) | ||
1311 | goto out_free_dgram; | ||
1312 | |||
1288 | qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; | 1313 | qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; |
1289 | 1314 | ||
1290 | skb_pull(skb, x25->neighbour->extended ? | 1315 | skb_pull(skb, header_len); |
1291 | X25_EXT_MIN_LEN : X25_STD_MIN_LEN); | ||
1292 | 1316 | ||
1293 | if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { | 1317 | if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) { |
1294 | asmptr = skb_push(skb, 1); | 1318 | asmptr = skb_push(skb, 1); |
@@ -1336,256 +1360,253 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1336 | int rc; | 1360 | int rc; |
1337 | 1361 | ||
1338 | switch (cmd) { | 1362 | switch (cmd) { |
1339 | case TIOCOUTQ: { | 1363 | case TIOCOUTQ: { |
1340 | int amount; | 1364 | int amount; |
1341 | 1365 | ||
1342 | amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); | 1366 | amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); |
1343 | if (amount < 0) | 1367 | if (amount < 0) |
1344 | amount = 0; | 1368 | amount = 0; |
1345 | rc = put_user(amount, (unsigned int __user *)argp); | 1369 | rc = put_user(amount, (unsigned int __user *)argp); |
1346 | break; | 1370 | break; |
1347 | } | 1371 | } |
1348 | 1372 | ||
1349 | case TIOCINQ: { | 1373 | case TIOCINQ: { |
1350 | struct sk_buff *skb; | 1374 | struct sk_buff *skb; |
1351 | int amount = 0; | 1375 | int amount = 0; |
1352 | /* | 1376 | /* |
1353 | * These two are safe on a single CPU system as | 1377 | * These two are safe on a single CPU system as |
1354 | * only user tasks fiddle here | 1378 | * only user tasks fiddle here |
1355 | */ | 1379 | */ |
1356 | lock_sock(sk); | 1380 | lock_sock(sk); |
1357 | if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) | 1381 | if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) |
1358 | amount = skb->len; | 1382 | amount = skb->len; |
1359 | release_sock(sk); | 1383 | release_sock(sk); |
1360 | rc = put_user(amount, (unsigned int __user *)argp); | 1384 | rc = put_user(amount, (unsigned int __user *)argp); |
1361 | break; | 1385 | break; |
1362 | } | 1386 | } |
1363 | 1387 | ||
1364 | case SIOCGSTAMP: | 1388 | case SIOCGSTAMP: |
1365 | rc = -EINVAL; | 1389 | rc = -EINVAL; |
1366 | if (sk) | 1390 | if (sk) |
1367 | rc = sock_get_timestamp(sk, | 1391 | rc = sock_get_timestamp(sk, |
1368 | (struct timeval __user *)argp); | 1392 | (struct timeval __user *)argp); |
1393 | break; | ||
1394 | case SIOCGSTAMPNS: | ||
1395 | rc = -EINVAL; | ||
1396 | if (sk) | ||
1397 | rc = sock_get_timestampns(sk, | ||
1398 | (struct timespec __user *)argp); | ||
1399 | break; | ||
1400 | case SIOCGIFADDR: | ||
1401 | case SIOCSIFADDR: | ||
1402 | case SIOCGIFDSTADDR: | ||
1403 | case SIOCSIFDSTADDR: | ||
1404 | case SIOCGIFBRDADDR: | ||
1405 | case SIOCSIFBRDADDR: | ||
1406 | case SIOCGIFNETMASK: | ||
1407 | case SIOCSIFNETMASK: | ||
1408 | case SIOCGIFMETRIC: | ||
1409 | case SIOCSIFMETRIC: | ||
1410 | rc = -EINVAL; | ||
1411 | break; | ||
1412 | case SIOCADDRT: | ||
1413 | case SIOCDELRT: | ||
1414 | rc = -EPERM; | ||
1415 | if (!capable(CAP_NET_ADMIN)) | ||
1369 | break; | 1416 | break; |
1370 | case SIOCGSTAMPNS: | 1417 | rc = x25_route_ioctl(cmd, argp); |
1371 | rc = -EINVAL; | 1418 | break; |
1372 | if (sk) | 1419 | case SIOCX25GSUBSCRIP: |
1373 | rc = sock_get_timestampns(sk, | 1420 | rc = x25_subscr_ioctl(cmd, argp); |
1374 | (struct timespec __user *)argp); | 1421 | break; |
1375 | break; | 1422 | case SIOCX25SSUBSCRIP: |
1376 | case SIOCGIFADDR: | 1423 | rc = -EPERM; |
1377 | case SIOCSIFADDR: | 1424 | if (!capable(CAP_NET_ADMIN)) |
1378 | case SIOCGIFDSTADDR: | ||
1379 | case SIOCSIFDSTADDR: | ||
1380 | case SIOCGIFBRDADDR: | ||
1381 | case SIOCSIFBRDADDR: | ||
1382 | case SIOCGIFNETMASK: | ||
1383 | case SIOCSIFNETMASK: | ||
1384 | case SIOCGIFMETRIC: | ||
1385 | case SIOCSIFMETRIC: | ||
1386 | rc = -EINVAL; | ||
1387 | break; | ||
1388 | case SIOCADDRT: | ||
1389 | case SIOCDELRT: | ||
1390 | rc = -EPERM; | ||
1391 | if (!capable(CAP_NET_ADMIN)) | ||
1392 | break; | ||
1393 | rc = x25_route_ioctl(cmd, argp); | ||
1394 | break; | ||
1395 | case SIOCX25GSUBSCRIP: | ||
1396 | rc = x25_subscr_ioctl(cmd, argp); | ||
1397 | break; | ||
1398 | case SIOCX25SSUBSCRIP: | ||
1399 | rc = -EPERM; | ||
1400 | if (!capable(CAP_NET_ADMIN)) | ||
1401 | break; | ||
1402 | rc = x25_subscr_ioctl(cmd, argp); | ||
1403 | break; | ||
1404 | case SIOCX25GFACILITIES: { | ||
1405 | lock_sock(sk); | ||
1406 | rc = copy_to_user(argp, &x25->facilities, | ||
1407 | sizeof(x25->facilities)) | ||
1408 | ? -EFAULT : 0; | ||
1409 | release_sock(sk); | ||
1410 | break; | 1425 | break; |
1411 | } | 1426 | rc = x25_subscr_ioctl(cmd, argp); |
1427 | break; | ||
1428 | case SIOCX25GFACILITIES: { | ||
1429 | lock_sock(sk); | ||
1430 | rc = copy_to_user(argp, &x25->facilities, | ||
1431 | sizeof(x25->facilities)) | ||
1432 | ? -EFAULT : 0; | ||
1433 | release_sock(sk); | ||
1434 | break; | ||
1435 | } | ||
1412 | 1436 | ||
1413 | case SIOCX25SFACILITIES: { | 1437 | case SIOCX25SFACILITIES: { |
1414 | struct x25_facilities facilities; | 1438 | struct x25_facilities facilities; |
1415 | rc = -EFAULT; | 1439 | rc = -EFAULT; |
1416 | if (copy_from_user(&facilities, argp, | 1440 | if (copy_from_user(&facilities, argp, sizeof(facilities))) |
1417 | sizeof(facilities))) | 1441 | break; |
1418 | break; | 1442 | rc = -EINVAL; |
1419 | rc = -EINVAL; | 1443 | lock_sock(sk); |
1420 | lock_sock(sk); | 1444 | if (sk->sk_state != TCP_LISTEN && |
1421 | if (sk->sk_state != TCP_LISTEN && | 1445 | sk->sk_state != TCP_CLOSE) |
1422 | sk->sk_state != TCP_CLOSE) | 1446 | goto out_fac_release; |
1423 | goto out_fac_release; | 1447 | if (facilities.pacsize_in < X25_PS16 || |
1424 | if (facilities.pacsize_in < X25_PS16 || | 1448 | facilities.pacsize_in > X25_PS4096) |
1425 | facilities.pacsize_in > X25_PS4096) | 1449 | goto out_fac_release; |
1426 | goto out_fac_release; | 1450 | if (facilities.pacsize_out < X25_PS16 || |
1427 | if (facilities.pacsize_out < X25_PS16 || | 1451 | facilities.pacsize_out > X25_PS4096) |
1428 | facilities.pacsize_out > X25_PS4096) | 1452 | goto out_fac_release; |
1429 | goto out_fac_release; | 1453 | if (facilities.winsize_in < 1 || |
1430 | if (facilities.winsize_in < 1 || | 1454 | facilities.winsize_in > 127) |
1431 | facilities.winsize_in > 127) | 1455 | goto out_fac_release; |
1456 | if (facilities.throughput) { | ||
1457 | int out = facilities.throughput & 0xf0; | ||
1458 | int in = facilities.throughput & 0x0f; | ||
1459 | if (!out) | ||
1460 | facilities.throughput |= | ||
1461 | X25_DEFAULT_THROUGHPUT << 4; | ||
1462 | else if (out < 0x30 || out > 0xD0) | ||
1432 | goto out_fac_release; | 1463 | goto out_fac_release; |
1433 | if (facilities.throughput) { | 1464 | if (!in) |
1434 | int out = facilities.throughput & 0xf0; | 1465 | facilities.throughput |= |
1435 | int in = facilities.throughput & 0x0f; | 1466 | X25_DEFAULT_THROUGHPUT; |
1436 | if (!out) | 1467 | else if (in < 0x03 || in > 0x0D) |
1437 | facilities.throughput |= | ||
1438 | X25_DEFAULT_THROUGHPUT << 4; | ||
1439 | else if (out < 0x30 || out > 0xD0) | ||
1440 | goto out_fac_release; | ||
1441 | if (!in) | ||
1442 | facilities.throughput |= | ||
1443 | X25_DEFAULT_THROUGHPUT; | ||
1444 | else if (in < 0x03 || in > 0x0D) | ||
1445 | goto out_fac_release; | ||
1446 | } | ||
1447 | if (facilities.reverse && | ||
1448 | (facilities.reverse & 0x81) != 0x81) | ||
1449 | goto out_fac_release; | 1468 | goto out_fac_release; |
1450 | x25->facilities = facilities; | ||
1451 | rc = 0; | ||
1452 | out_fac_release: | ||
1453 | release_sock(sk); | ||
1454 | break; | ||
1455 | } | ||
1456 | |||
1457 | case SIOCX25GDTEFACILITIES: { | ||
1458 | lock_sock(sk); | ||
1459 | rc = copy_to_user(argp, &x25->dte_facilities, | ||
1460 | sizeof(x25->dte_facilities)); | ||
1461 | release_sock(sk); | ||
1462 | if (rc) | ||
1463 | rc = -EFAULT; | ||
1464 | break; | ||
1465 | } | 1469 | } |
1470 | if (facilities.reverse && | ||
1471 | (facilities.reverse & 0x81) != 0x81) | ||
1472 | goto out_fac_release; | ||
1473 | x25->facilities = facilities; | ||
1474 | rc = 0; | ||
1475 | out_fac_release: | ||
1476 | release_sock(sk); | ||
1477 | break; | ||
1478 | } | ||
1466 | 1479 | ||
1467 | case SIOCX25SDTEFACILITIES: { | 1480 | case SIOCX25GDTEFACILITIES: { |
1468 | struct x25_dte_facilities dtefacs; | 1481 | lock_sock(sk); |
1482 | rc = copy_to_user(argp, &x25->dte_facilities, | ||
1483 | sizeof(x25->dte_facilities)); | ||
1484 | release_sock(sk); | ||
1485 | if (rc) | ||
1469 | rc = -EFAULT; | 1486 | rc = -EFAULT; |
1470 | if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) | 1487 | break; |
1471 | break; | 1488 | } |
1472 | rc = -EINVAL; | ||
1473 | lock_sock(sk); | ||
1474 | if (sk->sk_state != TCP_LISTEN && | ||
1475 | sk->sk_state != TCP_CLOSE) | ||
1476 | goto out_dtefac_release; | ||
1477 | if (dtefacs.calling_len > X25_MAX_AE_LEN) | ||
1478 | goto out_dtefac_release; | ||
1479 | if (dtefacs.calling_ae == NULL) | ||
1480 | goto out_dtefac_release; | ||
1481 | if (dtefacs.called_len > X25_MAX_AE_LEN) | ||
1482 | goto out_dtefac_release; | ||
1483 | if (dtefacs.called_ae == NULL) | ||
1484 | goto out_dtefac_release; | ||
1485 | x25->dte_facilities = dtefacs; | ||
1486 | rc = 0; | ||
1487 | out_dtefac_release: | ||
1488 | release_sock(sk); | ||
1489 | break; | ||
1490 | } | ||
1491 | 1489 | ||
1492 | case SIOCX25GCALLUSERDATA: { | 1490 | case SIOCX25SDTEFACILITIES: { |
1493 | lock_sock(sk); | 1491 | struct x25_dte_facilities dtefacs; |
1494 | rc = copy_to_user(argp, &x25->calluserdata, | 1492 | rc = -EFAULT; |
1495 | sizeof(x25->calluserdata)) | 1493 | if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) |
1496 | ? -EFAULT : 0; | ||
1497 | release_sock(sk); | ||
1498 | break; | 1494 | break; |
1499 | } | 1495 | rc = -EINVAL; |
1496 | lock_sock(sk); | ||
1497 | if (sk->sk_state != TCP_LISTEN && | ||
1498 | sk->sk_state != TCP_CLOSE) | ||
1499 | goto out_dtefac_release; | ||
1500 | if (dtefacs.calling_len > X25_MAX_AE_LEN) | ||
1501 | goto out_dtefac_release; | ||
1502 | if (dtefacs.calling_ae == NULL) | ||
1503 | goto out_dtefac_release; | ||
1504 | if (dtefacs.called_len > X25_MAX_AE_LEN) | ||
1505 | goto out_dtefac_release; | ||
1506 | if (dtefacs.called_ae == NULL) | ||
1507 | goto out_dtefac_release; | ||
1508 | x25->dte_facilities = dtefacs; | ||
1509 | rc = 0; | ||
1510 | out_dtefac_release: | ||
1511 | release_sock(sk); | ||
1512 | break; | ||
1513 | } | ||
1500 | 1514 | ||
1501 | case SIOCX25SCALLUSERDATA: { | 1515 | case SIOCX25GCALLUSERDATA: { |
1502 | struct x25_calluserdata calluserdata; | 1516 | lock_sock(sk); |
1517 | rc = copy_to_user(argp, &x25->calluserdata, | ||
1518 | sizeof(x25->calluserdata)) | ||
1519 | ? -EFAULT : 0; | ||
1520 | release_sock(sk); | ||
1521 | break; | ||
1522 | } | ||
1503 | 1523 | ||
1504 | rc = -EFAULT; | 1524 | case SIOCX25SCALLUSERDATA: { |
1505 | if (copy_from_user(&calluserdata, argp, | 1525 | struct x25_calluserdata calluserdata; |
1506 | sizeof(calluserdata))) | ||
1507 | break; | ||
1508 | rc = -EINVAL; | ||
1509 | if (calluserdata.cudlength > X25_MAX_CUD_LEN) | ||
1510 | break; | ||
1511 | lock_sock(sk); | ||
1512 | x25->calluserdata = calluserdata; | ||
1513 | release_sock(sk); | ||
1514 | rc = 0; | ||
1515 | break; | ||
1516 | } | ||
1517 | 1526 | ||
1518 | case SIOCX25GCAUSEDIAG: { | 1527 | rc = -EFAULT; |
1519 | lock_sock(sk); | 1528 | if (copy_from_user(&calluserdata, argp, sizeof(calluserdata))) |
1520 | rc = copy_to_user(argp, &x25->causediag, | ||
1521 | sizeof(x25->causediag)) | ||
1522 | ? -EFAULT : 0; | ||
1523 | release_sock(sk); | ||
1524 | break; | 1529 | break; |
1525 | } | 1530 | rc = -EINVAL; |
1531 | if (calluserdata.cudlength > X25_MAX_CUD_LEN) | ||
1532 | break; | ||
1533 | lock_sock(sk); | ||
1534 | x25->calluserdata = calluserdata; | ||
1535 | release_sock(sk); | ||
1536 | rc = 0; | ||
1537 | break; | ||
1538 | } | ||
1526 | 1539 | ||
1527 | case SIOCX25SCAUSEDIAG: { | 1540 | case SIOCX25GCAUSEDIAG: { |
1528 | struct x25_causediag causediag; | 1541 | lock_sock(sk); |
1529 | rc = -EFAULT; | 1542 | rc = copy_to_user(argp, &x25->causediag, sizeof(x25->causediag)) |
1530 | if (copy_from_user(&causediag, argp, sizeof(causediag))) | 1543 | ? -EFAULT : 0; |
1531 | break; | 1544 | release_sock(sk); |
1532 | lock_sock(sk); | 1545 | break; |
1533 | x25->causediag = causediag; | 1546 | } |
1534 | release_sock(sk); | 1547 | |
1535 | rc = 0; | 1548 | case SIOCX25SCAUSEDIAG: { |
1549 | struct x25_causediag causediag; | ||
1550 | rc = -EFAULT; | ||
1551 | if (copy_from_user(&causediag, argp, sizeof(causediag))) | ||
1536 | break; | 1552 | break; |
1553 | lock_sock(sk); | ||
1554 | x25->causediag = causediag; | ||
1555 | release_sock(sk); | ||
1556 | rc = 0; | ||
1557 | break; | ||
1537 | 1558 | ||
1538 | } | 1559 | } |
1539 | 1560 | ||
1540 | case SIOCX25SCUDMATCHLEN: { | 1561 | case SIOCX25SCUDMATCHLEN: { |
1541 | struct x25_subaddr sub_addr; | 1562 | struct x25_subaddr sub_addr; |
1542 | rc = -EINVAL; | 1563 | rc = -EINVAL; |
1543 | lock_sock(sk); | 1564 | lock_sock(sk); |
1544 | if(sk->sk_state != TCP_CLOSE) | 1565 | if(sk->sk_state != TCP_CLOSE) |
1545 | goto out_cud_release; | 1566 | goto out_cud_release; |
1546 | rc = -EFAULT; | 1567 | rc = -EFAULT; |
1547 | if (copy_from_user(&sub_addr, argp, | 1568 | if (copy_from_user(&sub_addr, argp, |
1548 | sizeof(sub_addr))) | 1569 | sizeof(sub_addr))) |
1549 | goto out_cud_release; | 1570 | goto out_cud_release; |
1550 | rc = -EINVAL; | 1571 | rc = -EINVAL; |
1551 | if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) | 1572 | if (sub_addr.cudmatchlength > X25_MAX_CUD_LEN) |
1552 | goto out_cud_release; | 1573 | goto out_cud_release; |
1553 | x25->cudmatchlength = sub_addr.cudmatchlength; | 1574 | x25->cudmatchlength = sub_addr.cudmatchlength; |
1554 | rc = 0; | 1575 | rc = 0; |
1555 | out_cud_release: | 1576 | out_cud_release: |
1556 | release_sock(sk); | 1577 | release_sock(sk); |
1557 | break; | 1578 | break; |
1558 | } | 1579 | } |
1559 | 1580 | ||
1560 | case SIOCX25CALLACCPTAPPRV: { | 1581 | case SIOCX25CALLACCPTAPPRV: { |
1561 | rc = -EINVAL; | 1582 | rc = -EINVAL; |
1562 | lock_sock(sk); | 1583 | lock_sock(sk); |
1563 | if (sk->sk_state != TCP_CLOSE) | 1584 | if (sk->sk_state != TCP_CLOSE) |
1564 | break; | ||
1565 | clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); | ||
1566 | release_sock(sk); | ||
1567 | rc = 0; | ||
1568 | break; | 1585 | break; |
1569 | } | 1586 | clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); |
1587 | release_sock(sk); | ||
1588 | rc = 0; | ||
1589 | break; | ||
1590 | } | ||
1570 | 1591 | ||
1571 | case SIOCX25SENDCALLACCPT: { | 1592 | case SIOCX25SENDCALLACCPT: { |
1572 | rc = -EINVAL; | 1593 | rc = -EINVAL; |
1573 | lock_sock(sk); | 1594 | lock_sock(sk); |
1574 | if (sk->sk_state != TCP_ESTABLISHED) | 1595 | if (sk->sk_state != TCP_ESTABLISHED) |
1575 | break; | ||
1576 | /* must call accptapprv above */ | ||
1577 | if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags)) | ||
1578 | break; | ||
1579 | x25_write_internal(sk, X25_CALL_ACCEPTED); | ||
1580 | x25->state = X25_STATE_3; | ||
1581 | release_sock(sk); | ||
1582 | rc = 0; | ||
1583 | break; | 1596 | break; |
1584 | } | 1597 | /* must call accptapprv above */ |
1585 | 1598 | if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags)) | |
1586 | default: | ||
1587 | rc = -ENOIOCTLCMD; | ||
1588 | break; | 1599 | break; |
1600 | x25_write_internal(sk, X25_CALL_ACCEPTED); | ||
1601 | x25->state = X25_STATE_3; | ||
1602 | release_sock(sk); | ||
1603 | rc = 0; | ||
1604 | break; | ||
1605 | } | ||
1606 | |||
1607 | default: | ||
1608 | rc = -ENOIOCTLCMD; | ||
1609 | break; | ||
1589 | } | 1610 | } |
1590 | 1611 | ||
1591 | return rc; | 1612 | return rc; |
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 9005f6daeab..fa2b41888bd 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c | |||
@@ -32,6 +32,9 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb) | |||
32 | unsigned short frametype; | 32 | unsigned short frametype; |
33 | unsigned int lci; | 33 | unsigned int lci; |
34 | 34 | ||
35 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) | ||
36 | return 0; | ||
37 | |||
35 | frametype = skb->data[2]; | 38 | frametype = skb->data[2]; |
36 | lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); | 39 | lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF); |
37 | 40 | ||
@@ -115,6 +118,9 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, | |||
115 | goto drop; | 118 | goto drop; |
116 | } | 119 | } |
117 | 120 | ||
121 | if (!pskb_may_pull(skb, 1)) | ||
122 | return 0; | ||
123 | |||
118 | switch (skb->data[0]) { | 124 | switch (skb->data[0]) { |
119 | 125 | ||
120 | case X25_IFACE_DATA: | 126 | case X25_IFACE_DATA: |
@@ -146,21 +152,21 @@ void x25_establish_link(struct x25_neigh *nb) | |||
146 | unsigned char *ptr; | 152 | unsigned char *ptr; |
147 | 153 | ||
148 | switch (nb->dev->type) { | 154 | switch (nb->dev->type) { |
149 | case ARPHRD_X25: | 155 | case ARPHRD_X25: |
150 | if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { | 156 | if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) { |
151 | printk(KERN_ERR "x25_dev: out of memory\n"); | 157 | printk(KERN_ERR "x25_dev: out of memory\n"); |
152 | return; | 158 | return; |
153 | } | 159 | } |
154 | ptr = skb_put(skb, 1); | 160 | ptr = skb_put(skb, 1); |
155 | *ptr = X25_IFACE_CONNECT; | 161 | *ptr = X25_IFACE_CONNECT; |
156 | break; | 162 | break; |
157 | 163 | ||
158 | #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) | 164 | #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) |
159 | case ARPHRD_ETHER: | 165 | case ARPHRD_ETHER: |
160 | return; | 166 | return; |
161 | #endif | 167 | #endif |
162 | default: | 168 | default: |
163 | return; | 169 | return; |
164 | } | 170 | } |
165 | 171 | ||
166 | skb->protocol = htons(ETH_P_X25); | 172 | skb->protocol = htons(ETH_P_X25); |
@@ -202,19 +208,19 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb) | |||
202 | skb_reset_network_header(skb); | 208 | skb_reset_network_header(skb); |
203 | 209 | ||
204 | switch (nb->dev->type) { | 210 | switch (nb->dev->type) { |
205 | case ARPHRD_X25: | 211 | case ARPHRD_X25: |
206 | dptr = skb_push(skb, 1); | 212 | dptr = skb_push(skb, 1); |
207 | *dptr = X25_IFACE_DATA; | 213 | *dptr = X25_IFACE_DATA; |
208 | break; | 214 | break; |
209 | 215 | ||
210 | #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) | 216 | #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) |
211 | case ARPHRD_ETHER: | 217 | case ARPHRD_ETHER: |
212 | kfree_skb(skb); | 218 | kfree_skb(skb); |
213 | return; | 219 | return; |
214 | #endif | 220 | #endif |
215 | default: | 221 | default: |
216 | kfree_skb(skb); | 222 | kfree_skb(skb); |
217 | return; | 223 | return; |
218 | } | 224 | } |
219 | 225 | ||
220 | skb->protocol = htons(ETH_P_X25); | 226 | skb->protocol = htons(ETH_P_X25); |
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index f77e4e75f91..36384a1fa9f 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c | |||
@@ -44,7 +44,7 @@ | |||
44 | int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, | 44 | int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, |
45 | struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) | 45 | struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) |
46 | { | 46 | { |
47 | unsigned char *p = skb->data; | 47 | unsigned char *p; |
48 | unsigned int len; | 48 | unsigned int len; |
49 | 49 | ||
50 | *vc_fac_mask = 0; | 50 | *vc_fac_mask = 0; |
@@ -60,14 +60,16 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, | |||
60 | memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); | 60 | memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); |
61 | memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); | 61 | memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); |
62 | 62 | ||
63 | if (skb->len < 1) | 63 | if (!pskb_may_pull(skb, 1)) |
64 | return 0; | 64 | return 0; |
65 | 65 | ||
66 | len = *p++; | 66 | len = skb->data[0]; |
67 | 67 | ||
68 | if (len >= skb->len) | 68 | if (!pskb_may_pull(skb, 1 + len)) |
69 | return -1; | 69 | return -1; |
70 | 70 | ||
71 | p = skb->data + 1; | ||
72 | |||
71 | while (len > 0) { | 73 | while (len > 0) { |
72 | switch (*p & X25_FAC_CLASS_MASK) { | 74 | switch (*p & X25_FAC_CLASS_MASK) { |
73 | case X25_FAC_CLASS_A: | 75 | case X25_FAC_CLASS_A: |
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index 15de65f0471..a49cd4ec551 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c | |||
@@ -94,55 +94,62 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
94 | struct x25_sock *x25 = x25_sk(sk); | 94 | struct x25_sock *x25 = x25_sk(sk); |
95 | 95 | ||
96 | switch (frametype) { | 96 | switch (frametype) { |
97 | case X25_CALL_ACCEPTED: { | 97 | case X25_CALL_ACCEPTED: { |
98 | 98 | ||
99 | x25_stop_timer(sk); | 99 | x25_stop_timer(sk); |
100 | x25->condition = 0x00; | 100 | x25->condition = 0x00; |
101 | x25->vs = 0; | 101 | x25->vs = 0; |
102 | x25->va = 0; | 102 | x25->va = 0; |
103 | x25->vr = 0; | 103 | x25->vr = 0; |
104 | x25->vl = 0; | 104 | x25->vl = 0; |
105 | x25->state = X25_STATE_3; | 105 | x25->state = X25_STATE_3; |
106 | sk->sk_state = TCP_ESTABLISHED; | 106 | sk->sk_state = TCP_ESTABLISHED; |
107 | /* | 107 | /* |
108 | * Parse the data in the frame. | 108 | * Parse the data in the frame. |
109 | */ | 109 | */ |
110 | skb_pull(skb, X25_STD_MIN_LEN); | 110 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) |
111 | 111 | goto out_clear; | |
112 | len = x25_parse_address_block(skb, &source_addr, | 112 | skb_pull(skb, X25_STD_MIN_LEN); |
113 | &dest_addr); | 113 | |
114 | if (len > 0) | 114 | len = x25_parse_address_block(skb, &source_addr, |
115 | skb_pull(skb, len); | 115 | &dest_addr); |
116 | else if (len < 0) | 116 | if (len > 0) |
117 | skb_pull(skb, len); | ||
118 | else if (len < 0) | ||
119 | goto out_clear; | ||
120 | |||
121 | len = x25_parse_facilities(skb, &x25->facilities, | ||
122 | &x25->dte_facilities, | ||
123 | &x25->vc_facil_mask); | ||
124 | if (len > 0) | ||
125 | skb_pull(skb, len); | ||
126 | else if (len < 0) | ||
127 | goto out_clear; | ||
128 | /* | ||
129 | * Copy any Call User Data. | ||
130 | */ | ||
131 | if (skb->len > 0) { | ||
132 | if (skb->len > X25_MAX_CUD_LEN) | ||
117 | goto out_clear; | 133 | goto out_clear; |
118 | 134 | ||
119 | len = x25_parse_facilities(skb, &x25->facilities, | 135 | skb_copy_bits(skb, 0, x25->calluserdata.cuddata, |
120 | &x25->dte_facilities, | 136 | skb->len); |
121 | &x25->vc_facil_mask); | 137 | x25->calluserdata.cudlength = skb->len; |
122 | if (len > 0) | ||
123 | skb_pull(skb, len); | ||
124 | else if (len < 0) | ||
125 | goto out_clear; | ||
126 | /* | ||
127 | * Copy any Call User Data. | ||
128 | */ | ||
129 | if (skb->len > 0) { | ||
130 | skb_copy_from_linear_data(skb, | ||
131 | x25->calluserdata.cuddata, | ||
132 | skb->len); | ||
133 | x25->calluserdata.cudlength = skb->len; | ||
134 | } | ||
135 | if (!sock_flag(sk, SOCK_DEAD)) | ||
136 | sk->sk_state_change(sk); | ||
137 | break; | ||
138 | } | 138 | } |
139 | case X25_CLEAR_REQUEST: | 139 | if (!sock_flag(sk, SOCK_DEAD)) |
140 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 140 | sk->sk_state_change(sk); |
141 | x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); | 141 | break; |
142 | break; | 142 | } |
143 | case X25_CLEAR_REQUEST: | ||
144 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
145 | goto out_clear; | ||
143 | 146 | ||
144 | default: | 147 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
145 | break; | 148 | x25_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); |
149 | break; | ||
150 | |||
151 | default: | ||
152 | break; | ||
146 | } | 153 | } |
147 | 154 | ||
148 | return 0; | 155 | return 0; |
@@ -164,6 +171,9 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
164 | switch (frametype) { | 171 | switch (frametype) { |
165 | 172 | ||
166 | case X25_CLEAR_REQUEST: | 173 | case X25_CLEAR_REQUEST: |
174 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
175 | goto out_clear; | ||
176 | |||
167 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 177 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
168 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); | 178 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); |
169 | break; | 179 | break; |
@@ -177,6 +187,11 @@ static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
177 | } | 187 | } |
178 | 188 | ||
179 | return 0; | 189 | return 0; |
190 | |||
191 | out_clear: | ||
192 | x25_write_internal(sk, X25_CLEAR_REQUEST); | ||
193 | x25_start_t23timer(sk); | ||
194 | return 0; | ||
180 | } | 195 | } |
181 | 196 | ||
182 | /* | 197 | /* |
@@ -206,6 +221,9 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
206 | break; | 221 | break; |
207 | 222 | ||
208 | case X25_CLEAR_REQUEST: | 223 | case X25_CLEAR_REQUEST: |
224 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
225 | goto out_clear; | ||
226 | |||
209 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 227 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
210 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); | 228 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); |
211 | break; | 229 | break; |
@@ -304,6 +322,12 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
304 | } | 322 | } |
305 | 323 | ||
306 | return queued; | 324 | return queued; |
325 | |||
326 | out_clear: | ||
327 | x25_write_internal(sk, X25_CLEAR_REQUEST); | ||
328 | x25->state = X25_STATE_2; | ||
329 | x25_start_t23timer(sk); | ||
330 | return 0; | ||
307 | } | 331 | } |
308 | 332 | ||
309 | /* | 333 | /* |
@@ -313,13 +337,13 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
313 | */ | 337 | */ |
314 | static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) | 338 | static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype) |
315 | { | 339 | { |
340 | struct x25_sock *x25 = x25_sk(sk); | ||
341 | |||
316 | switch (frametype) { | 342 | switch (frametype) { |
317 | 343 | ||
318 | case X25_RESET_REQUEST: | 344 | case X25_RESET_REQUEST: |
319 | x25_write_internal(sk, X25_RESET_CONFIRMATION); | 345 | x25_write_internal(sk, X25_RESET_CONFIRMATION); |
320 | case X25_RESET_CONFIRMATION: { | 346 | case X25_RESET_CONFIRMATION: { |
321 | struct x25_sock *x25 = x25_sk(sk); | ||
322 | |||
323 | x25_stop_timer(sk); | 347 | x25_stop_timer(sk); |
324 | x25->condition = 0x00; | 348 | x25->condition = 0x00; |
325 | x25->va = 0; | 349 | x25->va = 0; |
@@ -331,6 +355,9 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
331 | break; | 355 | break; |
332 | } | 356 | } |
333 | case X25_CLEAR_REQUEST: | 357 | case X25_CLEAR_REQUEST: |
358 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 2)) | ||
359 | goto out_clear; | ||
360 | |||
334 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); | 361 | x25_write_internal(sk, X25_CLEAR_CONFIRMATION); |
335 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); | 362 | x25_disconnect(sk, 0, skb->data[3], skb->data[4]); |
336 | break; | 363 | break; |
@@ -340,6 +367,12 @@ static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
340 | } | 367 | } |
341 | 368 | ||
342 | return 0; | 369 | return 0; |
370 | |||
371 | out_clear: | ||
372 | x25_write_internal(sk, X25_CLEAR_REQUEST); | ||
373 | x25->state = X25_STATE_2; | ||
374 | x25_start_t23timer(sk); | ||
375 | return 0; | ||
343 | } | 376 | } |
344 | 377 | ||
345 | /* Higher level upcall for a LAPB frame */ | 378 | /* Higher level upcall for a LAPB frame */ |
@@ -354,18 +387,18 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb) | |||
354 | frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m); | 387 | frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m); |
355 | 388 | ||
356 | switch (x25->state) { | 389 | switch (x25->state) { |
357 | case X25_STATE_1: | 390 | case X25_STATE_1: |
358 | queued = x25_state1_machine(sk, skb, frametype); | 391 | queued = x25_state1_machine(sk, skb, frametype); |
359 | break; | 392 | break; |
360 | case X25_STATE_2: | 393 | case X25_STATE_2: |
361 | queued = x25_state2_machine(sk, skb, frametype); | 394 | queued = x25_state2_machine(sk, skb, frametype); |
362 | break; | 395 | break; |
363 | case X25_STATE_3: | 396 | case X25_STATE_3: |
364 | queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m); | 397 | queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m); |
365 | break; | 398 | break; |
366 | case X25_STATE_4: | 399 | case X25_STATE_4: |
367 | queued = x25_state4_machine(sk, skb, frametype); | 400 | queued = x25_state4_machine(sk, skb, frametype); |
368 | break; | 401 | break; |
369 | } | 402 | } |
370 | 403 | ||
371 | x25_kick(sk); | 404 | x25_kick(sk); |
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 21306928d47..4acacf3c661 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c | |||
@@ -76,30 +76,32 @@ void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb, | |||
76 | int confirm; | 76 | int confirm; |
77 | 77 | ||
78 | switch (frametype) { | 78 | switch (frametype) { |
79 | case X25_RESTART_REQUEST: | 79 | case X25_RESTART_REQUEST: |
80 | confirm = !x25_t20timer_pending(nb); | 80 | confirm = !x25_t20timer_pending(nb); |
81 | x25_stop_t20timer(nb); | 81 | x25_stop_t20timer(nb); |
82 | nb->state = X25_LINK_STATE_3; | 82 | nb->state = X25_LINK_STATE_3; |
83 | if (confirm) | 83 | if (confirm) |
84 | x25_transmit_restart_confirmation(nb); | 84 | x25_transmit_restart_confirmation(nb); |
85 | break; | ||
86 | |||
87 | case X25_RESTART_CONFIRMATION: | ||
88 | x25_stop_t20timer(nb); | ||
89 | nb->state = X25_LINK_STATE_3; | ||
90 | break; | ||
91 | |||
92 | case X25_DIAGNOSTIC: | ||
93 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN + 4)) | ||
85 | break; | 94 | break; |
86 | 95 | ||
87 | case X25_RESTART_CONFIRMATION: | 96 | printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", |
88 | x25_stop_t20timer(nb); | 97 | skb->data[3], skb->data[4], |
89 | nb->state = X25_LINK_STATE_3; | 98 | skb->data[5], skb->data[6]); |
90 | break; | 99 | break; |
91 | |||
92 | case X25_DIAGNOSTIC: | ||
93 | printk(KERN_WARNING "x25: diagnostic #%d - " | ||
94 | "%02X %02X %02X\n", | ||
95 | skb->data[3], skb->data[4], | ||
96 | skb->data[5], skb->data[6]); | ||
97 | break; | ||
98 | 100 | ||
99 | default: | 101 | default: |
100 | printk(KERN_WARNING "x25: received unknown %02X " | 102 | printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", |
101 | "with LCI 000\n", frametype); | 103 | frametype); |
102 | break; | 104 | break; |
103 | } | 105 | } |
104 | 106 | ||
105 | if (nb->state == X25_LINK_STATE_3) | 107 | if (nb->state == X25_LINK_STATE_3) |
@@ -193,18 +195,18 @@ void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci, | |||
193 | void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb) | 195 | void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb) |
194 | { | 196 | { |
195 | switch (nb->state) { | 197 | switch (nb->state) { |
196 | case X25_LINK_STATE_0: | 198 | case X25_LINK_STATE_0: |
197 | skb_queue_tail(&nb->queue, skb); | 199 | skb_queue_tail(&nb->queue, skb); |
198 | nb->state = X25_LINK_STATE_1; | 200 | nb->state = X25_LINK_STATE_1; |
199 | x25_establish_link(nb); | 201 | x25_establish_link(nb); |
200 | break; | 202 | break; |
201 | case X25_LINK_STATE_1: | 203 | case X25_LINK_STATE_1: |
202 | case X25_LINK_STATE_2: | 204 | case X25_LINK_STATE_2: |
203 | skb_queue_tail(&nb->queue, skb); | 205 | skb_queue_tail(&nb->queue, skb); |
204 | break; | 206 | break; |
205 | case X25_LINK_STATE_3: | 207 | case X25_LINK_STATE_3: |
206 | x25_send_frame(skb, nb); | 208 | x25_send_frame(skb, nb); |
207 | break; | 209 | break; |
208 | } | 210 | } |
209 | } | 211 | } |
210 | 212 | ||
@@ -214,14 +216,14 @@ void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb) | |||
214 | void x25_link_established(struct x25_neigh *nb) | 216 | void x25_link_established(struct x25_neigh *nb) |
215 | { | 217 | { |
216 | switch (nb->state) { | 218 | switch (nb->state) { |
217 | case X25_LINK_STATE_0: | 219 | case X25_LINK_STATE_0: |
218 | nb->state = X25_LINK_STATE_2; | 220 | nb->state = X25_LINK_STATE_2; |
219 | break; | 221 | break; |
220 | case X25_LINK_STATE_1: | 222 | case X25_LINK_STATE_1: |
221 | x25_transmit_restart_request(nb); | 223 | x25_transmit_restart_request(nb); |
222 | nb->state = X25_LINK_STATE_2; | 224 | nb->state = X25_LINK_STATE_2; |
223 | x25_start_t20timer(nb); | 225 | x25_start_t20timer(nb); |
224 | break; | 226 | break; |
225 | } | 227 | } |
226 | } | 228 | } |
227 | 229 | ||
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index dc20cf12f39..5170d52bfd9 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c | |||
@@ -126,32 +126,30 @@ void x25_write_internal(struct sock *sk, int frametype) | |||
126 | * Adjust frame size. | 126 | * Adjust frame size. |
127 | */ | 127 | */ |
128 | switch (frametype) { | 128 | switch (frametype) { |
129 | case X25_CALL_REQUEST: | 129 | case X25_CALL_REQUEST: |
130 | len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + | 130 | len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN; |
131 | X25_MAX_CUD_LEN; | 131 | break; |
132 | break; | 132 | case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */ |
133 | case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */ | 133 | if (x25->facilities.reverse & 0x80) { |
134 | if(x25->facilities.reverse & 0x80) { | 134 | len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN; |
135 | len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN; | 135 | } else { |
136 | } else { | 136 | len += 1 + X25_MAX_FAC_LEN; |
137 | len += 1 + X25_MAX_FAC_LEN; | 137 | } |
138 | } | 138 | break; |
139 | break; | 139 | case X25_CLEAR_REQUEST: |
140 | case X25_CLEAR_REQUEST: | 140 | case X25_RESET_REQUEST: |
141 | case X25_RESET_REQUEST: | 141 | len += 2; |
142 | len += 2; | 142 | break; |
143 | break; | 143 | case X25_RR: |
144 | case X25_RR: | 144 | case X25_RNR: |
145 | case X25_RNR: | 145 | case X25_REJ: |
146 | case X25_REJ: | 146 | case X25_CLEAR_CONFIRMATION: |
147 | case X25_CLEAR_CONFIRMATION: | 147 | case X25_INTERRUPT_CONFIRMATION: |
148 | case X25_INTERRUPT_CONFIRMATION: | 148 | case X25_RESET_CONFIRMATION: |
149 | case X25_RESET_CONFIRMATION: | 149 | break; |
150 | break; | 150 | default: |
151 | default: | 151 | printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype); |
152 | printk(KERN_ERR "X.25: invalid frame type %02X\n", | 152 | return; |
153 | frametype); | ||
154 | return; | ||
155 | } | 153 | } |
156 | 154 | ||
157 | if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) | 155 | if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) |
@@ -271,31 +269,39 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, | |||
271 | int *d, int *m) | 269 | int *d, int *m) |
272 | { | 270 | { |
273 | struct x25_sock *x25 = x25_sk(sk); | 271 | struct x25_sock *x25 = x25_sk(sk); |
274 | unsigned char *frame = skb->data; | 272 | unsigned char *frame; |
273 | |||
274 | if (!pskb_may_pull(skb, X25_STD_MIN_LEN)) | ||
275 | return X25_ILLEGAL; | ||
276 | frame = skb->data; | ||
275 | 277 | ||
276 | *ns = *nr = *q = *d = *m = 0; | 278 | *ns = *nr = *q = *d = *m = 0; |
277 | 279 | ||
278 | switch (frame[2]) { | 280 | switch (frame[2]) { |
279 | case X25_CALL_REQUEST: | 281 | case X25_CALL_REQUEST: |
280 | case X25_CALL_ACCEPTED: | 282 | case X25_CALL_ACCEPTED: |
281 | case X25_CLEAR_REQUEST: | 283 | case X25_CLEAR_REQUEST: |
282 | case X25_CLEAR_CONFIRMATION: | 284 | case X25_CLEAR_CONFIRMATION: |
283 | case X25_INTERRUPT: | 285 | case X25_INTERRUPT: |
284 | case X25_INTERRUPT_CONFIRMATION: | 286 | case X25_INTERRUPT_CONFIRMATION: |
285 | case X25_RESET_REQUEST: | 287 | case X25_RESET_REQUEST: |
286 | case X25_RESET_CONFIRMATION: | 288 | case X25_RESET_CONFIRMATION: |
287 | case X25_RESTART_REQUEST: | 289 | case X25_RESTART_REQUEST: |
288 | case X25_RESTART_CONFIRMATION: | 290 | case X25_RESTART_CONFIRMATION: |
289 | case X25_REGISTRATION_REQUEST: | 291 | case X25_REGISTRATION_REQUEST: |
290 | case X25_REGISTRATION_CONFIRMATION: | 292 | case X25_REGISTRATION_CONFIRMATION: |
291 | case X25_DIAGNOSTIC: | 293 | case X25_DIAGNOSTIC: |
292 | return frame[2]; | 294 | return frame[2]; |
293 | } | 295 | } |
294 | 296 | ||
295 | if (x25->neighbour->extended) { | 297 | if (x25->neighbour->extended) { |
296 | if (frame[2] == X25_RR || | 298 | if (frame[2] == X25_RR || |
297 | frame[2] == X25_RNR || | 299 | frame[2] == X25_RNR || |
298 | frame[2] == X25_REJ) { | 300 | frame[2] == X25_REJ) { |
301 | if (!pskb_may_pull(skb, X25_EXT_MIN_LEN)) | ||
302 | return X25_ILLEGAL; | ||
303 | frame = skb->data; | ||
304 | |||
299 | *nr = (frame[3] >> 1) & 0x7F; | 305 | *nr = (frame[3] >> 1) & 0x7F; |
300 | return frame[2]; | 306 | return frame[2]; |
301 | } | 307 | } |
@@ -310,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, | |||
310 | 316 | ||
311 | if (x25->neighbour->extended) { | 317 | if (x25->neighbour->extended) { |
312 | if ((frame[2] & 0x01) == X25_DATA) { | 318 | if ((frame[2] & 0x01) == X25_DATA) { |
319 | if (!pskb_may_pull(skb, X25_EXT_MIN_LEN)) | ||
320 | return X25_ILLEGAL; | ||
321 | frame = skb->data; | ||
322 | |||
313 | *q = (frame[0] & X25_Q_BIT) == X25_Q_BIT; | 323 | *q = (frame[0] & X25_Q_BIT) == X25_Q_BIT; |
314 | *d = (frame[0] & X25_D_BIT) == X25_D_BIT; | 324 | *d = (frame[0] & X25_D_BIT) == X25_D_BIT; |
315 | *m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT; | 325 | *m = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT; |