pep.c revision 5c313e9a7773ec4d7ac554e841fba583f7c63aba
19641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* 29641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * File: pep.c 39641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 49641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Phonet pipe protocol end point socket 59641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 69641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Copyright (C) 2008 Nokia Corporation. 79641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 89641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> 99641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * This program is free software; you can redistribute it and/or 119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * modify it under the terms of the GNU General Public License 129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * version 2 as published by the Free Software Foundation. 139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * This program is distributed in the hope that it will be useful, but 159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * WITHOUT ANY WARRANTY; without even the implied warranty of 169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * General Public License for more details. 189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * You should have received a copy of the GNU General Public License 209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * along with this program; if not, write to the Free Software 219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 02110-1301 USA 239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/kernel.h> 269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/socket.h> 279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/sock.h> 289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/tcp_states.h> 299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <asm/ioctls.h> 309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/phonet.h> 329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/phonet/phonet.h> 339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/phonet/pep.h> 3402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont#include <net/phonet/gprs.h> 359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* sk_state values: 379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_CLOSE sock not in use yet 389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_CLOSE_WAIT disconnected pipe 399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_LISTEN listening pipe endpoint 409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_SYN_RECV connected pipe in disabled state 419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_ESTABLISHED connected pipe in enabled state 429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * pep_sock locking: 449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - sk_state, ackq, hlist: sock lock needed 459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - listener: read only 469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - pipe_handle: read only 479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define CREDITS_MAX 10 509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define CREDITS_THR 7 519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic const struct sockaddr_pn pipe_srv = { 539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .spn_family = AF_PHONET, 549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .spn_resource = 0xD9, /* pipe service */ 559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */ 589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Get the next TLV sub-block. */ 609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen, 619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont void *buf) 629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont void *data = NULL; 649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct { 659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 sb_type; 669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 sb_len; 679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } *ph, h; 689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int buflen = *plen; 699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = skb_header_pointer(skb, 0, 2, &h); 719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len)) 729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->sb_len -= 2; 749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *ptype = ph->sb_type; 759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *plen = ph->sb_len; 769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (buflen > ph->sb_len) 789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont buflen = ph->sb_len; 799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont data = skb_header_pointer(skb, 2, buflen, buf); 809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, 2 + ph->sb_len); 819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return data; 829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_reply(struct sock *sk, struct sk_buff *oskb, 859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 code, const void *data, int len, gfp_t priority) 869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct pnpipehdr *oph = pnp_hdr(oskb); 889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); 929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_set_owner_w(skb, sk); 959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PNPIPE_HEADER); 979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_put(skb, len); 989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_copy_to_linear_data(skb, data, len); 999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_push(skb, sizeof(*ph)); 1009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reset_transport_header(skb); 1019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = pnp_hdr(skb); 1029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = oph->utid; 1039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = oph->message_id + 1; /* REQ -> RESP */ 1049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = oph->pipe_handle; 1059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->error_code = code; 1069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pn_skb_send(sk, skb, &pipe_srv); 1089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define PAD 0x00 1119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_accept_conn(struct sock *sk, struct sk_buff *skb) 1129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont static const u8 data[20] = { 1149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, PAD, PAD, 2 /* sub-blocks */, 1159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_PIPE_SB_REQUIRED_FC_TX, pep_sb_size(5), 3, PAD, 1169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_MULTI_CREDIT_FLOW_CONTROL, 1179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_ONE_CREDIT_FLOW_CONTROL, 1189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_LEGACY_FLOW_CONTROL, 1199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, 1209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_PIPE_SB_PREFERRED_FC_RX, pep_sb_size(5), 3, PAD, 1219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_MULTI_CREDIT_FLOW_CONTROL, 1229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_ONE_CREDIT_FLOW_CONTROL, 1239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_LEGACY_FLOW_CONTROL, 1249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, 1259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont }; 1269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont might_sleep(); 1289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pep_reply(sk, skb, PN_PIPE_NO_ERROR, data, sizeof(data), 1299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont GFP_KERNEL); 1309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code) 1339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ }; 1359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont WARN_ON(code == PN_PIPE_NO_ERROR); 1369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC); 1379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Control requests are not sent by the pipe service and have a specific 1409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * message format. */ 141c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontstatic int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, 142c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont gfp_t priority) 1439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct pnpipehdr *oph = pnp_hdr(oskb); 1459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 1469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 1479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 1489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 149c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); 1509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 1519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 1529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_set_owner_w(skb, sk); 1539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PHONET_HEADER); 1559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = (struct pnpipehdr *)skb_put(skb, sizeof(*ph) + 4); 1569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = oph->utid; 1589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = PNS_PEP_CTRL_RESP; 1599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = oph->pipe_handle; 1609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[0] = oph->data[1]; /* CTRL id */ 1619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[1] = oph->data[0]; /* PEP type */ 1629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[2] = code; /* error code, at an usual offset */ 1639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[3] = PAD; 1649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[4] = PAD; 1659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_src_sockaddr(oskb, &dst); 1679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pn_skb_send(sk, skb, &dst); 1689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) 1719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 1749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 1759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); 1779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 1789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 1799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_set_owner_w(skb, sk); 1809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PNPIPE_HEADER + 4); 1829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_push(skb, sizeof(*ph) + 4); 1839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reset_transport_header(skb); 1849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = pnp_hdr(skb); 1859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = 0; 1869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = PNS_PEP_STATUS_IND; 1879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 1889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pep_type = PN_PEP_TYPE_COMMON; 1899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[1] = type; 1909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[2] = PAD; 1919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[3] = PAD; 1929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[4] = status; 1939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pn_skb_send(sk, skb, &pipe_srv); 1959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Send our RX flow control information to the sender. 1989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket must be locked. */ 1999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pipe_grant_credits(struct sock *sk) 2009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 2029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 2049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (pn->rx_fc) { 2069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_LEGACY_FLOW_CONTROL: /* TODO */ 2079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_ONE_CREDIT_FLOW_CONTROL: 2099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL, 2109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PEP_IND_READY, GFP_ATOMIC); 2119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = 1; 2129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_MULTI_CREDIT_FLOW_CONTROL: 2149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX) 2159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS, 2179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont CREDITS_MAX - pn->rx_credits, 2189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont GFP_ATOMIC) == 0) 2199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = CREDITS_MAX; 2209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) 2259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 2279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 228be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont int wake = 0; 2299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) 2319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 2329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hdr->data[0] != PN_PEP_TYPE_COMMON) { 2349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n", 2359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont (unsigned)hdr->data[0]); 2369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 2379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->data[1]) { 2409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PEP_IND_FLOW_CONTROL: 2419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (pn->tx_fc) { 2429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_LEGACY_FLOW_CONTROL: 2439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->data[4]) { 2449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PEP_IND_BUSY: 245be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 2469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PEP_IND_READY: 248be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, wake = 1); 2499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_ONE_CREDIT_FLOW_CONTROL: 2539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hdr->data[4] == PEP_IND_READY) 254be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, wake = 1); 2559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: 2609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) 2619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 262be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_add(wake = hdr->data[4], &pn->tx_credits); 2639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 2669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n", 2679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont (unsigned)hdr->data[1]); 2689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 2699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 270be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (wake) 2719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_write_space(sk); 2729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 2739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_rcv_created(struct sock *sk, struct sk_buff *skb) 2769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 2789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 2799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 n_sb = hdr->data[0]; 2809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; 2829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, sizeof(*hdr)); 2839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (n_sb > 0) { 2849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 type, buf[2], len = sizeof(buf); 2859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 *data = pep_get_sb(skb, &type, &len, buf); 2869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (data == NULL) 2889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 2899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (type) { 2909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_SB_NEGOTIATED_FC: 2919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (len < 2 || (data[0] | data[1]) > 3) 2929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->tx_fc = data[0] & 3; 2949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_fc = data[1] & 3; 2959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb--; 2989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 3009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 3019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Queue an skb to a connected sock. 3039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. */ 3049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) 3059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 3069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 3079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 308c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct sk_buff_head *queue; 3099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err = 0; 3109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); 3129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 3149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 3159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 3169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 3199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 3209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_CLOSE_WAIT; 3219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 3229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state_change(sk); 3239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 3269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ 3279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 3289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 3319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->state_after_reset) { 3329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_DISABLE: 3339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->init_enable = 0; 3349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_ENABLE: 3369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->init_enable = 1; 3379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: /* not allowed to send an error here!? */ 3399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EINVAL; 3409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 3419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 3439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 344be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 3459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 3469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 349c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) 350c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont break; 351c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont __skb_pull(skb, 4); 352c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont queue = &pn->ctrlreq_queue; 353c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto queue; 3549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_DATA: 3569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, 3); /* Pipe data header */ 3579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn_flow_safe(pn->rx_fc)) { 3589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_queue_rcv_skb(sk, skb); 3599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 3609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 3619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pn->rx_credits == 0) { 3659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOBUFS; 3669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits--; 369c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont queue = &sk->sk_receive_queue; 370c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto queue; 3719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_STATUS_IND: 3739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_rcv_status(sk, skb); 3749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_REDIRECTED_IND: 3779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pipe_rcv_created(sk, skb); 3789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_CREATED_IND: 3819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pipe_rcv_created(sk, skb); 3829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 3839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 3859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_RESET_IND: 3869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn->init_enable) 3879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 3899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_ENABLED_IND: 3909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn_flow_safe(pn->tx_fc)) { 391be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 1); 3929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_write_space(sk); 3939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 3959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; /* Nothing to do */ 3969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_ESTABLISHED; 3979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_grant_credits(sk); 3989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_DISABLED_IND: 4019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_SYN_RECV; 4029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = 0; 4039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 4069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n", 4079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr->message_id); 4089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EINVAL; 4099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 4119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 4129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 413c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 414c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontqueue: 415c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb->dev = NULL; 416c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_set_owner_r(skb, sk); 417c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont err = skb->len; 418c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_tail(queue, skb); 419c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 420c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont sk->sk_data_ready(sk, err); 421c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont return 0; 4229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Destroy connected sock. */ 4259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pipe_destruct(struct sock *sk) 4269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 427c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 428c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 4299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_purge(&sk->sk_receive_queue); 430c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_purge(&pn->ctrlreq_queue); 4319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) 4349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 4359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *newsk; 4369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *newpn, *pn = pep_sk(sk); 4379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr; 4389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 4399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u16 peer_type; 4409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle, enabled, n_sb; 4419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_pull(skb, sizeof(*hdr) + 4)) 4439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 4449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr = pnp_hdr(skb); 4469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 4479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->state_after_connect) { 4489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_DISABLE: 4499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont enabled = 0; 4509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_ENABLE: 4529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont enabled = 1; 4539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 4559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM); 4569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 4579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont peer_type = hdr->other_pep_type << 8; 4599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (unlikely(sk->sk_state != TCP_LISTEN) || sk_acceptq_is_full(sk)) { 4619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 4629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOBUFS; 4639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Parse sub-blocks (options) */ 4669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb = hdr->data[4]; 4679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (n_sb > 0) { 4689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 type, buf[1], len = sizeof(buf); 4699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 4709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (data == NULL) 4729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 4739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (type) { 4749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE: 4759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (len < 1) 4769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 4779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont peer_type = (peer_type & 0xff00) | data[0]; 4789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb--; 4819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = skb_clone(skb, GFP_ATOMIC); 4849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 4859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 4869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Create a new to-be-accepted sock */ 4889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot); 4899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!newsk) { 4909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 4919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 4929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_init_data(NULL, newsk); 4949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_state = TCP_SYN_RECV; 4959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_backlog_rcv = pipe_do_rcv; 4969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_protocol = sk->sk_protocol; 4979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_destruct = pipe_destruct; 4989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn = pep_sk(newsk); 5009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 5019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); 5029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->pn_sk.resource = pn->pn_sk.resource; 503c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_head_init(&newpn->ctrlreq_queue); 5049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->pipe_handle = pipe_handle; 505be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&newpn->tx_credits, 0); 5069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->peer_type = peer_type; 507be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont newpn->rx_credits = 0; 5089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 5099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->init_enable = enabled; 5109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); 5129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_head(&newsk->sk_receive_queue, skb); 5139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 5149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_data_ready(sk, 0); 5159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_acceptq_added(sk); 5179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_add_node(newsk, &pn->ackq); 5189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 5199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 5209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Listening sock must be locked */ 5229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct sock *pep_find_pipe(const struct hlist_head *hlist, 5239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct sockaddr_pn *dst, 5249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle) 5259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 5269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct hlist_node *node; 5279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 5289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u16 dobj = pn_sockaddr_get_object(dst); 5299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_for_each(sknode, node, hlist) { 5319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pnnode = pep_sk(sknode); 5329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Ports match, but addresses might not: */ 5349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pn_sk.sobject != dobj) 5359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 5369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pipe_handle != pipe_handle) 5379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 5389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode->sk_state == TCP_CLOSE_WAIT) 5399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 5409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sknode); 5429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sknode; 5439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 5449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 5459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 5469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* 5489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Deliver an skb to a listening sock. 5499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. 5509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * We then queue the skb to the right connected sock (if any). 5519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 5529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_do_rcv(struct sock *sk, struct sk_buff *skb) 5539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 5549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 5559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 5562ddc1ac1b9f00096869a48b97c28de72386200d2Rémi Denis-Courmont struct pnpipehdr *hdr; 5579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 5589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err = NET_RX_SUCCESS; 5599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle; 5609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr))) 5629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 5639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr = pnp_hdr(skb); 5659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 5669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_handle == PN_PIPE_INVALID_HANDLE) 5679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 5689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 5709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Look for an existing pipe handle */ 5729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle); 5739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode) 5749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sk_receive_skb(sknode, skb, 1); 5759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Look for a pipe handle pending accept */ 5779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle); 5789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode) { 5799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_put(sknode); 5809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (net_ratelimit()) 5819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont printk(KERN_WARNING"Phonet unconnected PEP ignored"); 5829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = NET_RX_DROP; 5839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 5849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 5859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 5879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 5889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pep_connreq_rcv(sk, skb); 5899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 5929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 5939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 596c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC); 5979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 6009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 6019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 6029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* invalid handle is not even allowed here! */ 6039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 6049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = NET_RX_DROP; 6059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdrop: 6079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 6089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 6099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 6109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* associated socket ceases to exist */ 6129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_close(struct sock *sk, long timeout) 6139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 61502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int ifindex = 0; 6169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_common_release(sk); 6189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 6209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_LISTEN) { 6219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Destroy the listen queue */ 6229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 6239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct hlist_node *p, *n; 6249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_for_each_safe(sknode, p, n, &pn->ackq) 6269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_del_node_init(sknode); 6279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_CLOSE; 6289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 62902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ifindex = pn->ifindex; 63002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 6319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 63202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 63302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (ifindex) 63402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 6359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 6369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_wait_connreq(struct sock *sk, int noblock) 6389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct task_struct *tsk = current; 6409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 6419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont long timeo = sock_rcvtimeo(sk, noblock); 6429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont for (;;) { 6449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont DEFINE_WAIT(wait); 6459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_LISTEN) 6479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 6489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!hlist_empty(&pn->ackq)) 6499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 6509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!timeo) 6519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EWOULDBLOCK; 6529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (signal_pending(tsk)) 6539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sock_intr_errno(timeo); 6549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont prepare_to_wait_exclusive(&sk->sk_socket->wait, &wait, 6569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont TASK_INTERRUPTIBLE); 6579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 6589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont timeo = schedule_timeout(timeo); 6599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 6609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont finish_wait(&sk->sk_socket->wait, &wait); 6619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 6649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 6659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) 6679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 6699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *newsk = NULL; 6709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *oskb; 6719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err; 6729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 6749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pep_wait_connreq(sk, flags & O_NONBLOCK); 6759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 6769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 6779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = __sk_head(&pn->ackq); 6799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont oskb = skb_dequeue(&newsk->sk_receive_queue); 6819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pep_accept_conn(newsk, oskb); 6829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) { 6839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_head(&newsk->sk_receive_queue, oskb); 6849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = NULL; 6859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 6869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sk); 6899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_sk(newsk)->listener = sk; 6909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(newsk); 6929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_del_node_init(newsk); 6939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_acceptq_removed(sk); 6949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_add_node(newsk, &pn->hlist); 6959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __sock_put(newsk); 6969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 6989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 6999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *errp = err; 7009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return newsk; 7019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) 7049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 705c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 7069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int answ; 7079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (cmd) { 7099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case SIOCINQ: 7109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_LISTEN) 7119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 7129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 714c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (sock_flag(sk, SOCK_URGINLINE) 715c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont && !skb_queue_empty(&pn->ctrlreq_queue)) 716c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont answ = skb_peek(&pn->ctrlreq_queue)->len; 717c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont else if (!skb_queue_empty(&sk->sk_receive_queue)) 7189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = skb_peek(&sk->sk_receive_queue)->len; 7199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 7209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = 0; 7219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 7229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return put_user(answ, (int __user *)arg); 7239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOIOCTLCMD; 7269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_init(struct sock *sk) 7299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 7309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 7319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont INIT_HLIST_HEAD(&pn->ackq); 7339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont INIT_HLIST_HEAD(&pn->hlist); 734c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_head_init(&pn->ctrlreq_queue); 7359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 7369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 7379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 73902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_setsockopt(struct sock *sk, int level, int optname, 74002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont char __user *optval, int optlen) 74102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 74202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 74302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int val = 0, err = 0; 74402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 74502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 74602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 74702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (optlen >= sizeof(int)) { 74802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(val, (int __user *) optval)) 74902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 75002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 75102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 75202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont lock_sock(sk); 75302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 75402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 75502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val && val != PNPIPE_ENCAP_IP) { 75602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EINVAL; 75702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 75802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 75902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!pn->ifindex == !val) 76002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; /* Nothing to do! */ 76102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!capable(CAP_NET_ADMIN)) { 76202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EPERM; 76302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 76402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 76502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val) { 76602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 76702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = gprs_attach(sk); 76802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (err > 0) { 76902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = err; 77002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 77102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 77202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } else { 77302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 77402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 77502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 77602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 77702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 77802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont goto out_norel; 77902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 78002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -ENOPROTOOPT; 78102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 78202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 78302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 78402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontout_norel: 78502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return err; 78602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 78702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 78802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_getsockopt(struct sock *sk, int level, int optname, 78902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont char __user *optval, int __user *optlen) 79002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 79102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 79202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int len, val; 79302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 79402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 79502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 79602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(len, optlen)) 79702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 79802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 79902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 80002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 80102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; 80202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 80302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_IFINDEX: 80402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont val = pn->ifindex; 80502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 80602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 80702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 80802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 80902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 81002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont len = min_t(unsigned int, sizeof(int), len); 81102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(len, optlen)) 81202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 81302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(val, (int __user *) optval)) 81402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 81502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return 0; 81602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 81702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 81802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pipe_skb_send(struct sock *sk, struct sk_buff *skb) 81902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 82002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 82102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pnpipehdr *ph; 82202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 823be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (pn_flow_safe(pn->tx_fc) && 824be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont !atomic_add_unless(&pn->tx_credits, -1, 0)) { 825be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont kfree_skb(skb); 826be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return -ENOBUFS; 827be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont } 828be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont 82902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_push(skb, 3); 83002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reset_transport_header(skb); 83102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph = pnp_hdr(skb); 83202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->utid = 0; 83302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->message_id = PNS_PIPE_DATA; 83402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 83502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 83602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return pn_skb_send(sk, skb, &pipe_srv); 83702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 83802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 8399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 8409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len) 8419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 8429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 8439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb = NULL; 8449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont long timeo; 8459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags = msg->msg_flags; 8469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err, done; 8479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR)) 8499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 8509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 8529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 8539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { 8549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOTCONN; 8559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 8569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) { 8589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until the pipe gets to enabled state */ 8599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdisabled: 8609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sk_stream_wait_connect(sk, &timeo); 8619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 8629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 8639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_CLOSE_WAIT) { 8659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 8669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 8679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 8709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until flow control allows TX */ 872be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = atomic_read(&pn->tx_credits); 8739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (!done) { 8749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont DEFINE_WAIT(wait); 8759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!timeo) { 8779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EAGAIN; 8789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 8799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (signal_pending(current)) { 8819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_intr_errno(timeo); 8829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 8839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont prepare_to_wait(&sk->sk_socket->wait, &wait, 8869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont TASK_INTERRUPTIBLE); 887be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); 8889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont finish_wait(&sk->sk_socket->wait, &wait); 8899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) 8919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto disabled; 8929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) { 8959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, 8969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont flags & MSG_DONTWAIT, &err); 8979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb == NULL) 8989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 8999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PHONET_HEADER + 3); 9009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 901be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED || 902be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont !atomic_read(&pn->tx_credits)) 9039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto disabled; /* sock_alloc_send_skb might sleep */ 9049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 9059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); 9079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err < 0) 9089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 9099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 91002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = pipe_skb_send(sk, skb); 9119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err >= 0) 9129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = len; /* success! */ 9139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = NULL; 9149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 9159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 9169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 9179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 9189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 92002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_writeable(struct sock *sk) 92102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 92202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 92302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 924be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return atomic_read(&pn->tx_credits); 92502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 92602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 92702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_write(struct sock *sk, struct sk_buff *skb) 92802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 92902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *rskb, *fs; 93002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int flen = 0; 93102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 93202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); 93302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!rskb) { 93402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont kfree_skb(skb); 93502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOMEM; 93602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 93702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_shinfo(rskb)->frag_list = skb; 93802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->len += skb->len; 93902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->data_len += rskb->len; 94002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->truesize += rskb->len; 94102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 94202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont /* Avoid nested fragments */ 9435c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_walk_frags(skb, fs) 94402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont flen += fs->len; 94502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->next = skb_shinfo(skb)->frag_list; 9465c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_frag_list_init(skb); 94702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->len -= flen; 94802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->data_len -= flen; 94902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->truesize -= flen; 95002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 95102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reserve(rskb, MAX_PHONET_HEADER + 3); 95202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return pipe_skb_send(sk, rskb); 95302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 95402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 95502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstruct sk_buff *pep_read(struct sock *sk) 95602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 95702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); 95802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 95902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 96002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pipe_grant_credits(sk); 96102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return skb; 96202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 96302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 9649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_recvmsg(struct kiocb *iocb, struct sock *sk, 9659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len, int noblock, 9669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags, int *addr_len) 9679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 9689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 9699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err; 9709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) 9729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOTCONN; 9739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 974c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) { 975c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont /* Dequeue and acknowledge control request */ 976c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 977c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 978c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb = skb_dequeue(&pn->ctrlreq_queue); 979c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (skb) { 980c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, 981c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont GFP_KERNEL); 982c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont msg->msg_flags |= MSG_OOB; 983c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto copy; 984c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 985c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (flags & MSG_OOB) 986c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont return -EINVAL; 987c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 988c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 9899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = skb_recv_datagram(sk, flags, noblock, &err); 9909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 9919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb == NULL) { 9929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT) 9939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 9949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 9959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 9969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 9979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 9999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_grant_credits(sk); 10009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1001c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontcopy: 10029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_EOR; 10039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb->len > len) 10049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_TRUNC; 10059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 10069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont len = skb->len; 10079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); 10099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 10109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = (flags & MSG_TRUNC) ? skb->len : len; 10119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_free_datagram(sk, skb); 10139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 10149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 10159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_unhash(struct sock *sk) 10179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 10189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 10199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *skparent = NULL; 10209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 10229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { 10239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skparent = pn->listener; 10249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_del_node_init(sk); 10259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 10269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk = skparent; 10289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn = pep_sk(skparent); 10299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 10309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 10319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Unhash a listening sock only when it is closed 10329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * and all of its active connected pipes are closed. */ 10339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hlist_empty(&pn->hlist)) 10349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_sock_unhash(&pn->pn_sk.sk); 10359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 10369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skparent) 10389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_put(skparent); 10399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 10409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct proto pep_proto = { 10429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .close = pep_sock_close, 10439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .accept = pep_sock_accept, 10449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ioctl = pep_ioctl, 10459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .init = pep_init, 104602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .setsockopt = pep_setsockopt, 104702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .getsockopt = pep_getsockopt, 10489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sendmsg = pep_sendmsg, 10499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .recvmsg = pep_recvmsg, 10509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .backlog_rcv = pep_do_rcv, 10519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .hash = pn_sock_hash, 10529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .unhash = pep_sock_unhash, 10539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .get_port = pn_sock_get_port, 10549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .obj_size = sizeof(struct pep_sock), 10559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .owner = THIS_MODULE, 10569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .name = "PNPIPE", 10579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 10589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct phonet_protocol pep_pn_proto = { 10609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ops = &phonet_stream_ops, 10619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .prot = &pep_proto, 10629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sock_type = SOCK_SEQPACKET, 10639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 10649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int __init pep_register(void) 10669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 10679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return phonet_proto_register(PN_PROTO_PIPE, &pep_pn_proto); 10689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 10699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void __exit pep_unregister(void) 10719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 10729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont phonet_proto_unregister(PN_PROTO_PIPE, &pep_pn_proto); 10739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 10749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_init(pep_register); 10769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_exit(pep_unregister); 10779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_AUTHOR("Remi Denis-Courmont, Nokia"); 10789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_DESCRIPTION("Phonet pipe protocol"); 10799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_LICENSE("GPL"); 10809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_ALIAS_NET_PF_PROTO(PF_PHONET, PN_PROTO_PIPE); 1081