Loading include/net/llc_conn.h +1 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ struct llc_sock { struct llc_addr laddr; /* lsap/mac pair */ struct llc_addr daddr; /* dsap/mac pair */ struct net_device *dev; /* device to send to remote */ u32 copied_seq; /* head of yet unread data */ u8 retry_count; /* number of retries */ u8 ack_must_be_send; u8 first_pdu_Ns; Loading net/llc/af_llc.c +147 −33 Original line number Diff line number Diff line Loading @@ -648,53 +648,167 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) * llc_ui_recvmsg - copy received data to the socket user. * @sock: Socket to copy data from. * @msg: Various user space related information. * @size: Size of user buffer. * @len: Size of user buffer. * @flags: User specified flags. * * Copy received data to the socket user. * Returns non-negative upon success, negative otherwise. */ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) struct msghdr *msg, size_t len, int flags) { struct sock *sk = sock->sk; struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; struct sk_buff *skb; const int nonblock = flags & MSG_DONTWAIT; struct sk_buff *skb = NULL; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); size_t copied = 0; int rc = -ENOMEM; int noblock = flags & MSG_DONTWAIT; u32 peek_seq = 0; u32 *seq; unsigned long used; int target; /* Read at least this many bytes */ long timeo; dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); lock_sock(sk); if (skb_queue_empty(&sk->sk_receive_queue)) { rc = llc_wait_data(sk, sock_rcvtimeo(sk, noblock)); if (rc) copied = -ENOTCONN; if (sk->sk_state == TCP_LISTEN) goto out; timeo = sock_rcvtimeo(sk, nonblock); seq = &llc->copied_seq; if (flags & MSG_PEEK) { peek_seq = llc->copied_seq; seq = &peek_seq; } skb = skb_dequeue(&sk->sk_receive_queue); if (!skb) /* shutdown */ goto out; copied = skb->len; if (copied > size) copied = size; rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (rc) goto dgram_free; if (skb->len > copied) { skb_pull(skb, copied); skb_queue_head(&sk->sk_receive_queue, skb); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); copied = 0; do { u32 offset; /* * We need to check signals first, to get correct SIGURG * handling. FIXME: Need to check this doesn't impact 1003.1g * and move it down to the bottom of the loop */ if (signal_pending(current)) { if (copied) break; copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; break; } if (uaddr) memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); if (!skb->next) { dgram_free: kfree_skb(skb); /* Next get a buffer. */ skb = skb_peek(&sk->sk_receive_queue); if (skb) { offset = *seq; goto found_ok_skb; } /* Well, if we have backlog, try to process it now yet. */ if (copied >= target && !sk->sk_backlog.tail) break; if (copied) { if (sk->sk_err || sk->sk_state == TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || (flags & MSG_PEEK)) break; } else { if (sock_flag(sk, SOCK_DONE)) break; if (sk->sk_err) { copied = sock_error(sk); break; } if (sk->sk_shutdown & RCV_SHUTDOWN) break; if (sk->sk_state == TCP_CLOSE) { if (!sock_flag(sk, SOCK_DONE)) { /* * This occurs when user tries to read * from never connected socket. */ copied = -ENOTCONN; break; } break; } if (!timeo) { copied = -EAGAIN; break; } } if (copied >= target) { /* Do not sleep, just process backlog. */ release_sock(sk); lock_sock(sk); } else sk_wait_data(sk, &timeo); if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) { if (net_ratelimit()) printk(KERN_DEBUG "LLC(%s:%d): Application " "bug, race in MSG_PEEK.\n", current->comm, current->pid); peek_seq = llc->copied_seq; } continue; found_ok_skb: /* Ok so how much can we use? */ used = skb->len - offset; if (len < used) used = len; if (!(flags & MSG_TRUNC)) { int rc = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used); if (rc) { /* Exception. Bailout! */ if (!copied) copied = -EFAULT; break; } } *seq += used; copied += used; len -= used; if (used + offset < skb->len) continue; if (!(flags & MSG_PEEK)) { sk_eat_skb(sk, skb); *seq = 0; } } while (len > 0); /* * According to UNIX98, msg_name/msg_namelen are ignored * on connected socket. -ANK * But... af_llc still doesn't have separate sets of methods for * SOCK_DGRAM and SOCK_STREAM :-( So we have to do this test, will * eventually fix this tho :-) -acme */ if (sk->sk_type == SOCK_DGRAM) goto copy_uaddr; out: release_sock(sk); return rc ? : copied; return copied; copy_uaddr: if (uaddr != NULL && skb != NULL) { memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); } goto out; } /** Loading net/llc/llc_conn.c +1 −1 Original line number Diff line number Diff line Loading @@ -120,8 +120,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) sk->sk_socket->state = SS_UNCONNECTED; sk->sk_state = TCP_CLOSE; if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); sock_set_flag(sk, SOCK_DEAD); sk->sk_state_change(sk); } } kfree_skb(skb); Loading net/llc/llc_proc.c +1 −1 Original line number Diff line number Diff line Loading @@ -134,7 +134,7 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v) llc_ui_format_mac(seq, llc->daddr.mac); seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, atomic_read(&sk->sk_wmem_alloc), atomic_read(&sk->sk_rmem_alloc), atomic_read(&sk->sk_rmem_alloc) - llc->copied_seq, sk->sk_state, sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1, llc->link); Loading net/llc/llc_sap.c +4 −1 Original line number Diff line number Diff line Loading @@ -49,9 +49,12 @@ struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev) void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) { struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sockaddr_llc *addr; if (skb->sk->sk_type == SOCK_STREAM) /* See UNIX98 */ return; /* save primitive for use by the user. */ addr = llc_ui_skb_cb(skb); addr->sllc_family = sk->sk_family; addr->sllc_arphrd = skb->dev->type; addr->sllc_test = prim == LLC_TEST_PRIM; Loading Loading
include/net/llc_conn.h +1 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ struct llc_sock { struct llc_addr laddr; /* lsap/mac pair */ struct llc_addr daddr; /* dsap/mac pair */ struct net_device *dev; /* device to send to remote */ u32 copied_seq; /* head of yet unread data */ u8 retry_count; /* number of retries */ u8 ack_must_be_send; u8 first_pdu_Ns; Loading
net/llc/af_llc.c +147 −33 Original line number Diff line number Diff line Loading @@ -648,53 +648,167 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) * llc_ui_recvmsg - copy received data to the socket user. * @sock: Socket to copy data from. * @msg: Various user space related information. * @size: Size of user buffer. * @len: Size of user buffer. * @flags: User specified flags. * * Copy received data to the socket user. * Returns non-negative upon success, negative otherwise. */ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) struct msghdr *msg, size_t len, int flags) { struct sock *sk = sock->sk; struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; struct sk_buff *skb; const int nonblock = flags & MSG_DONTWAIT; struct sk_buff *skb = NULL; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); size_t copied = 0; int rc = -ENOMEM; int noblock = flags & MSG_DONTWAIT; u32 peek_seq = 0; u32 *seq; unsigned long used; int target; /* Read at least this many bytes */ long timeo; dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); lock_sock(sk); if (skb_queue_empty(&sk->sk_receive_queue)) { rc = llc_wait_data(sk, sock_rcvtimeo(sk, noblock)); if (rc) copied = -ENOTCONN; if (sk->sk_state == TCP_LISTEN) goto out; timeo = sock_rcvtimeo(sk, nonblock); seq = &llc->copied_seq; if (flags & MSG_PEEK) { peek_seq = llc->copied_seq; seq = &peek_seq; } skb = skb_dequeue(&sk->sk_receive_queue); if (!skb) /* shutdown */ goto out; copied = skb->len; if (copied > size) copied = size; rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (rc) goto dgram_free; if (skb->len > copied) { skb_pull(skb, copied); skb_queue_head(&sk->sk_receive_queue, skb); target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); copied = 0; do { u32 offset; /* * We need to check signals first, to get correct SIGURG * handling. FIXME: Need to check this doesn't impact 1003.1g * and move it down to the bottom of the loop */ if (signal_pending(current)) { if (copied) break; copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; break; } if (uaddr) memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); if (!skb->next) { dgram_free: kfree_skb(skb); /* Next get a buffer. */ skb = skb_peek(&sk->sk_receive_queue); if (skb) { offset = *seq; goto found_ok_skb; } /* Well, if we have backlog, try to process it now yet. */ if (copied >= target && !sk->sk_backlog.tail) break; if (copied) { if (sk->sk_err || sk->sk_state == TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || (flags & MSG_PEEK)) break; } else { if (sock_flag(sk, SOCK_DONE)) break; if (sk->sk_err) { copied = sock_error(sk); break; } if (sk->sk_shutdown & RCV_SHUTDOWN) break; if (sk->sk_state == TCP_CLOSE) { if (!sock_flag(sk, SOCK_DONE)) { /* * This occurs when user tries to read * from never connected socket. */ copied = -ENOTCONN; break; } break; } if (!timeo) { copied = -EAGAIN; break; } } if (copied >= target) { /* Do not sleep, just process backlog. */ release_sock(sk); lock_sock(sk); } else sk_wait_data(sk, &timeo); if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) { if (net_ratelimit()) printk(KERN_DEBUG "LLC(%s:%d): Application " "bug, race in MSG_PEEK.\n", current->comm, current->pid); peek_seq = llc->copied_seq; } continue; found_ok_skb: /* Ok so how much can we use? */ used = skb->len - offset; if (len < used) used = len; if (!(flags & MSG_TRUNC)) { int rc = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, used); if (rc) { /* Exception. Bailout! */ if (!copied) copied = -EFAULT; break; } } *seq += used; copied += used; len -= used; if (used + offset < skb->len) continue; if (!(flags & MSG_PEEK)) { sk_eat_skb(sk, skb); *seq = 0; } } while (len > 0); /* * According to UNIX98, msg_name/msg_namelen are ignored * on connected socket. -ANK * But... af_llc still doesn't have separate sets of methods for * SOCK_DGRAM and SOCK_STREAM :-( So we have to do this test, will * eventually fix this tho :-) -acme */ if (sk->sk_type == SOCK_DGRAM) goto copy_uaddr; out: release_sock(sk); return rc ? : copied; return copied; copy_uaddr: if (uaddr != NULL && skb != NULL) { memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); } goto out; } /** Loading
net/llc/llc_conn.c +1 −1 Original line number Diff line number Diff line Loading @@ -120,8 +120,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) sk->sk_socket->state = SS_UNCONNECTED; sk->sk_state = TCP_CLOSE; if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); sock_set_flag(sk, SOCK_DEAD); sk->sk_state_change(sk); } } kfree_skb(skb); Loading
net/llc/llc_proc.c +1 −1 Original line number Diff line number Diff line Loading @@ -134,7 +134,7 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v) llc_ui_format_mac(seq, llc->daddr.mac); seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->daddr.lsap, atomic_read(&sk->sk_wmem_alloc), atomic_read(&sk->sk_rmem_alloc), atomic_read(&sk->sk_rmem_alloc) - llc->copied_seq, sk->sk_state, sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1, llc->link); Loading
net/llc/llc_sap.c +4 −1 Original line number Diff line number Diff line Loading @@ -49,9 +49,12 @@ struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev) void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) { struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sockaddr_llc *addr; if (skb->sk->sk_type == SOCK_STREAM) /* See UNIX98 */ return; /* save primitive for use by the user. */ addr = llc_ui_skb_cb(skb); addr->sllc_family = sk->sk_family; addr->sllc_arphrd = skb->dev->type; addr->sllc_test = prim == LLC_TEST_PRIM; Loading