diff options
author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2008-10-05 14:15:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-05 14:15:43 -0400 |
commit | c41bd97f815720f9404f97da0c4f4400b52c243d (patch) | |
tree | 104f57ed611ea4a2a7d4cfc370fe3bcd1090a71a /net/phonet/pep.c | |
parent | 9641458d3ec42def729fde64669abf07f3220cd5 (diff) |
Phonet: receive pipe control requests as out-of-band data
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.c | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index c5dfecb207d2..d564d07cb797 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -137,14 +137,15 @@ static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code) | |||
137 | 137 | ||
138 | /* Control requests are not sent by the pipe service and have a specific | 138 | /* Control requests are not sent by the pipe service and have a specific |
139 | * message format. */ | 139 | * message format. */ |
140 | static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code) | 140 | static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, |
141 | gfp_t priority) | ||
141 | { | 142 | { |
142 | const struct pnpipehdr *oph = pnp_hdr(oskb); | 143 | const struct pnpipehdr *oph = pnp_hdr(oskb); |
143 | struct sk_buff *skb; | 144 | struct sk_buff *skb; |
144 | struct pnpipehdr *ph; | 145 | struct pnpipehdr *ph; |
145 | struct sockaddr_pn dst; | 146 | struct sockaddr_pn dst; |
146 | 147 | ||
147 | skb = alloc_skb(MAX_PNPIPE_HEADER + 4, GFP_ATOMIC); | 148 | skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); |
148 | if (!skb) | 149 | if (!skb) |
149 | return -ENOMEM; | 150 | return -ENOMEM; |
150 | skb_set_owner_w(skb, sk); | 151 | skb_set_owner_w(skb, sk); |
@@ -305,6 +306,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
305 | { | 306 | { |
306 | struct pep_sock *pn = pep_sk(sk); | 307 | struct pep_sock *pn = pep_sk(sk); |
307 | struct pnpipehdr *hdr = pnp_hdr(skb); | 308 | struct pnpipehdr *hdr = pnp_hdr(skb); |
309 | struct sk_buff_head *queue; | ||
308 | int err = 0; | 310 | int err = 0; |
309 | 311 | ||
310 | BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); | 312 | BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); |
@@ -345,9 +347,11 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
345 | break; | 347 | break; |
346 | 348 | ||
347 | case PNS_PEP_CTRL_REQ: | 349 | case PNS_PEP_CTRL_REQ: |
348 | /* TODO */ | 350 | if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) |
349 | pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR); | 351 | break; |
350 | break; | 352 | __skb_pull(skb, 4); |
353 | queue = &pn->ctrlreq_queue; | ||
354 | goto queue; | ||
351 | 355 | ||
352 | case PNS_PIPE_DATA: | 356 | case PNS_PIPE_DATA: |
353 | __skb_pull(skb, 3); /* Pipe data header */ | 357 | __skb_pull(skb, 3); /* Pipe data header */ |
@@ -363,13 +367,8 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
363 | break; | 367 | break; |
364 | } | 368 | } |
365 | pn->rx_credits--; | 369 | pn->rx_credits--; |
366 | skb->dev = NULL; | 370 | queue = &sk->sk_receive_queue; |
367 | skb_set_owner_r(skb, sk); | 371 | goto queue; |
368 | err = skb->len; | ||
369 | skb_queue_tail(&sk->sk_receive_queue, skb); | ||
370 | if (!sock_flag(sk, SOCK_DEAD)) | ||
371 | sk->sk_data_ready(sk, err); | ||
372 | return 0; | ||
373 | 372 | ||
374 | case PNS_PEP_STATUS_IND: | 373 | case PNS_PEP_STATUS_IND: |
375 | pipe_rcv_status(sk, skb); | 374 | pipe_rcv_status(sk, skb); |
@@ -412,12 +411,24 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
412 | out: | 411 | out: |
413 | kfree_skb(skb); | 412 | kfree_skb(skb); |
414 | return err; | 413 | return err; |
414 | |||
415 | queue: | ||
416 | skb->dev = NULL; | ||
417 | skb_set_owner_r(skb, sk); | ||
418 | err = skb->len; | ||
419 | skb_queue_tail(queue, skb); | ||
420 | if (!sock_flag(sk, SOCK_DEAD)) | ||
421 | sk->sk_data_ready(sk, err); | ||
422 | return 0; | ||
415 | } | 423 | } |
416 | 424 | ||
417 | /* Destroy connected sock. */ | 425 | /* Destroy connected sock. */ |
418 | static void pipe_destruct(struct sock *sk) | 426 | static void pipe_destruct(struct sock *sk) |
419 | { | 427 | { |
428 | struct pep_sock *pn = pep_sk(sk); | ||
429 | |||
420 | skb_queue_purge(&sk->sk_receive_queue); | 430 | skb_queue_purge(&sk->sk_receive_queue); |
431 | skb_queue_purge(&pn->ctrlreq_queue); | ||
421 | } | 432 | } |
422 | 433 | ||
423 | static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) | 434 | static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) |
@@ -490,6 +501,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) | |||
490 | pn_skb_get_dst_sockaddr(skb, &dst); | 501 | pn_skb_get_dst_sockaddr(skb, &dst); |
491 | newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); | 502 | newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); |
492 | newpn->pn_sk.resource = pn->pn_sk.resource; | 503 | newpn->pn_sk.resource = pn->pn_sk.resource; |
504 | skb_queue_head_init(&newpn->ctrlreq_queue); | ||
493 | newpn->pipe_handle = pipe_handle; | 505 | newpn->pipe_handle = pipe_handle; |
494 | newpn->peer_type = peer_type; | 506 | newpn->peer_type = peer_type; |
495 | newpn->rx_credits = newpn->tx_credits = 0; | 507 | newpn->rx_credits = newpn->tx_credits = 0; |
@@ -581,7 +593,7 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
581 | break; | 593 | break; |
582 | 594 | ||
583 | case PNS_PEP_CTRL_REQ: | 595 | case PNS_PEP_CTRL_REQ: |
584 | pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE); | 596 | pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC); |
585 | break; | 597 | break; |
586 | 598 | ||
587 | case PNS_PEP_RESET_REQ: | 599 | case PNS_PEP_RESET_REQ: |
@@ -684,6 +696,7 @@ out: | |||
684 | 696 | ||
685 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | 697 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) |
686 | { | 698 | { |
699 | struct pep_sock *pn = pep_sk(sk); | ||
687 | int answ; | 700 | int answ; |
688 | 701 | ||
689 | switch (cmd) { | 702 | switch (cmd) { |
@@ -692,7 +705,10 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
692 | return -EINVAL; | 705 | return -EINVAL; |
693 | 706 | ||
694 | lock_sock(sk); | 707 | lock_sock(sk); |
695 | if (!skb_queue_empty(&sk->sk_receive_queue)) | 708 | if (sock_flag(sk, SOCK_URGINLINE) |
709 | && !skb_queue_empty(&pn->ctrlreq_queue)) | ||
710 | answ = skb_peek(&pn->ctrlreq_queue)->len; | ||
711 | else if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
696 | answ = skb_peek(&sk->sk_receive_queue)->len; | 712 | answ = skb_peek(&sk->sk_receive_queue)->len; |
697 | else | 713 | else |
698 | answ = 0; | 714 | answ = 0; |
@@ -709,6 +725,7 @@ static int pep_init(struct sock *sk) | |||
709 | 725 | ||
710 | INIT_HLIST_HEAD(&pn->ackq); | 726 | INIT_HLIST_HEAD(&pn->ackq); |
711 | INIT_HLIST_HEAD(&pn->hlist); | 727 | INIT_HLIST_HEAD(&pn->hlist); |
728 | skb_queue_head_init(&pn->ctrlreq_queue); | ||
712 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; | 729 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; |
713 | return 0; | 730 | return 0; |
714 | } | 731 | } |
@@ -810,11 +827,24 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
810 | struct sk_buff *skb; | 827 | struct sk_buff *skb; |
811 | int err; | 828 | int err; |
812 | 829 | ||
813 | if (unlikely(flags & MSG_OOB)) | ||
814 | return -EOPNOTSUPP; | ||
815 | if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) | 830 | if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) |
816 | return -ENOTCONN; | 831 | return -ENOTCONN; |
817 | 832 | ||
833 | if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) { | ||
834 | /* Dequeue and acknowledge control request */ | ||
835 | struct pep_sock *pn = pep_sk(sk); | ||
836 | |||
837 | skb = skb_dequeue(&pn->ctrlreq_queue); | ||
838 | if (skb) { | ||
839 | pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, | ||
840 | GFP_KERNEL); | ||
841 | msg->msg_flags |= MSG_OOB; | ||
842 | goto copy; | ||
843 | } | ||
844 | if (flags & MSG_OOB) | ||
845 | return -EINVAL; | ||
846 | } | ||
847 | |||
818 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 848 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
819 | lock_sock(sk); | 849 | lock_sock(sk); |
820 | if (skb == NULL) { | 850 | if (skb == NULL) { |
@@ -827,9 +857,8 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
827 | if (sk->sk_state == TCP_ESTABLISHED) | 857 | if (sk->sk_state == TCP_ESTABLISHED) |
828 | pipe_grant_credits(sk); | 858 | pipe_grant_credits(sk); |
829 | release_sock(sk); | 859 | release_sock(sk); |
830 | 860 | copy: | |
831 | msg->msg_flags |= MSG_EOR; | 861 | msg->msg_flags |= MSG_EOR; |
832 | |||
833 | if (skb->len > len) | 862 | if (skb->len > len) |
834 | msg->msg_flags |= MSG_TRUNC; | 863 | msg->msg_flags |= MSG_TRUNC; |
835 | else | 864 | else |