aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/llc_conn.h1
-rw-r--r--net/llc/af_llc.c180
-rw-r--r--net/llc/llc_conn.c2
-rw-r--r--net/llc/llc_proc.c2
-rw-r--r--net/llc/llc_sap.c5
5 files changed, 154 insertions, 36 deletions
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
index e44f494bbef1..54852ff6033b 100644
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -38,6 +38,7 @@ struct llc_sock {
38 struct llc_addr laddr; /* lsap/mac pair */ 38 struct llc_addr laddr; /* lsap/mac pair */
39 struct llc_addr daddr; /* dsap/mac pair */ 39 struct llc_addr daddr; /* dsap/mac pair */
40 struct net_device *dev; /* device to send to remote */ 40 struct net_device *dev; /* device to send to remote */
41 u32 copied_seq; /* head of yet unread data */
41 u8 retry_count; /* number of retries */ 42 u8 retry_count; /* number of retries */
42 u8 ack_must_be_send; 43 u8 ack_must_be_send;
43 u8 first_pdu_Ns; 44 u8 first_pdu_Ns;
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/**
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index e10ce5adb104..042b24a8ca4c 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -120,8 +120,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
120 sk->sk_socket->state = SS_UNCONNECTED; 120 sk->sk_socket->state = SS_UNCONNECTED;
121 sk->sk_state = TCP_CLOSE; 121 sk->sk_state = TCP_CLOSE;
122 if (!sock_flag(sk, SOCK_DEAD)) { 122 if (!sock_flag(sk, SOCK_DEAD)) {
123 sk->sk_state_change(sk);
124 sock_set_flag(sk, SOCK_DEAD); 123 sock_set_flag(sk, SOCK_DEAD);
124 sk->sk_state_change(sk);
125 } 125 }
126 } 126 }
127 kfree_skb(skb); 127 kfree_skb(skb);
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index 36e8db3fa1a2..bd531cb235a7 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -134,7 +134,7 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v)
134 llc_ui_format_mac(seq, llc->daddr.mac); 134 llc_ui_format_mac(seq, llc->daddr.mac);
135 seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, 135 seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap,
136 atomic_read(&sk->sk_wmem_alloc), 136 atomic_read(&sk->sk_wmem_alloc),
137 atomic_read(&sk->sk_rmem_alloc), 137 atomic_read(&sk->sk_rmem_alloc) - llc->copied_seq,
138 sk->sk_state, 138 sk->sk_state,
139 sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1, 139 sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1,
140 llc->link); 140 llc->link);
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index e6d538937f93..4029ceee9b91 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -49,9 +49,12 @@ struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev)
49 49
50void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) 50void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim)
51{ 51{
52 struct sockaddr_llc *addr = llc_ui_skb_cb(skb); 52 struct sockaddr_llc *addr;
53 53
54 if (skb->sk->sk_type == SOCK_STREAM) /* See UNIX98 */
55 return;
54 /* save primitive for use by the user. */ 56 /* save primitive for use by the user. */
57 addr = llc_ui_skb_cb(skb);
55 addr->sllc_family = sk->sk_family; 58 addr->sllc_family = sk->sk_family;
56 addr->sllc_arphrd = skb->dev->type; 59 addr->sllc_arphrd = skb->dev->type;
57 addr->sllc_test = prim == LLC_TEST_PRIM; 60 addr->sllc_test = prim == LLC_TEST_PRIM;