ethtool: reduce stack usage
[safe/jmp/linux-2.6] / net / phonet / pep.c
index bb3e678..360cf37 100644 (file)
@@ -346,12 +346,17 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                break;
 
        case PNS_PEP_CTRL_REQ:
-               if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX)
+               if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
+                       atomic_inc(&sk->sk_drops);
                        break;
+               }
                __skb_pull(skb, 4);
                queue = &pn->ctrlreq_queue;
                goto queue;
 
+       case PNS_PIPE_ALIGNED_DATA:
+               __skb_pull(skb, 1);
+               /* fall through */
        case PNS_PIPE_DATA:
                __skb_pull(skb, 3); /* Pipe data header */
                if (!pn_flow_safe(pn->rx_fc)) {
@@ -362,6 +367,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
                }
 
                if (pn->rx_credits == 0) {
+                       atomic_inc(&sk->sk_drops);
                        err = -ENOBUFS;
                        break;
                }
@@ -438,6 +444,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
        struct sockaddr_pn dst;
        u16 peer_type;
        u8 pipe_handle, enabled, n_sb;
+       u8 aligned = 0;
 
        if (!pskb_pull(skb, sizeof(*hdr) + 4))
                return -EINVAL;
@@ -476,6 +483,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
                                return -EINVAL;
                        peer_type = (peer_type & 0xff00) | data[0];
                        break;
+               case PN_PIPE_SB_ALIGNED_DATA:
+                       aligned = data[0] != 0;
+                       break;
                }
                n_sb--;
        }
@@ -507,6 +517,7 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
        newpn->rx_credits = 0;
        newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
        newpn->init_enable = enabled;
+       newpn->aligned = aligned;
 
        BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
        skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -553,7 +564,7 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct pep_sock *pn = pep_sk(sk);
        struct sock *sknode;
-       struct pnpipehdr *hdr = pnp_hdr(skb);
+       struct pnpipehdr *hdr;
        struct sockaddr_pn dst;
        int err = NET_RX_SUCCESS;
        u8 pipe_handle;
@@ -711,8 +722,8 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
                        return -EINVAL;
 
                lock_sock(sk);
-               if (sock_flag(sk, SOCK_URGINLINE)
-                && !skb_queue_empty(&pn->ctrlreq_queue))
+               if (sock_flag(sk, SOCK_URGINLINE) &&
+                   !skb_queue_empty(&pn->ctrlreq_queue))
                        answ = skb_peek(&pn->ctrlreq_queue)->len;
                else if (!skb_queue_empty(&sk->sk_receive_queue))
                        answ = skb_peek(&sk->sk_receive_queue)->len;
@@ -737,7 +748,7 @@ static int pep_init(struct sock *sk)
 }
 
 static int pep_setsockopt(struct sock *sk, int level, int optname,
-                               char __user *optval, int optlen)
+                               char __user *optval, unsigned int optlen)
 {
        struct pep_sock *pn = pep_sk(sk);
        int val = 0, err = 0;
@@ -826,11 +837,15 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
                return -ENOBUFS;
        }
 
-       skb_push(skb, 3);
+       skb_push(skb, 3 + pn->aligned);
        skb_reset_transport_header(skb);
        ph = pnp_hdr(skb);
        ph->utid = 0;
-       ph->message_id = PNS_PIPE_DATA;
+       if (pn->aligned) {
+               ph->message_id = PNS_PIPE_ALIGNED_DATA;
+               ph->data[0] = 0; /* padding */
+       } else
+               ph->message_id = PNS_PIPE_DATA;
        ph->pipe_handle = pn->pipe_handle;
 
        return pn_skb_send(sk, skb, &pipe_srv);
@@ -840,14 +855,26 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
                        struct msghdr *msg, size_t len)
 {
        struct pep_sock *pn = pep_sk(sk);
-       struct sk_buff *skb = NULL;
+       struct sk_buff *skb;
        long timeo;
        int flags = msg->msg_flags;
        int err, done;
 
-       if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR))
+       if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|
+                               MSG_CMSG_COMPAT)) ||
+                       !(msg->msg_flags & MSG_EOR))
                return -EOPNOTSUPP;
 
+       skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
+                                       flags & MSG_DONTWAIT, &err);
+       if (!skb)
+               return -ENOBUFS;
+
+       skb_reserve(skb, MAX_PHONET_HEADER + 3);
+       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+       if (err < 0)
+               goto outfree;
+
        lock_sock(sk);
        timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
        if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) {
@@ -891,28 +918,13 @@ disabled:
                        goto disabled;
        }
 
-       if (!skb) {
-               skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
-                                               flags & MSG_DONTWAIT, &err);
-               if (skb == NULL)
-                       goto out;
-               skb_reserve(skb, MAX_PHONET_HEADER + 3);
-
-               if (sk->sk_state != TCP_ESTABLISHED ||
-                   !atomic_read(&pn->tx_credits))
-                       goto disabled; /* sock_alloc_send_skb might sleep */
-       }
-
-       err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
-       if (err < 0)
-               goto out;
-
        err = pipe_skb_send(sk, skb);
        if (err >= 0)
                err = len; /* success! */
        skb = NULL;
 out:
        release_sock(sk);
+outfree:
        kfree_skb(skb);
        return err;
 }
@@ -929,6 +941,9 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
        struct sk_buff *rskb, *fs;
        int flen = 0;
 
+       if (pep_sk(sk)->aligned)
+               return pipe_skb_send(sk, skb);
+
        rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
        if (!rskb) {
                kfree_skb(skb);
@@ -940,10 +955,10 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
        rskb->truesize += rskb->len;
 
        /* Avoid nested fragments */
-       for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
+       skb_walk_frags(skb, fs)
                flen += fs->len;
        skb->next = skb_shinfo(skb)->frag_list;
-       skb_shinfo(skb)->frag_list = NULL;
+       skb_frag_list_init(skb);
        skb->len -= flen;
        skb->data_len -= flen;
        skb->truesize -= flen;
@@ -968,6 +983,10 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
        struct sk_buff *skb;
        int err;
 
+       if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL|
+                       MSG_NOSIGNAL|MSG_CMSG_COMPAT))
+               return -EOPNOTSUPP;
+
        if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE)))
                return -ENOTCONN;
 
@@ -975,6 +994,8 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
                /* Dequeue and acknowledge control request */
                struct pep_sock *pn = pep_sk(sk);
 
+               if (flags & MSG_PEEK)
+                       return -EOPNOTSUPP;
                skb = skb_dequeue(&pn->ctrlreq_queue);
                if (skb) {
                        pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR,