aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet/pep.c
diff options
context:
space:
mode:
authorRémi Denis-Courmont <remi.denis-courmont@nokia.com>2011-03-08 17:44:12 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-09 14:59:33 -0500
commit297edb6003268c1d60da8c21eb76bf39b6428213 (patch)
treeb17c7544eed3430ed89a56e54a3de14fe9755c3c /net/phonet/pep.c
parentacaf7df610ff3faf1778ce40d601fc3dd4a41b40 (diff)
Phonet: support active connection without pipe controller on modem
This provides support for newer ISI modems with no need for the earlier experimental compile-time alternative choice. With this, we can now use the same kernel and userspace with both types of modems. This also avoids confusing two different and incompatible state machines, actively connected vs accepted sockets, and adds connection response error handling (processing "SYN/RST" of sorts). Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/phonet/pep.c')
-rw-r--r--net/phonet/pep.c172
1 files changed, 101 insertions, 71 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index abfb795af142..671effb4ea15 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -136,7 +136,6 @@ static int pep_indicate(struct sock *sk, u8 id, u8 code,
136 136
137#define PAD 0x00 137#define PAD 0x00
138 138
139#ifdef CONFIG_PHONET_PIPECTRLR
140static int pipe_handler_request(struct sock *sk, u8 id, u8 code, 139static int pipe_handler_request(struct sock *sk, u8 id, u8 code,
141 const void *data, int len) 140 const void *data, int len)
142{ 141{
@@ -168,11 +167,7 @@ static int pipe_handler_send_created_ind(struct sock *sk)
168 data, 4, GFP_ATOMIC); 167 data, 4, GFP_ATOMIC);
169} 168}
170 169
171static int pipe_handler_send_ind(struct sock *sk, u8 id) 170#ifdef CONFIG_PHONET_PIPECTRLR
172{
173 return pep_indicate(sk, id, PAD, NULL, 0, GFP_ATOMIC);
174}
175
176static int pipe_handler_enable_pipe(struct sock *sk, int enable) 171static int pipe_handler_enable_pipe(struct sock *sk, int enable)
177{ 172{
178 u8 id = enable ? PNS_PEP_ENABLE_REQ : PNS_PEP_DISABLE_REQ; 173 u8 id = enable ? PNS_PEP_ENABLE_REQ : PNS_PEP_DISABLE_REQ;
@@ -376,32 +371,11 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
376 sk->sk_state_change(sk); 371 sk->sk_state_change(sk);
377 break; 372 break;
378 373
379#ifdef CONFIG_PHONET_PIPECTRLR
380 case PNS_PEP_DISCONNECT_RESP:
381 sk->sk_state = TCP_CLOSE;
382 break;
383#endif
384
385 case PNS_PEP_ENABLE_REQ: 374 case PNS_PEP_ENABLE_REQ:
386 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ 375 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
387 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 376 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
388 break; 377 break;
389 378
390#ifdef CONFIG_PHONET_PIPECTRLR
391 case PNS_PEP_ENABLE_RESP:
392 pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND);
393
394 if (!pn_flow_safe(pn->tx_fc)) {
395 atomic_set(&pn->tx_credits, 1);
396 sk->sk_write_space(sk);
397 }
398 if (sk->sk_state == TCP_ESTABLISHED)
399 break; /* Nothing to do */
400 sk->sk_state = TCP_ESTABLISHED;
401 pipe_grant_credits(sk, GFP_ATOMIC);
402 break;
403#endif
404
405 case PNS_PEP_RESET_REQ: 379 case PNS_PEP_RESET_REQ:
406 switch (hdr->state_after_reset) { 380 switch (hdr->state_after_reset) {
407 case PN_PIPE_DISABLE: 381 case PN_PIPE_DISABLE:
@@ -420,15 +394,6 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
420 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 394 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
421 break; 395 break;
422 396
423#ifdef CONFIG_PHONET_PIPECTRLR
424 case PNS_PEP_DISABLE_RESP:
425 atomic_set(&pn->tx_credits, 0);
426 pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND);
427 sk->sk_state = TCP_SYN_RECV;
428 pn->rx_credits = 0;
429 break;
430#endif
431
432 case PNS_PEP_CTRL_REQ: 397 case PNS_PEP_CTRL_REQ:
433 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { 398 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
434 atomic_inc(&sk->sk_drops); 399 atomic_inc(&sk->sk_drops);
@@ -521,7 +486,6 @@ static void pipe_destruct(struct sock *sk)
521 skb_queue_purge(&pn->ctrlreq_queue); 486 skb_queue_purge(&pn->ctrlreq_queue);
522} 487}
523 488
524#ifdef CONFIG_PHONET_PIPECTRLR
525static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) 489static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n)
526{ 490{
527 unsigned i; 491 unsigned i;
@@ -546,6 +510,8 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
546 return -EINVAL; 510 return -EINVAL;
547 511
548 hdr = pnp_hdr(skb); 512 hdr = pnp_hdr(skb);
513 if (hdr->error_code != PN_PIPE_NO_ERROR)
514 return -ECONNREFUSED;
549 515
550 /* Parse sub-blocks */ 516 /* Parse sub-blocks */
551 n_sb = hdr->data[4]; 517 n_sb = hdr->data[4];
@@ -573,14 +539,74 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
573 n_sb--; 539 n_sb--;
574 } 540 }
575 541
576 sk->sk_state = TCP_SYN_RECV;
577 sk->sk_backlog_rcv = pipe_do_rcv;
578 pn->rx_credits = 0;
579 sk->sk_state_change(sk);
580
581 return pipe_handler_send_created_ind(sk); 542 return pipe_handler_send_created_ind(sk);
582} 543}
583#endif 544
545/* Queue an skb to an actively connected sock.
546 * Socket lock must be held. */
547static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
548{
549 struct pep_sock *pn = pep_sk(sk);
550 struct pnpipehdr *hdr = pnp_hdr(skb);
551 int err = NET_RX_SUCCESS;
552
553 switch (hdr->message_id) {
554 case PNS_PIPE_ALIGNED_DATA:
555 __skb_pull(skb, 1);
556 /* fall through */
557 case PNS_PIPE_DATA:
558 __skb_pull(skb, 3); /* Pipe data header */
559 if (!pn_flow_safe(pn->rx_fc)) {
560 err = sock_queue_rcv_skb(sk, skb);
561 if (!err)
562 return NET_RX_SUCCESS;
563 err = NET_RX_DROP;
564 break;
565 }
566
567 if (pn->rx_credits == 0) {
568 atomic_inc(&sk->sk_drops);
569 err = NET_RX_DROP;
570 break;
571 }
572 pn->rx_credits--;
573 skb->dev = NULL;
574 skb_set_owner_r(skb, sk);
575 err = skb->len;
576 skb_queue_tail(&sk->sk_receive_queue, skb);
577 if (!sock_flag(sk, SOCK_DEAD))
578 sk->sk_data_ready(sk, err);
579 return NET_RX_SUCCESS;
580
581 case PNS_PEP_CONNECT_RESP:
582 if (sk->sk_state != TCP_SYN_SENT)
583 break;
584 if (!sock_flag(sk, SOCK_DEAD))
585 sk->sk_state_change(sk);
586 if (pep_connresp_rcv(sk, skb)) {
587 sk->sk_state = TCP_CLOSE_WAIT;
588 break;
589 }
590
591 sk->sk_state = TCP_ESTABLISHED;
592 if (!pn_flow_safe(pn->tx_fc)) {
593 atomic_set(&pn->tx_credits, 1);
594 sk->sk_write_space(sk);
595 }
596 pipe_grant_credits(sk, GFP_ATOMIC);
597 break;
598
599 case PNS_PEP_DISCONNECT_RESP:
600 /* sock should already be dead, nothing to do */
601 break;
602
603 case PNS_PEP_STATUS_IND:
604 pipe_rcv_status(sk, skb);
605 break;
606 }
607 kfree_skb(skb);
608 return err;
609}
584 610
585/* Listening sock must be locked */ 611/* Listening sock must be locked */
586static struct sock *pep_find_pipe(const struct hlist_head *hlist, 612static struct sock *pep_find_pipe(const struct hlist_head *hlist,
@@ -649,12 +675,6 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
649 sk->sk_data_ready(sk, 0); 675 sk->sk_data_ready(sk, 0);
650 return NET_RX_SUCCESS; 676 return NET_RX_SUCCESS;
651 677
652#ifdef CONFIG_PHONET_PIPECTRLR
653 case PNS_PEP_CONNECT_RESP:
654 pep_connresp_rcv(sk, skb);
655 break;
656#endif
657
658 case PNS_PEP_DISCONNECT_REQ: 678 case PNS_PEP_DISCONNECT_REQ:
659 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 679 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
660 break; 680 break;
@@ -667,15 +687,19 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
667 case PNS_PEP_ENABLE_REQ: 687 case PNS_PEP_ENABLE_REQ:
668 case PNS_PEP_DISABLE_REQ: 688 case PNS_PEP_DISABLE_REQ:
669 /* invalid handle is not even allowed here! */ 689 /* invalid handle is not even allowed here! */
670 default:
671 break; 690 break;
691
692 default:
693 if ((1 << sk->sk_state)
694 & ~(TCPF_CLOSE|TCPF_LISTEN|TCPF_CLOSE_WAIT))
695 /* actively connected socket */
696 return pipe_handler_do_rcv(sk, skb);
672 } 697 }
673drop: 698drop:
674 kfree_skb(skb); 699 kfree_skb(skb);
675 return NET_RX_SUCCESS; 700 return NET_RX_SUCCESS;
676} 701}
677 702
678#ifndef CONFIG_PHONET_PIPECTRLR
679static int pipe_do_remove(struct sock *sk) 703static int pipe_do_remove(struct sock *sk)
680{ 704{
681 struct pep_sock *pn = pep_sk(sk); 705 struct pep_sock *pn = pep_sk(sk);
@@ -693,7 +717,6 @@ static int pipe_do_remove(struct sock *sk)
693 ph->data[0] = PAD; 717 ph->data[0] = PAD;
694 return pn_skb_send(sk, skb, NULL); 718 return pn_skb_send(sk, skb, NULL);
695} 719}
696#endif
697 720
698/* associated socket ceases to exist */ 721/* associated socket ceases to exist */
699static void pep_sock_close(struct sock *sk, long timeout) 722static void pep_sock_close(struct sock *sk, long timeout)
@@ -706,13 +729,12 @@ static void pep_sock_close(struct sock *sk, long timeout)
706 729
707 lock_sock(sk); 730 lock_sock(sk);
708 if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { 731 if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) {
709#ifndef CONFIG_PHONET_PIPECTRLR 732 if (sk->sk_backlog_rcv == pipe_do_rcv)
710 /* Forcefully remove dangling Phonet pipe */ 733 /* Forcefully remove dangling Phonet pipe */
711 pipe_do_remove(sk); 734 pipe_do_remove(sk);
712#else 735 else
713 /* send pep disconnect request */ 736 pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD,
714 pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, NULL, 0); 737 NULL, 0);
715#endif
716 } 738 }
717 sk->sk_state = TCP_CLOSE; 739 sk->sk_state = TCP_CLOSE;
718 740
@@ -844,20 +866,22 @@ drop:
844 return newsk; 866 return newsk;
845} 867}
846 868
847#ifdef CONFIG_PHONET_PIPECTRLR
848static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) 869static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len)
849{ 870{
850 struct pep_sock *pn = pep_sk(sk); 871 struct pep_sock *pn = pep_sk(sk);
851 const struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; 872 int err;
852 u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; 873 u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD };
853 874
854 pn->pn_sk.dobject = pn_sockaddr_get_object(spn);
855 pn->pn_sk.resource = pn_sockaddr_get_resource(spn);
856 pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ 875 pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
857 return pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, 876 err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ,
858 PN_PIPE_DISABLE, data, 4); 877 PN_PIPE_ENABLE, data, 4);
878 if (err) {
879 pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
880 return err;
881 }
882 sk->sk_state = TCP_SYN_SENT;
883 return 0;
859} 884}
860#endif
861 885
862static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) 886static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
863{ 887{
@@ -890,8 +914,16 @@ static int pep_init(struct sock *sk)
890 914
891 sk->sk_destruct = pipe_destruct; 915 sk->sk_destruct = pipe_destruct;
892 INIT_HLIST_HEAD(&pn->hlist); 916 INIT_HLIST_HEAD(&pn->hlist);
917 pn->listener = NULL;
893 skb_queue_head_init(&pn->ctrlreq_queue); 918 skb_queue_head_init(&pn->ctrlreq_queue);
919 atomic_set(&pn->tx_credits, 0);
920 pn->ifindex = 0;
921 pn->peer_type = 0;
894 pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 922 pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
923 pn->rx_credits = 0;
924 pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL;
925 pn->init_enable = 1;
926 pn->aligned = 0;
895 return 0; 927 return 0;
896} 928}
897 929
@@ -1219,9 +1251,9 @@ static void pep_sock_unhash(struct sock *sk)
1219 1251
1220 lock_sock(sk); 1252 lock_sock(sk);
1221 1253
1222#ifndef CONFIG_PHONET_PIPECTRLR 1254 if (pn->listener != NULL) {
1223 if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) {
1224 skparent = pn->listener; 1255 skparent = pn->listener;
1256 pn->listener = NULL;
1225 release_sock(sk); 1257 release_sock(sk);
1226 1258
1227 pn = pep_sk(skparent); 1259 pn = pep_sk(skparent);
@@ -1229,7 +1261,7 @@ static void pep_sock_unhash(struct sock *sk)
1229 sk_del_node_init(sk); 1261 sk_del_node_init(sk);
1230 sk = skparent; 1262 sk = skparent;
1231 } 1263 }
1232#endif 1264
1233 /* Unhash a listening sock only when it is closed 1265 /* Unhash a listening sock only when it is closed
1234 * and all of its active connected pipes are closed. */ 1266 * and all of its active connected pipes are closed. */
1235 if (hlist_empty(&pn->hlist)) 1267 if (hlist_empty(&pn->hlist))
@@ -1243,9 +1275,7 @@ static void pep_sock_unhash(struct sock *sk)
1243static struct proto pep_proto = { 1275static struct proto pep_proto = {
1244 .close = pep_sock_close, 1276 .close = pep_sock_close,
1245 .accept = pep_sock_accept, 1277 .accept = pep_sock_accept,
1246#ifdef CONFIG_PHONET_PIPECTRLR
1247 .connect = pep_sock_connect, 1278 .connect = pep_sock_connect,
1248#endif
1249 .ioctl = pep_ioctl, 1279 .ioctl = pep_ioctl,
1250 .init = pep_init, 1280 .init = pep_init,
1251 .setsockopt = pep_setsockopt, 1281 .setsockopt = pep_setsockopt,