Phonet: implement GPRS virtual interface over PEP socket
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c41bd97f81
commit
02a47617cd
|
@ -31,9 +31,17 @@
|
|||
#define PN_PROTO_PIPE 2
|
||||
#define PHONET_NPROTO 3
|
||||
|
||||
/* Socket options for SOL_PNPIPE level */
|
||||
#define PNPIPE_ENCAP 1
|
||||
#define PNPIPE_IFINDEX 2
|
||||
|
||||
#define PNADDR_ANY 0
|
||||
#define PNPORT_RESOURCE_ROUTING 0
|
||||
|
||||
/* Values for PNPIPE_ENCAP option */
|
||||
#define PNPIPE_ENCAP_NONE 0
|
||||
#define PNPIPE_ENCAP_IP 1
|
||||
|
||||
/* ioctls */
|
||||
#define SIOCPNGETOBJECT (SIOCPROTOPRIVATE + 0)
|
||||
|
||||
|
|
|
@ -297,6 +297,7 @@ struct ucred {
|
|||
#define SOL_RXRPC 272
|
||||
#define SOL_PPPOL2TP 273
|
||||
#define SOL_BLUETOOTH 274
|
||||
#define SOL_PNPIPE 275
|
||||
|
||||
/* IPX options */
|
||||
#define IPX_TYPE 1
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* File: pep_gprs.h
|
||||
*
|
||||
* GPRS over Phonet pipe end point socket
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation.
|
||||
*
|
||||
* Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef NET_PHONET_GPRS_H
|
||||
#define NET_PHONET_GPRS_H
|
||||
|
||||
struct sock;
|
||||
struct sk_buff;
|
||||
|
||||
int pep_writeable(struct sock *sk);
|
||||
int pep_write(struct sock *sk, struct sk_buff *skb);
|
||||
struct sk_buff *pep_read(struct sock *sk);
|
||||
|
||||
int gprs_attach(struct sock *sk);
|
||||
void gprs_detach(struct sock *sk);
|
||||
|
||||
#endif
|
|
@ -35,6 +35,7 @@ struct pep_sock {
|
|||
struct sock *listener;
|
||||
struct sk_buff_head ctrlreq_queue;
|
||||
#define PNPIPE_CTRLREQ_MAX 10
|
||||
int ifindex;
|
||||
u16 peer_type; /* peer type/subtype */
|
||||
u8 pipe_handle;
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@ phonet-objs := \
|
|||
sysctl.o \
|
||||
af_phonet.o
|
||||
|
||||
pn_pep-objs := pep.o
|
||||
pn_pep-objs := pep.o pep-gprs.o
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* File: pep-gprs.c
|
||||
*
|
||||
* GPRS over Phonet pipe end point socket
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation.
|
||||
*
|
||||
* Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/if_phonet.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <net/phonet/gprs.h>
|
||||
|
||||
#define GPRS_DEFAULT_MTU 1400
|
||||
|
||||
struct gprs_dev {
|
||||
struct sock *sk;
|
||||
void (*old_state_change)(struct sock *);
|
||||
void (*old_data_ready)(struct sock *, int);
|
||||
void (*old_write_space)(struct sock *);
|
||||
|
||||
struct net_device *net;
|
||||
struct net_device_stats stats;
|
||||
|
||||
struct sk_buff_head tx_queue;
|
||||
struct work_struct tx_work;
|
||||
spinlock_t tx_lock;
|
||||
unsigned tx_max;
|
||||
};
|
||||
|
||||
static int gprs_type_trans(struct sk_buff *skb)
|
||||
{
|
||||
const u8 *pvfc;
|
||||
u8 buf;
|
||||
|
||||
pvfc = skb_header_pointer(skb, 0, 1, &buf);
|
||||
if (!pvfc)
|
||||
return 0;
|
||||
/* Look at IP version field */
|
||||
switch (*pvfc >> 4) {
|
||||
case 4:
|
||||
return htons(ETH_P_IP);
|
||||
case 6:
|
||||
return htons(ETH_P_IPV6);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket callbacks
|
||||
*/
|
||||
|
||||
static void gprs_state_change(struct sock *sk)
|
||||
{
|
||||
struct gprs_dev *dev = sk->sk_user_data;
|
||||
|
||||
if (sk->sk_state == TCP_CLOSE_WAIT) {
|
||||
netif_stop_queue(dev->net);
|
||||
netif_carrier_off(dev->net);
|
||||
}
|
||||
}
|
||||
|
||||
static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
int err = 0;
|
||||
u16 protocol = gprs_type_trans(skb);
|
||||
|
||||
if (!protocol) {
|
||||
err = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (likely(skb_headroom(skb) & 3)) {
|
||||
struct sk_buff *rskb, *fs;
|
||||
int flen = 0;
|
||||
|
||||
/* Phonet Pipe data header is misaligned (3 bytes),
|
||||
* so wrap the IP packet as a single fragment of an head-less
|
||||
* socket buffer. The network stack will pull what it needs,
|
||||
* but at least, the whole IP payload is not memcpy'd. */
|
||||
rskb = netdev_alloc_skb(dev->net, 0);
|
||||
if (!rskb) {
|
||||
err = -ENOBUFS;
|
||||
goto drop;
|
||||
}
|
||||
skb_shinfo(rskb)->frag_list = skb;
|
||||
rskb->len += skb->len;
|
||||
rskb->data_len += rskb->len;
|
||||
rskb->truesize += rskb->len;
|
||||
|
||||
/* Avoid nested fragments */
|
||||
for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
|
||||
flen += fs->len;
|
||||
skb->next = skb_shinfo(skb)->frag_list;
|
||||
skb_shinfo(skb)->frag_list = NULL;
|
||||
skb->len -= flen;
|
||||
skb->data_len -= flen;
|
||||
skb->truesize -= flen;
|
||||
|
||||
skb = rskb;
|
||||
}
|
||||
|
||||
skb->protocol = protocol;
|
||||
skb_reset_mac_header(skb);
|
||||
skb->dev = dev->net;
|
||||
|
||||
if (likely(dev->net->flags & IFF_UP)) {
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += skb->len;
|
||||
netif_rx(skb);
|
||||
skb = NULL;
|
||||
} else
|
||||
err = -ENODEV;
|
||||
|
||||
drop:
|
||||
if (skb) {
|
||||
dev_kfree_skb(skb);
|
||||
dev->stats.rx_dropped++;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void gprs_data_ready(struct sock *sk, int len)
|
||||
{
|
||||
struct gprs_dev *dev = sk->sk_user_data;
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = pep_read(sk)) != NULL) {
|
||||
skb_orphan(skb);
|
||||
gprs_recv(dev, skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void gprs_write_space(struct sock *sk)
|
||||
{
|
||||
struct gprs_dev *dev = sk->sk_user_data;
|
||||
unsigned credits = pep_writeable(sk);
|
||||
|
||||
spin_lock_bh(&dev->tx_lock);
|
||||
dev->tx_max = credits;
|
||||
if (credits > skb_queue_len(&dev->tx_queue))
|
||||
netif_wake_queue(dev->net);
|
||||
spin_unlock_bh(&dev->tx_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Network device callbacks
|
||||
*/
|
||||
|
||||
static int gprs_xmit(struct sk_buff *skb, struct net_device *net)
|
||||
{
|
||||
struct gprs_dev *dev = netdev_priv(net);
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
case htons(ETH_P_IPV6):
|
||||
break;
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&dev->tx_lock);
|
||||
if (likely(skb_queue_len(&dev->tx_queue) < dev->tx_max)) {
|
||||
skb_queue_tail(&dev->tx_queue, skb);
|
||||
skb = NULL;
|
||||
}
|
||||
if (skb_queue_len(&dev->tx_queue) >= dev->tx_max)
|
||||
netif_stop_queue(net);
|
||||
spin_unlock(&dev->tx_lock);
|
||||
|
||||
schedule_work(&dev->tx_work);
|
||||
if (unlikely(skb))
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gprs_tx(struct work_struct *work)
|
||||
{
|
||||
struct gprs_dev *dev = container_of(work, struct gprs_dev, tx_work);
|
||||
struct sock *sk = dev->sk;
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = skb_dequeue(&dev->tx_queue)) != NULL) {
|
||||
int err;
|
||||
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
dev->stats.tx_packets++;
|
||||
|
||||
skb_orphan(skb);
|
||||
skb_set_owner_w(skb, sk);
|
||||
|
||||
lock_sock(sk);
|
||||
err = pep_write(sk, skb);
|
||||
if (err) {
|
||||
LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
|
||||
dev->net->name, err);
|
||||
dev->stats.tx_aborted_errors++;
|
||||
dev->stats.tx_errors++;
|
||||
}
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
gprs_write_space(sk);
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
static int gprs_set_mtu(struct net_device *net, int new_mtu)
|
||||
{
|
||||
if ((new_mtu < 576) || (new_mtu > (PHONET_MAX_MTU - 11)))
|
||||
return -EINVAL;
|
||||
|
||||
net->mtu = new_mtu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct net_device_stats *gprs_get_stats(struct net_device *net)
|
||||
{
|
||||
struct gprs_dev *dev = netdev_priv(net);
|
||||
|
||||
return &dev->stats;
|
||||
}
|
||||
|
||||
static void gprs_setup(struct net_device *net)
|
||||
{
|
||||
net->features = NETIF_F_FRAGLIST;
|
||||
net->type = ARPHRD_NONE;
|
||||
net->flags = IFF_POINTOPOINT | IFF_NOARP;
|
||||
net->mtu = GPRS_DEFAULT_MTU;
|
||||
net->hard_header_len = 0;
|
||||
net->addr_len = 0;
|
||||
net->tx_queue_len = 10;
|
||||
|
||||
net->destructor = free_netdev;
|
||||
net->hard_start_xmit = gprs_xmit; /* mandatory */
|
||||
net->change_mtu = gprs_set_mtu;
|
||||
net->get_stats = gprs_get_stats;
|
||||
}
|
||||
|
||||
/*
|
||||
* External interface
|
||||
*/
|
||||
|
||||
/*
|
||||
* Attach a GPRS interface to a datagram socket.
|
||||
* Returns the interface index on success, negative error code on error.
|
||||
*/
|
||||
int gprs_attach(struct sock *sk)
|
||||
{
|
||||
static const char ifname[] = "gprs%d";
|
||||
struct gprs_dev *dev;
|
||||
struct net_device *net;
|
||||
int err;
|
||||
|
||||
if (unlikely(sk->sk_type == SOCK_STREAM))
|
||||
return -EINVAL; /* need packet boundaries */
|
||||
|
||||
/* Create net device */
|
||||
net = alloc_netdev(sizeof(*dev), ifname, gprs_setup);
|
||||
if (!net)
|
||||
return -ENOMEM;
|
||||
dev = netdev_priv(net);
|
||||
dev->net = net;
|
||||
dev->tx_max = 0;
|
||||
spin_lock_init(&dev->tx_lock);
|
||||
skb_queue_head_init(&dev->tx_queue);
|
||||
INIT_WORK(&dev->tx_work, gprs_tx);
|
||||
|
||||
netif_stop_queue(net);
|
||||
err = register_netdev(net);
|
||||
if (err) {
|
||||
free_netdev(net);
|
||||
return err;
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
if (unlikely(sk->sk_user_data)) {
|
||||
err = -EBUSY;
|
||||
goto out_rel;
|
||||
}
|
||||
if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) ||
|
||||
sock_flag(sk, SOCK_DEAD))) {
|
||||
err = -EINVAL;
|
||||
goto out_rel;
|
||||
}
|
||||
sk->sk_user_data = dev;
|
||||
dev->old_state_change = sk->sk_state_change;
|
||||
dev->old_data_ready = sk->sk_data_ready;
|
||||
dev->old_write_space = sk->sk_write_space;
|
||||
sk->sk_state_change = gprs_state_change;
|
||||
sk->sk_data_ready = gprs_data_ready;
|
||||
sk->sk_write_space = gprs_write_space;
|
||||
release_sock(sk);
|
||||
|
||||
sock_hold(sk);
|
||||
dev->sk = sk;
|
||||
|
||||
printk(KERN_DEBUG"%s: attached\n", net->name);
|
||||
gprs_write_space(sk); /* kick off TX */
|
||||
return net->ifindex;
|
||||
|
||||
out_rel:
|
||||
release_sock(sk);
|
||||
unregister_netdev(net);
|
||||
return err;
|
||||
}
|
||||
|
||||
void gprs_detach(struct sock *sk)
|
||||
{
|
||||
struct gprs_dev *dev = sk->sk_user_data;
|
||||
struct net_device *net = dev->net;
|
||||
|
||||
lock_sock(sk);
|
||||
sk->sk_user_data = NULL;
|
||||
sk->sk_state_change = dev->old_state_change;
|
||||
sk->sk_data_ready = dev->old_data_ready;
|
||||
sk->sk_write_space = dev->old_write_space;
|
||||
release_sock(sk);
|
||||
|
||||
printk(KERN_DEBUG"%s: detached\n", net->name);
|
||||
unregister_netdev(net);
|
||||
flush_scheduled_work();
|
||||
sock_put(sk);
|
||||
skb_queue_purge(&dev->tx_queue);
|
||||
}
|
161
net/phonet/pep.c
161
net/phonet/pep.c
|
@ -31,6 +31,7 @@
|
|||
#include <linux/phonet.h>
|
||||
#include <net/phonet/phonet.h>
|
||||
#include <net/phonet/pep.h>
|
||||
#include <net/phonet/gprs.h>
|
||||
|
||||
/* sk_state values:
|
||||
* TCP_CLOSE sock not in use yet
|
||||
|
@ -612,6 +613,7 @@ drop:
|
|||
static void pep_sock_close(struct sock *sk, long timeout)
|
||||
{
|
||||
struct pep_sock *pn = pep_sk(sk);
|
||||
int ifindex = 0;
|
||||
|
||||
sk_common_release(sk);
|
||||
|
||||
|
@ -625,7 +627,12 @@ static void pep_sock_close(struct sock *sk, long timeout)
|
|||
sk_del_node_init(sknode);
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
}
|
||||
ifindex = pn->ifindex;
|
||||
pn->ifindex = 0;
|
||||
release_sock(sk);
|
||||
|
||||
if (ifindex)
|
||||
gprs_detach(sk);
|
||||
}
|
||||
|
||||
static int pep_wait_connreq(struct sock *sk, int noblock)
|
||||
|
@ -730,12 +737,107 @@ static int pep_init(struct sock *sk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pep_setsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int optlen)
|
||||
{
|
||||
struct pep_sock *pn = pep_sk(sk);
|
||||
int val = 0, err = 0;
|
||||
|
||||
if (level != SOL_PNPIPE)
|
||||
return -ENOPROTOOPT;
|
||||
if (optlen >= sizeof(int)) {
|
||||
if (get_user(val, (int __user *) optval))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
switch (optname) {
|
||||
case PNPIPE_ENCAP:
|
||||
if (val && val != PNPIPE_ENCAP_IP) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!pn->ifindex == !val)
|
||||
break; /* Nothing to do! */
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
err = -EPERM;
|
||||
break;
|
||||
}
|
||||
if (val) {
|
||||
release_sock(sk);
|
||||
err = gprs_attach(sk);
|
||||
if (err > 0) {
|
||||
pn->ifindex = err;
|
||||
err = 0;
|
||||
}
|
||||
} else {
|
||||
pn->ifindex = 0;
|
||||
release_sock(sk);
|
||||
gprs_detach(sk);
|
||||
err = 0;
|
||||
}
|
||||
goto out_norel;
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
}
|
||||
release_sock(sk);
|
||||
|
||||
out_norel:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pep_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct pep_sock *pn = pep_sk(sk);
|
||||
int len, val;
|
||||
|
||||
if (level != SOL_PNPIPE)
|
||||
return -ENOPROTOOPT;
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
switch (optname) {
|
||||
case PNPIPE_ENCAP:
|
||||
val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
|
||||
break;
|
||||
case PNPIPE_IFINDEX:
|
||||
val = pn->ifindex;
|
||||
break;
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
||||
len = min_t(unsigned int, sizeof(int), len);
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (put_user(val, (int __user *) optval))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct pep_sock *pn = pep_sk(sk);
|
||||
struct pnpipehdr *ph;
|
||||
|
||||
skb_push(skb, 3);
|
||||
skb_reset_transport_header(skb);
|
||||
ph = pnp_hdr(skb);
|
||||
ph->utid = 0;
|
||||
ph->message_id = PNS_PIPE_DATA;
|
||||
ph->pipe_handle = pn->pipe_handle;
|
||||
if (pn_flow_safe(pn->tx_fc) && pn->tx_credits)
|
||||
pn->tx_credits--;
|
||||
|
||||
return pn_skb_send(sk, skb, &pipe_srv);
|
||||
}
|
||||
|
||||
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 pnpipehdr *ph;
|
||||
long timeo;
|
||||
int flags = msg->msg_flags;
|
||||
int err, done;
|
||||
|
@ -801,16 +903,7 @@ disabled:
|
|||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
__skb_push(skb, 3);
|
||||
skb_reset_transport_header(skb);
|
||||
ph = pnp_hdr(skb);
|
||||
ph->utid = 0;
|
||||
ph->message_id = PNS_PIPE_DATA;
|
||||
ph->pipe_handle = pn->pipe_handle;
|
||||
if (pn_flow_safe(pn->tx_fc)) /* credit-based flow control */
|
||||
pn->tx_credits--;
|
||||
|
||||
err = pn_skb_send(sk, skb, &pipe_srv);
|
||||
err = pipe_skb_send(sk, skb);
|
||||
if (err >= 0)
|
||||
err = len; /* success! */
|
||||
skb = NULL;
|
||||
|
@ -820,6 +913,50 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
int pep_writeable(struct sock *sk)
|
||||
{
|
||||
struct pep_sock *pn = pep_sk(sk);
|
||||
|
||||
return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0;
|
||||
}
|
||||
|
||||
int pep_write(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *rskb, *fs;
|
||||
int flen = 0;
|
||||
|
||||
rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
|
||||
if (!rskb) {
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_shinfo(rskb)->frag_list = skb;
|
||||
rskb->len += skb->len;
|
||||
rskb->data_len += rskb->len;
|
||||
rskb->truesize += rskb->len;
|
||||
|
||||
/* Avoid nested fragments */
|
||||
for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
|
||||
flen += fs->len;
|
||||
skb->next = skb_shinfo(skb)->frag_list;
|
||||
skb_shinfo(skb)->frag_list = NULL;
|
||||
skb->len -= flen;
|
||||
skb->data_len -= flen;
|
||||
skb->truesize -= flen;
|
||||
|
||||
skb_reserve(rskb, MAX_PHONET_HEADER + 3);
|
||||
return pipe_skb_send(sk, rskb);
|
||||
}
|
||||
|
||||
struct sk_buff *pep_read(struct sock *sk)
|
||||
{
|
||||
struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
|
||||
|
||||
if (sk->sk_state == TCP_ESTABLISHED)
|
||||
pipe_grant_credits(sk);
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
|
||||
struct msghdr *msg, size_t len, int noblock,
|
||||
int flags, int *addr_len)
|
||||
|
@ -902,6 +1039,8 @@ static struct proto pep_proto = {
|
|||
.accept = pep_sock_accept,
|
||||
.ioctl = pep_ioctl,
|
||||
.init = pep_init,
|
||||
.setsockopt = pep_setsockopt,
|
||||
.getsockopt = pep_getsockopt,
|
||||
.sendmsg = pep_sendmsg,
|
||||
.recvmsg = pep_recvmsg,
|
||||
.backlog_rcv = pep_do_rcv,
|
||||
|
|
|
@ -342,11 +342,11 @@ const struct proto_ops phonet_stream_ops = {
|
|||
.ioctl = pn_socket_ioctl,
|
||||
.listen = pn_socket_listen,
|
||||
.shutdown = sock_no_shutdown,
|
||||
.setsockopt = sock_no_setsockopt,
|
||||
.getsockopt = sock_no_getsockopt,
|
||||
.setsockopt = sock_common_setsockopt,
|
||||
.getsockopt = sock_common_getsockopt,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_setsockopt = sock_no_setsockopt,
|
||||
.compat_getsockopt = compat_sock_no_getsockopt,
|
||||
.compat_setsockopt = compat_sock_common_setsockopt,
|
||||
.compat_getsockopt = compat_sock_common_getsockopt,
|
||||
#endif
|
||||
.sendmsg = pn_socket_sendmsg,
|
||||
.recvmsg = sock_common_recvmsg,
|
||||
|
|
Loading…
Reference in New Issue