/** * llc_ui_accept - accept a new incoming connection. * @sock: Socket which connections arrive on. * @newsock: Socket to move incoming connection to. * @flags: User specified operational flags. * * Accept a new incoming connection. * Returns 0 upon success, negative otherwise. */ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) { struct sock *sk = sock->sk, *newsk; struct llc_opt *llc, *newllc; struct sk_buff *skb; int rc = -EOPNOTSUPP; dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->laddr.lsap); lock_sock(sk); if (sk->sk_type != SOCK_STREAM) goto out; rc = -EINVAL; if (sock->state != SS_UNCONNECTED || sk->sk_state != TCP_LISTEN) goto out; /* wait for a connection to arrive. */ rc = llc_ui_wait_for_data(sk, sk->sk_rcvtimeo); if (rc) goto out; dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->laddr.lsap); skb = skb_dequeue(&sk->sk_receive_queue); rc = -EINVAL; if (!skb->sk) goto frees; rc = 0; newsk = skb->sk; /* attach connection to a new socket. */ llc_ui_sk_init(newsock, newsk); newsk->sk_pair = NULL; newsk->sk_zapped = 0; newsk->sk_state = TCP_ESTABLISHED; newsock->state = SS_CONNECTED; llc = llc_sk(sk); newllc = llc_sk(newsk); memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr)); newllc->link = llc_ui_next_link_no(newllc->laddr.lsap); /* put original socket back into a clean listen state. */ sk->sk_state = TCP_LISTEN; sk->sk_ack_backlog--; skb->sk = NULL; dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap); frees: kfree_skb(skb); out: release_sock(sk); return rc; }
/** * 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. * @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 sock *sk = sock->sk; struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; struct sk_buff *skb; size_t copied = 0; int rc = -ENOMEM, timeout; int noblock = flags & MSG_DONTWAIT; dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); lock_sock(sk); timeout = sock_rcvtimeo(sk, noblock); rc = llc_ui_wait_for_data(sk, timeout); if (rc) { dprintk("%s: llc_ui_wait_for_data failed recv " "in %02X from %02X\n", __FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); goto out; } 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); } if (uaddr) memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); if (!skb->list) { dgram_free: kfree_skb(skb); } out: release_sock(sk); return rc ? : copied; }