aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/af_llc.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@mandriva.com>2005-09-22 07:29:08 -0400
committerArnaldo Carvalho de Melo <acme@mandriva.com>2005-09-22 07:29:08 -0400
commit8420e1b541fe92aee1d8d4d25d9e33eaca756a7b (patch)
treec427c8cfe59bfae22eac2dc4c325aa947f7cb0eb /net/llc/af_llc.c
parentd389424e00f9097cd24b3df4ca0ab7221f140eeb (diff)
[LLC]: fix llc_ui_recvmsg, making it behave like tcp_recvmsg
In fact it is an exact copy of the parts that makes sense to LLC :-) Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/llc/af_llc.c')
-rw-r--r--net/llc/af_llc.c180
1 files changed, 147 insertions, 33 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 7aa51eb79b13..59d02cbbeb9e 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -648,53 +648,167 @@ out:
648 * llc_ui_recvmsg - copy received data to the socket user. 648 * llc_ui_recvmsg - copy received data to the socket user.
649 * @sock: Socket to copy data from. 649 * @sock: Socket to copy data from.
650 * @msg: Various user space related information. 650 * @msg: Various user space related information.
651 * @size: Size of user buffer. 651 * @len: Size of user buffer.
652 * @flags: User specified flags. 652 * @flags: User specified flags.
653 * 653 *
654 * Copy received data to the socket user. 654 * Copy received data to the socket user.
655 * Returns non-negative upon success, negative otherwise. 655 * Returns non-negative upon success, negative otherwise.
656 */ 656 */
657static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, 657static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
658 struct msghdr *msg, size_t size, int flags) 658 struct msghdr *msg, size_t len, int flags)
659{ 659{
660 struct sock *sk = sock->sk;
661 struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; 660 struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
662 struct sk_buff *skb; 661 const int nonblock = flags & MSG_DONTWAIT;
662 struct sk_buff *skb = NULL;
663 struct sock *sk = sock->sk;
664 struct llc_sock *llc = llc_sk(sk);
663 size_t copied = 0; 665 size_t copied = 0;
664 int rc = -ENOMEM; 666 u32 peek_seq = 0;
665 int noblock = flags & MSG_DONTWAIT; 667 u32 *seq;
668 unsigned long used;
669 int target; /* Read at least this many bytes */
670 long timeo;
666 671
667 dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,
668 llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
669 lock_sock(sk); 672 lock_sock(sk);
670 if (skb_queue_empty(&sk->sk_receive_queue)) { 673 copied = -ENOTCONN;
671 rc = llc_wait_data(sk, sock_rcvtimeo(sk, noblock)); 674 if (sk->sk_state == TCP_LISTEN)
672 if (rc)
673 goto out;
674 }
675 skb = skb_dequeue(&sk->sk_receive_queue);
676 if (!skb) /* shutdown */
677 goto out; 675 goto out;
678 copied = skb->len; 676
679 if (copied > size) 677 timeo = sock_rcvtimeo(sk, nonblock);
680 copied = size; 678
681 rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 679 seq = &llc->copied_seq;
682 if (rc) 680 if (flags & MSG_PEEK) {
683 goto dgram_free; 681 peek_seq = llc->copied_seq;
684 if (skb->len > copied) { 682 seq = &peek_seq;
685 skb_pull(skb, copied); 683 }
686 skb_queue_head(&sk->sk_receive_queue, skb); 684
687 } 685 target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
688 if (uaddr) 686 copied = 0;
689 memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); 687
690 msg->msg_namelen = sizeof(*uaddr); 688 do {
691 if (!skb->next) { 689 u32 offset;
692dgram_free: 690
693 kfree_skb(skb); 691 /*
694 } 692 * We need to check signals first, to get correct SIGURG
693 * handling. FIXME: Need to check this doesn't impact 1003.1g
694 * and move it down to the bottom of the loop
695 */
696 if (signal_pending(current)) {
697 if (copied)
698 break;
699 copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
700 break;
701 }
702
703 /* Next get a buffer. */
704
705 skb = skb_peek(&sk->sk_receive_queue);
706 if (skb) {
707 offset = *seq;
708 goto found_ok_skb;
709 }
710 /* Well, if we have backlog, try to process it now yet. */
711
712 if (copied >= target && !sk->sk_backlog.tail)
713 break;
714
715 if (copied) {
716 if (sk->sk_err ||
717 sk->sk_state == TCP_CLOSE ||
718 (sk->sk_shutdown & RCV_SHUTDOWN) ||
719 !timeo ||
720 (flags & MSG_PEEK))
721 break;
722 } else {
723 if (sock_flag(sk, SOCK_DONE))
724 break;
725
726 if (sk->sk_err) {
727 copied = sock_error(sk);
728 break;
729 }
730 if (sk->sk_shutdown & RCV_SHUTDOWN)
731 break;
732
733 if (sk->sk_state == TCP_CLOSE) {
734 if (!sock_flag(sk, SOCK_DONE)) {
735 /*
736 * This occurs when user tries to read
737 * from never connected socket.
738 */
739 copied = -ENOTCONN;
740 break;
741 }
742 break;
743 }
744 if (!timeo) {
745 copied = -EAGAIN;
746 break;
747 }
748 }
749
750 if (copied >= target) { /* Do not sleep, just process backlog. */
751 release_sock(sk);
752 lock_sock(sk);
753 } else
754 sk_wait_data(sk, &timeo);
755
756 if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) {
757 if (net_ratelimit())
758 printk(KERN_DEBUG "LLC(%s:%d): Application "
759 "bug, race in MSG_PEEK.\n",
760 current->comm, current->pid);
761 peek_seq = llc->copied_seq;
762 }
763 continue;
764 found_ok_skb:
765 /* Ok so how much can we use? */
766 used = skb->len - offset;
767 if (len < used)
768 used = len;
769
770 if (!(flags & MSG_TRUNC)) {
771 int rc = skb_copy_datagram_iovec(skb, offset,
772 msg->msg_iov, used);
773 if (rc) {
774 /* Exception. Bailout! */
775 if (!copied)
776 copied = -EFAULT;
777 break;
778 }
779 }
780
781 *seq += used;
782 copied += used;
783 len -= used;
784
785 if (used + offset < skb->len)
786 continue;
787
788 if (!(flags & MSG_PEEK)) {
789 sk_eat_skb(sk, skb);
790 *seq = 0;
791 }
792 } while (len > 0);
793
794 /*
795 * According to UNIX98, msg_name/msg_namelen are ignored
796 * on connected socket. -ANK
797 * But... af_llc still doesn't have separate sets of methods for
798 * SOCK_DGRAM and SOCK_STREAM :-( So we have to do this test, will
799 * eventually fix this tho :-) -acme
800 */
801 if (sk->sk_type == SOCK_DGRAM)
802 goto copy_uaddr;
695out: 803out:
696 release_sock(sk); 804 release_sock(sk);
697 return rc ? : copied; 805 return copied;
806copy_uaddr:
807 if (uaddr != NULL && skb != NULL) {
808 memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
809 msg->msg_namelen = sizeof(*uaddr);
810 }
811 goto out;
698} 812}
699 813
700/** 814/**