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)) {
}
if (pn->rx_credits == 0) {
+ atomic_inc(&sk->sk_drops);
err = -ENOBUFS;
break;
}
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;
return -EINVAL;
peer_type = (peer_type & 0xff00) | data[0];
break;
+ case PN_PIPE_SB_ALIGNED_DATA:
+ aligned = data[0] != 0;
+ break;
}
n_sb--;
}
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);
{
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;
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;
}
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;
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);
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)) {
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;
}
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);
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;
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;
/* 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,