pep.c revision 8f44fcc72a454c5eb7cbc138bd53f0963f23e87f
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> 265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/socket.h> 289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/sock.h> 299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/tcp_states.h> 309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <asm/ioctls.h> 319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/phonet.h> 339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/phonet/phonet.h> 349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/phonet/pep.h> 3502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont#include <net/phonet/gprs.h> 369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* sk_state values: 389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_CLOSE sock not in use yet 399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_CLOSE_WAIT disconnected pipe 409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_LISTEN listening pipe endpoint 419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_SYN_RECV connected pipe in disabled state 429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_ESTABLISHED connected pipe in enabled state 439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * pep_sock locking: 459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - sk_state, ackq, hlist: sock lock needed 469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - listener: read only 479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - pipe_handle: read only 489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define CREDITS_MAX 10 519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define CREDITS_THR 7 529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */ 549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Get the next TLV sub-block. */ 569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen, 579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont void *buf) 589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont void *data = NULL; 609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct { 619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 sb_type; 629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 sb_len; 639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } *ph, h; 649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int buflen = *plen; 659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = skb_header_pointer(skb, 0, 2, &h); 679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len)) 689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->sb_len -= 2; 709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *ptype = ph->sb_type; 719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *plen = ph->sb_len; 729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (buflen > ph->sb_len) 749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont buflen = ph->sb_len; 759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont data = skb_header_pointer(skb, 2, buflen, buf); 769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, 2 + ph->sb_len); 779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return data; 789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_reply(struct sock *sk, struct sk_buff *oskb, 819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 code, const void *data, int len, gfp_t priority) 829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct pnpipehdr *oph = pnp_hdr(oskb); 849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 8614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont struct sockaddr_pn peer; 879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); 899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_set_owner_w(skb, sk); 929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PNPIPE_HEADER); 949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_put(skb, len); 959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_copy_to_linear_data(skb, data, len); 969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_push(skb, sizeof(*ph)); 979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reset_transport_header(skb); 989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = pnp_hdr(skb); 999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = oph->utid; 1009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = oph->message_id + 1; /* REQ -> RESP */ 1019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = oph->pipe_handle; 1029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->error_code = code; 1039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10414ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont pn_skb_get_src_sockaddr(oskb, &peer); 10514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, &peer); 1069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define PAD 0x00 1098d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1108d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 1110165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmontstatic int pipe_handler_send_req(struct sock *sk, u8 msg_id, gfp_t priority) 1128d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 1138d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi int len; 1148d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct pnpipehdr *ph; 1158d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct sk_buff *skb; 116b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 1178d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1188d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi static const u8 data[4] = { 1198d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi PAD, PAD, PAD, PAD, 1208d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi }; 1218d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1228d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi switch (msg_id) { 1238d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_CONNECT_REQ: 1248d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi len = sizeof(data); 1258d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 1268d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1278d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_DISCONNECT_REQ: 1288d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_ENABLE_REQ: 1298d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_DISABLE_REQ: 1308d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi len = 0; 1318d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 1328d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1338d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi default: 1348d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi return -EINVAL; 1358d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi } 1368d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1378d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); 1388d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (!skb) 1398d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi return -ENOMEM; 1408d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_set_owner_w(skb, sk); 1418d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1428d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_reserve(skb, MAX_PNPIPE_HEADER); 1438d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (len) { 1448d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi __skb_put(skb, len); 1458d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_copy_to_linear_data(skb, data, len); 1468d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi } 1478d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi __skb_push(skb, sizeof(*ph)); 1488d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_reset_transport_header(skb); 1498d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph = pnp_hdr(skb); 1500165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont ph->utid = msg_id; /* whatever */ 1518d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph->message_id = msg_id; 152b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi ph->pipe_handle = pn->pipe_handle; 1538d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph->error_code = PN_PIPE_NO_ERROR; 1548d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 15514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 1568d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi} 1578d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1580165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmontstatic int pipe_handler_send_created_ind(struct sock *sk, u8 msg_id) 1598d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 1608d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi int err_code; 1618d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct pnpipehdr *ph; 1628d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct sk_buff *skb; 1638d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 164b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 1658d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi static u8 data[4] = { 1668d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 0x03, 0x04, 1678d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi }; 168b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi data[2] = pn->tx_fc; 169b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi data[3] = pn->rx_fc; 1708d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1718d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi /* 1728d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * actually, below is number of sub-blocks and not error code. 1738d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * Pipe_created_ind message format does not have any 1748d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * error code field. However, the Phonet stack will always send 1758d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * an error code as part of pnpipehdr. So, use that err_code to 1768d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * specify the number of sub-blocks. 1778d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi */ 1788d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi err_code = 0x01; 1798d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1808d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb = alloc_skb(MAX_PNPIPE_HEADER + sizeof(data), GFP_ATOMIC); 1818d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (!skb) 1828d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi return -ENOMEM; 1838d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_set_owner_w(skb, sk); 1848d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1858d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_reserve(skb, MAX_PNPIPE_HEADER); 1868d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi __skb_put(skb, sizeof(data)); 1878d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_copy_to_linear_data(skb, data, sizeof(data)); 1888d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi __skb_push(skb, sizeof(*ph)); 1898d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_reset_transport_header(skb); 1908d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph = pnp_hdr(skb); 1910165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont ph->utid = 0; 1928d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph->message_id = msg_id; 193b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi ph->pipe_handle = pn->pipe_handle; 1948d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph->error_code = err_code; 1958d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 19614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 1978d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi} 1988d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1990165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmontstatic int pipe_handler_send_ind(struct sock *sk, u8 msg_id) 2008d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 2018d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi int err_code; 2028d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct pnpipehdr *ph; 2038d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct sk_buff *skb; 204b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 2058d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 2068d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi /* 2078d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * actually, below is a filler. 2088d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * Pipe_enabled/disabled_ind message format does not have any 2098d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * error code field. However, the Phonet stack will always send 2108d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * an error code as part of pnpipehdr. So, use that err_code to 2118d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi * specify the filler value. 2128d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi */ 2138d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi err_code = 0x0; 2148d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 2158d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); 2168d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (!skb) 2178d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi return -ENOMEM; 2188d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_set_owner_w(skb, sk); 2198d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 2208d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_reserve(skb, MAX_PNPIPE_HEADER); 2218d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi __skb_push(skb, sizeof(*ph)); 2228d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi skb_reset_transport_header(skb); 2238d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph = pnp_hdr(skb); 2240165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont ph->utid = 0; 2258d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph->message_id = msg_id; 226b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi ph->pipe_handle = pn->pipe_handle; 2278d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph->error_code = err_code; 2288d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 22914ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 2308d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi} 2318d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 23203789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmontstatic int pipe_handler_enable_pipe(struct sock *sk, int enable) 2338d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 2340165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont u8 id = enable ? PNS_PEP_ENABLE_REQ : PNS_PEP_DISABLE_REQ; 2350165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont 2360165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont return pipe_handler_send_req(sk, id, GFP_KERNEL); 2378d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi} 2388d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#endif 2398d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 2409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_accept_conn(struct sock *sk, struct sk_buff *skb) 2419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont static const u8 data[20] = { 2439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, PAD, PAD, 2 /* sub-blocks */, 2449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_PIPE_SB_REQUIRED_FC_TX, pep_sb_size(5), 3, PAD, 2459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_MULTI_CREDIT_FLOW_CONTROL, 2469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_ONE_CREDIT_FLOW_CONTROL, 2479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_LEGACY_FLOW_CONTROL, 2489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, 2499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_PIPE_SB_PREFERRED_FC_RX, pep_sb_size(5), 3, PAD, 2509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_MULTI_CREDIT_FLOW_CONTROL, 2519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_ONE_CREDIT_FLOW_CONTROL, 2529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_LEGACY_FLOW_CONTROL, 2539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, 2549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont }; 2559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont might_sleep(); 2579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pep_reply(sk, skb, PN_PIPE_NO_ERROR, data, sizeof(data), 2589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont GFP_KERNEL); 2599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code) 2629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ }; 2649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont WARN_ON(code == PN_PIPE_NO_ERROR); 2659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC); 2669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Control requests are not sent by the pipe service and have a specific 2699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * message format. */ 270c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontstatic int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, 271c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont gfp_t priority) 2729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct pnpipehdr *oph = pnp_hdr(oskb); 2749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 2759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 2769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 2779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 278c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); 2799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 2809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 2819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_set_owner_w(skb, sk); 2829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PHONET_HEADER); 2849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = (struct pnpipehdr *)skb_put(skb, sizeof(*ph) + 4); 2859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = oph->utid; 2879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = PNS_PEP_CTRL_RESP; 2889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = oph->pipe_handle; 2899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[0] = oph->data[1]; /* CTRL id */ 2909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[1] = oph->data[0]; /* PEP type */ 2919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[2] = code; /* error code, at an usual offset */ 2929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[3] = PAD; 2939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[4] = PAD; 2949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_src_sockaddr(oskb, &dst); 2969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pn_skb_send(sk, skb, &dst); 2979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) 3009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 3019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 3029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 3039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 3049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); 3069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 3079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 3089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_set_owner_w(skb, sk); 3099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reserve(skb, MAX_PNPIPE_HEADER + 4); 3119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_push(skb, sizeof(*ph) + 4); 3129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_reset_transport_header(skb); 3139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = pnp_hdr(skb); 3149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = 0; 3159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = PNS_PEP_STATUS_IND; 3169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 3179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pep_type = PN_PEP_TYPE_COMMON; 3189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[1] = type; 3199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[2] = PAD; 3209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[3] = PAD; 3219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[4] = status; 3229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 32314ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 3249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 3259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Send our RX flow control information to the sender. 3279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket must be locked. */ 3289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pipe_grant_credits(struct sock *sk) 3299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 3309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 3319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 3339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (pn->rx_fc) { 3359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_LEGACY_FLOW_CONTROL: /* TODO */ 3369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_ONE_CREDIT_FLOW_CONTROL: 3389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL, 3399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PEP_IND_READY, GFP_ATOMIC); 3409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = 1; 3419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_MULTI_CREDIT_FLOW_CONTROL: 3439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX) 3449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS, 3469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont CREDITS_MAX - pn->rx_credits, 3479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont GFP_ATOMIC) == 0) 3489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = CREDITS_MAX; 3499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 3529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) 3549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 3559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 356a91e7d471e2e384035b9746ea707ccdcd353f5ddKumar Sanghvi struct pnpipehdr *hdr; 357be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont int wake = 0; 3589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) 3609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 3619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 362a91e7d471e2e384035b9746ea707ccdcd353f5ddKumar Sanghvi hdr = pnp_hdr(skb); 3639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hdr->data[0] != PN_PEP_TYPE_COMMON) { 3649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n", 3659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont (unsigned)hdr->data[0]); 3669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 3679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->data[1]) { 3709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PEP_IND_FLOW_CONTROL: 3719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (pn->tx_fc) { 3729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_LEGACY_FLOW_CONTROL: 3739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->data[4]) { 3749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PEP_IND_BUSY: 375be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 3769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PEP_IND_READY: 378be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, wake = 1); 3799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_ONE_CREDIT_FLOW_CONTROL: 3839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hdr->data[4] == PEP_IND_READY) 384be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, wake = 1); 3859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: 3909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) 3919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 392be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_add(wake = hdr->data[4], &pn->tx_credits); 3939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 3969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n", 3979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont (unsigned)hdr->data[1]); 3989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 3999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 400be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (wake) 4019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_write_space(sk); 4029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 4039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_rcv_created(struct sock *sk, struct sk_buff *skb) 4069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 4079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 4089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 4099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 n_sb = hdr->data[0]; 4109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; 4129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, sizeof(*hdr)); 4139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (n_sb > 0) { 4149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 type, buf[2], len = sizeof(buf); 4159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 *data = pep_get_sb(skb, &type, &len, buf); 4169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (data == NULL) 4189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 4199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (type) { 4209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_SB_NEGOTIATED_FC: 4219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (len < 2 || (data[0] | data[1]) > 3) 4229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->tx_fc = data[0] & 3; 4249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_fc = data[1] & 3; 4259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb--; 4289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 4309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Queue an skb to a connected sock. 4339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. */ 4349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) 4359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 4369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 4379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 438c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct sk_buff_head *queue; 4399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err = 0; 4409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); 4429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 4449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 4459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 4469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 4499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 4509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_CLOSE_WAIT; 4519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 4529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state_change(sk); 4539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4558d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 4568d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_DISCONNECT_RESP: 457b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_state = TCP_CLOSE; 4588d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 4598d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#endif 4608d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 4619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 4629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ 4639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 4649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4668d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 4678d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_ENABLE_RESP: 4680165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND); 4698d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 470b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi if (!pn_flow_safe(pn->tx_fc)) { 471b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi atomic_set(&pn->tx_credits, 1); 472b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_write_space(sk); 473b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi } 474b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi if (sk->sk_state == TCP_ESTABLISHED) 475b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi break; /* Nothing to do */ 476b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_state = TCP_ESTABLISHED; 477b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi pipe_grant_credits(sk); 4788d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 4798d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#endif 4808d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 4819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 4829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->state_after_reset) { 4839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_DISABLE: 4849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->init_enable = 0; 4859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_ENABLE: 4879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->init_enable = 1; 4889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: /* not allowed to send an error here!? */ 4909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EINVAL; 4919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 4929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 4949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 495be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 4969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 4979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4998d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 5008d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi case PNS_PEP_DISABLE_RESP: 501b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi atomic_set(&pn->tx_credits, 0); 5020165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND); 503b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_state = TCP_SYN_RECV; 504b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi pn->rx_credits = 0; 5058d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 5068d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#endif 5078d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 5089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 5092e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { 5102e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont atomic_inc(&sk->sk_drops); 511c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont break; 5122e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont } 513c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont __skb_pull(skb, 4); 514c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont queue = &pn->ctrlreq_queue; 515c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto queue; 5169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 517fc6a110754476362f9f4fa3199a637f2331c5993Rémi Denis-Courmont case PNS_PIPE_ALIGNED_DATA: 518fc6a110754476362f9f4fa3199a637f2331c5993Rémi Denis-Courmont __skb_pull(skb, 1); 519fc6a110754476362f9f4fa3199a637f2331c5993Rémi Denis-Courmont /* fall through */ 5209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_DATA: 5219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, 3); /* Pipe data header */ 5229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn_flow_safe(pn->rx_fc)) { 5239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_queue_rcv_skb(sk, skb); 5249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 5259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 5269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 5289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pn->rx_credits == 0) { 5302e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont atomic_inc(&sk->sk_drops); 5319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOBUFS; 5329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 5349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits--; 535c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont queue = &sk->sk_receive_queue; 536c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto queue; 5379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_STATUS_IND: 5399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_rcv_status(sk, skb); 5409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_REDIRECTED_IND: 5439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pipe_rcv_created(sk, skb); 5449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_CREATED_IND: 5479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pipe_rcv_created(sk, skb); 5489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 5499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 5519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_RESET_IND: 5529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn->init_enable) 5539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 5559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_ENABLED_IND: 5569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn_flow_safe(pn->tx_fc)) { 557be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 1); 5589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_write_space(sk); 5599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 5609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 5619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; /* Nothing to do */ 5629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_ESTABLISHED; 5639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_grant_credits(sk); 5649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_DISABLED_IND: 5679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_SYN_RECV; 5689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = 0; 5699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 5709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 5729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n", 5739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr->message_id); 5749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EINVAL; 5759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 5769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 5779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 5789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 579c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 580c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontqueue: 581c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb->dev = NULL; 582c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_set_owner_r(skb, sk); 583c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont err = skb->len; 584c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_tail(queue, skb); 585c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 586c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont sk->sk_data_ready(sk, err); 587c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont return 0; 5889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 5899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 5909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Destroy connected sock. */ 5919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pipe_destruct(struct sock *sk) 5929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 593c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 594c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 5959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_purge(&sk->sk_receive_queue); 596c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_purge(&pn->ctrlreq_queue); 5979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 5989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 599b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 6008f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmontstatic u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) 6018f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont{ 6028f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont unsigned i; 6038f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 final_fc = PN_NO_FLOW_CONTROL; 6048f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6058f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont for (i = 0; i < n; i++) { 6068f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 fc = fcs[i]; 6078f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6088f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (fc > final_fc && fc < PN_MAX_FLOW_CONTROL) 6098f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont final_fc = fc; 6108f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 6118f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return final_fc; 6128f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont} 6138f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 614b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvistatic int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) 615b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi{ 616b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 6178f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont struct pnpipehdr *hdr; 6188f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 n_sb; 6198f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6208f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (!pskb_pull(skb, sizeof(*hdr) + 4)) 6218f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return -EINVAL; 6228f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6238f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont hdr = pnp_hdr(skb); 6248f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6258f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont /* Parse sub-blocks */ 6268f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont n_sb = hdr->data[4]; 6278f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont while (n_sb > 0) { 6288f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 type, buf[6], len = sizeof(buf); 6298f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 6308f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6318f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (data == NULL) 6328f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return -EINVAL; 6338f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6348f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont switch (type) { 6358f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont case PN_PIPE_SB_REQUIRED_FC_TX: 6368f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (len < 2 || len < data[0]) 6378f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 6388f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont pn->tx_fc = pipe_negotiate_fc(data + 2, len - 2); 6398f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 6408f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6418f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont case PN_PIPE_SB_PREFERRED_FC_RX: 6428f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (len < 2 || len < data[0]) 6438f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 6448f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont pn->rx_fc = pipe_negotiate_fc(data + 2, len - 2); 6458f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 6468f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 6478f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 6488f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont n_sb--; 6498f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 650b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 651b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_state = TCP_SYN_RECV; 652b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_backlog_rcv = pipe_do_rcv; 653b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_destruct = pipe_destruct; 654b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi pn->rx_credits = 0; 655b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_state_change(sk); 656b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 6570165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont return pipe_handler_send_created_ind(sk, PNS_PIPE_CREATED_IND); 658b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi} 659b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#endif 660b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 6619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) 6629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *newsk; 6649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *newpn, *pn = pep_sk(sk); 6659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr; 66614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont struct sockaddr_pn dst, src; 6679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u16 peer_type; 6689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle, enabled, n_sb; 669fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont u8 aligned = 0; 6709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_pull(skb, sizeof(*hdr) + 4)) 6729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 6739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr = pnp_hdr(skb); 6759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 6769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->state_after_connect) { 6779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_DISABLE: 6789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont enabled = 0; 6799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 6809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_ENABLE: 6819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont enabled = 1; 6829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 6839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 6849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM); 6859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 6869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont peer_type = hdr->other_pep_type << 8; 6889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (unlikely(sk->sk_state != TCP_LISTEN) || sk_acceptq_is_full(sk)) { 6909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 6919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOBUFS; 6929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Parse sub-blocks (options) */ 6959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb = hdr->data[4]; 6969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (n_sb > 0) { 6979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 type, buf[1], len = sizeof(buf); 6989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 6999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (data == NULL) 7019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 7029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (type) { 7039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE: 7049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (len < 1) 7059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 7069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont peer_type = (peer_type & 0xff00) | data[0]; 7079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 708fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont case PN_PIPE_SB_ALIGNED_DATA: 709fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont aligned = data[0] != 0; 710fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont break; 7119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb--; 7139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = skb_clone(skb, GFP_ATOMIC); 7169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 7179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 7189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Create a new to-be-accepted sock */ 7209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot); 7219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!newsk) { 7229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 7239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 7249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_init_data(NULL, newsk); 7269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_state = TCP_SYN_RECV; 7279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_backlog_rcv = pipe_do_rcv; 7289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_protocol = sk->sk_protocol; 7299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk->sk_destruct = pipe_destruct; 7309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn = pep_sk(newsk); 7329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 73314ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont pn_skb_get_src_sockaddr(skb, &src); 7349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); 73514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont newpn->pn_sk.dobject = pn_sockaddr_get_object(&src); 73614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst); 737c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_head_init(&newpn->ctrlreq_queue); 7389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->pipe_handle = pipe_handle; 739be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&newpn->tx_credits, 0); 7409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->peer_type = peer_type; 741be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont newpn->rx_credits = 0; 7429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 7439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newpn->init_enable = enabled; 744fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont newpn->aligned = aligned; 7459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); 7479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_head(&newsk->sk_receive_queue, skb); 7489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 7499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_data_ready(sk, 0); 7509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_acceptq_added(sk); 7529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_add_node(newsk, &pn->ackq); 7539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 7549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Listening sock must be locked */ 7579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct sock *pep_find_pipe(const struct hlist_head *hlist, 7589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct sockaddr_pn *dst, 7599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle) 7609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 7619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct hlist_node *node; 7629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 7639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u16 dobj = pn_sockaddr_get_object(dst); 7649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_for_each(sknode, node, hlist) { 7669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pnnode = pep_sk(sknode); 7679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Ports match, but addresses might not: */ 7699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pn_sk.sobject != dobj) 7709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 7719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pipe_handle != pipe_handle) 7729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 7739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode->sk_state == TCP_CLOSE_WAIT) 7749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 7759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sknode); 7779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sknode; 7789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 7809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* 7839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Deliver an skb to a listening sock. 7849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. 7859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * We then queue the skb to the right connected sock (if any). 7869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 7879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_do_rcv(struct sock *sk, struct sk_buff *skb) 7889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 7899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 7909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 7912ddc1ac1b9f00096869a48b97c28de72386200d2Rémi Denis-Courmont struct pnpipehdr *hdr; 7929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 7939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err = NET_RX_SUCCESS; 7949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle; 7959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr))) 7979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 7989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr = pnp_hdr(skb); 8009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 8019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_handle == PN_PIPE_INVALID_HANDLE) 8029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 8039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 8059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Look for an existing pipe handle */ 8079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle); 8089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode) 8099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sk_receive_skb(sknode, skb, 1); 8109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Look for a pipe handle pending accept */ 8129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle); 8139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode) { 8149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_put(sknode); 8159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (net_ratelimit()) 8169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont printk(KERN_WARNING"Phonet unconnected PEP ignored"); 8179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = NET_RX_DROP; 8189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 8199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 8229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 8239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pep_connreq_rcv(sk, skb); 8249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 8259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 826b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 827b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi case PNS_PEP_CONNECT_RESP: 828b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi err = pep_connresp_rcv(sk, skb); 829b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi break; 830b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#endif 831b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 8329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 8339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 8349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 8359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 837c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC); 8389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 8399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 8419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 8429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 8439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* invalid handle is not even allowed here! */ 8449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 8459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = NET_RX_DROP; 8469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdrop: 8489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 8499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 8509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 8519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8526482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmontstatic int pipe_do_remove(struct sock *sk) 8536482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont{ 8546482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 8556482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct pnpipehdr *ph; 8566482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct sk_buff *skb; 8576482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 8586482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_KERNEL); 8596482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont if (!skb) 8606482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont return -ENOMEM; 8616482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 8626482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont skb_reserve(skb, MAX_PNPIPE_HEADER); 8636482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont __skb_push(skb, sizeof(*ph)); 8646482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont skb_reset_transport_header(skb); 8656482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph = pnp_hdr(skb); 8666482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->utid = 0; 8676482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->message_id = PNS_PIPE_REMOVE_REQ; 8686482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 8696482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->data[0] = PAD; 8706482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 87114ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 8726482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont} 8736482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 8749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* associated socket ceases to exist */ 8759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_close(struct sock *sk, long timeout) 8769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 8779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 87802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int ifindex = 0; 8799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 880e513480e28cdfd868755f05c1a654fcfcee58070Rémi Denis-Courmont sock_hold(sk); /* keep a reference after sk_common_release() */ 8819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_common_release(sk); 8829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 8849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_LISTEN) { 8859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Destroy the listen queue */ 8869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 8879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct hlist_node *p, *n; 8889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_for_each_safe(sknode, p, n, &pn->ackq) 8909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_del_node_init(sknode); 8919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_CLOSE; 8922feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont } else if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { 8932feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont#ifndef CONFIG_PHONET_PIPECTRLR 8946482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont /* Forcefully remove dangling Phonet pipe */ 8956482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont pipe_do_remove(sk); 8962feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont#else 897b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi /* send pep disconnect request */ 8980165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont pipe_handler_send_req(sk, PNS_PEP_DISCONNECT_REQ, GFP_KERNEL); 899b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi sk->sk_state = TCP_CLOSE; 900b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#endif 9012feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont } 902b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 90302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ifindex = pn->ifindex; 90402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 9059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 90602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 90702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (ifindex) 90802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 909e513480e28cdfd868755f05c1a654fcfcee58070Rémi Denis-Courmont sock_put(sk); 9109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_wait_connreq(struct sock *sk, int noblock) 9139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 9149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct task_struct *tsk = current; 9159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont long timeo = sock_rcvtimeo(sk, noblock); 9179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont for (;;) { 9199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont DEFINE_WAIT(wait); 9209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_LISTEN) 9229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 9239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!hlist_empty(&pn->ackq)) 9249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 9259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!timeo) 9269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EWOULDBLOCK; 9279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (signal_pending(tsk)) 9289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sock_intr_errno(timeo); 9299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 93043815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet prepare_to_wait_exclusive(sk_sleep(sk), &wait, 9319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont TASK_INTERRUPTIBLE); 9329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 9339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont timeo = schedule_timeout(timeo); 9349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 93543815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet finish_wait(sk_sleep(sk), &wait); 9369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 9379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 9399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) 9429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 9439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *newsk = NULL; 9459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *oskb; 9469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err; 9479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 9499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pep_wait_connreq(sk, flags & O_NONBLOCK); 9509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 9519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 9529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = __sk_head(&pn->ackq); 9549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont oskb = skb_dequeue(&newsk->sk_receive_queue); 9569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pep_accept_conn(newsk, oskb); 9579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) { 9589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_head(&newsk->sk_receive_queue, oskb); 9599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = NULL; 9609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 9619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 962635f081541edef7644073f9be50ee5bf7c57ce63Rémi Denis-Courmont kfree_skb(oskb); 9639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sk); 9659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_sk(newsk)->listener = sk; 9669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(newsk); 9689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_del_node_init(newsk); 9699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_acceptq_removed(sk); 9709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_add_node(newsk, &pn->hlist); 9719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __sock_put(newsk); 9729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 9749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 9759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *errp = err; 9769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return newsk; 9779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 979b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 980b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvistatic int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) 981b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi{ 982b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 98314ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont const struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; 984b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 98514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont pn->pn_sk.dobject = pn_sockaddr_get_object(spn); 98614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont pn->pn_sk.resource = pn_sockaddr_get_resource(spn); 9870165d69bcb18c5aa220538389c872852243f9725Rémi Denis-Courmont return pipe_handler_send_req(sk, PNS_PEP_CONNECT_REQ, GFP_KERNEL); 988b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi} 989b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#endif 990b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 9919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) 9929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 993c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int answ; 9959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (cmd) { 9979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case SIOCINQ: 9989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_LISTEN) 9999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 10009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 1002f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches if (sock_flag(sk, SOCK_URGINLINE) && 1003f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches !skb_queue_empty(&pn->ctrlreq_queue)) 1004c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont answ = skb_peek(&pn->ctrlreq_queue)->len; 1005c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont else if (!skb_queue_empty(&sk->sk_receive_queue)) 10069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = skb_peek(&sk->sk_receive_queue)->len; 10079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 10089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = 0; 10099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 10109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return put_user(answ, (int __user *)arg); 10119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 10129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOIOCTLCMD; 10149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 10159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_init(struct sock *sk) 10179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 10189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 10199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont INIT_HLIST_HEAD(&pn->ackq); 10219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont INIT_HLIST_HEAD(&pn->hlist); 1022c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_head_init(&pn->ctrlreq_queue); 10239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 10249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 10259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 10269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 102702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_setsockopt(struct sock *sk, int level, int optname, 1028b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Miller char __user *optval, unsigned int optlen) 102902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 103002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 103102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int val = 0, err = 0; 103202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 103302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 103402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 103502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (optlen >= sizeof(int)) { 103602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(val, (int __user *) optval)) 103702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 103802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 103902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 104002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont lock_sock(sk); 104102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 10428d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 1043b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi case PNPIPE_PIPE_HANDLE: 10448d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (val) { 1045b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi pn->pipe_handle = val; 10468d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 10478d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi } 10488d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#endif 10498d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 105002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 105102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val && val != PNPIPE_ENCAP_IP) { 105202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EINVAL; 105302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 105402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 105502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!pn->ifindex == !val) 105602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; /* Nothing to do! */ 105702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!capable(CAP_NET_ADMIN)) { 105802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EPERM; 105902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 106002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 106102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val) { 106202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 106302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = gprs_attach(sk); 106402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (err > 0) { 106502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = err; 106602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 106702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 106802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } else { 106902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 107002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 107102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 107202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 107302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 107402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont goto out_norel; 107503789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 107603789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont#ifdef CONFIG_PHONET_PIPECTRLR 107703789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont case PNPIPE_ENABLE: 10782feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont if ((1 << sk->sk_state) & ~(TCPF_SYN_RECV|TCPF_ESTABLISHED)) { 107903789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont err = -ENOTCONN; 108003789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont break; 108103789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont } 108203789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont err = pipe_handler_enable_pipe(sk, val); 108303789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont break; 108403789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont#endif 108503789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 108602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 108702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -ENOPROTOOPT; 108802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 108902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 109002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 109102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontout_norel: 109202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return err; 109302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 109402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 109502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_getsockopt(struct sock *sk, int level, int optname, 109602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont char __user *optval, int __user *optlen) 109702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 109802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 109902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int len, val; 110002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 110102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 110202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 110302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(len, optlen)) 110402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 110502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 110602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 110702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 110802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; 110902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 11108d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 111103789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont case PNPIPE_IFINDEX: 111203789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont val = pn->ifindex; 111303789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont break; 111403789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 11158d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 111603789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont case PNPIPE_ENABLE: 11172feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont val = sk->sk_state == TCP_ESTABLISHED; 11188d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi break; 11198d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi#endif 11208d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 112102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 112202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 112302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 112402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 112502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont len = min_t(unsigned int, sizeof(int), len); 112602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(len, optlen)) 112702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 112802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(val, (int __user *) optval)) 112902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 113002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return 0; 113102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 113202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 113302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pipe_skb_send(struct sock *sk, struct sk_buff *skb) 113402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 113502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 113602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pnpipehdr *ph; 1137e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont int err; 113802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1139be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (pn_flow_safe(pn->tx_fc) && 1140be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont !atomic_add_unless(&pn->tx_credits, -1, 0)) { 1141be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont kfree_skb(skb); 1142be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return -ENOBUFS; 1143be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont } 1144be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont 1145fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont skb_push(skb, 3 + pn->aligned); 114602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reset_transport_header(skb); 114702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph = pnp_hdr(skb); 114802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->utid = 0; 1149fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont if (pn->aligned) { 1150fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->message_id = PNS_PIPE_ALIGNED_DATA; 1151fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->data[0] = 0; /* padding */ 1152fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont } else 1153fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->message_id = PNS_PIPE_DATA; 115402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 115514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont err = pn_skb_send(sk, skb, NULL); 1156e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont 1157e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont if (err && pn_flow_safe(pn->tx_fc)) 1158e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont atomic_inc(&pn->tx_credits); 1159e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont return err; 1160e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont 116102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 116202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 11639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 11649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len) 11659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 11669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1167b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont struct sk_buff *skb; 11689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont long timeo; 11699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags = msg->msg_flags; 11709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err, done; 11719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 117282ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL| 117382ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont MSG_CMSG_COMPAT)) || 117482ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont !(msg->msg_flags & MSG_EOR)) 11759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 11769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1177b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, 1178b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont flags & MSG_DONTWAIT, &err); 1179b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont if (!skb) 118002ac3268a581639af241c254579160909373e12cRémi Denis-Courmont return err; 1181b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont 1182b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont skb_reserve(skb, MAX_PHONET_HEADER + 3); 1183b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); 1184b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont if (err < 0) 1185b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont goto outfree; 1186b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont 11879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 11889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 11899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { 11909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOTCONN; 11919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) { 11949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until the pipe gets to enabled state */ 11959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdisabled: 11969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sk_stream_wait_connect(sk, &timeo); 11979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 11989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_CLOSE_WAIT) { 12019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 12029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 12039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 12069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until flow control allows TX */ 1208be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = atomic_read(&pn->tx_credits); 12099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (!done) { 12109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont DEFINE_WAIT(wait); 12119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!timeo) { 12139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EAGAIN; 12149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 12159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (signal_pending(current)) { 12179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_intr_errno(timeo); 12189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 12199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 122143815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet prepare_to_wait(sk_sleep(sk), &wait, 12229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont TASK_INTERRUPTIBLE); 1223be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); 122443815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet finish_wait(sk_sleep(sk), &wait); 12259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) 12279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto disabled; 12289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 123002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = pipe_skb_send(sk, skb); 12319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err >= 0) 12329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = len; /* success! */ 12339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = NULL; 12349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 12359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1236b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmontoutfree: 12379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 12389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 12399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 12409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 124102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_writeable(struct sock *sk) 124202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 124302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 124402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1245be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return atomic_read(&pn->tx_credits); 124602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 124702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 124802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_write(struct sock *sk, struct sk_buff *skb) 124902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 125002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *rskb, *fs; 125102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int flen = 0; 125202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1253fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont if (pep_sk(sk)->aligned) 1254fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont return pipe_skb_send(sk, skb); 1255fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont 125602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); 125702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!rskb) { 125802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont kfree_skb(skb); 125902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOMEM; 126002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 126102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_shinfo(rskb)->frag_list = skb; 126202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->len += skb->len; 126302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->data_len += rskb->len; 126402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->truesize += rskb->len; 126502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 126602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont /* Avoid nested fragments */ 12675c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_walk_frags(skb, fs) 126802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont flen += fs->len; 126902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->next = skb_shinfo(skb)->frag_list; 12705c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_frag_list_init(skb); 127102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->len -= flen; 127202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->data_len -= flen; 127302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->truesize -= flen; 127402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 127502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reserve(rskb, MAX_PHONET_HEADER + 3); 127602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return pipe_skb_send(sk, rskb); 127702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 127802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 127902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstruct sk_buff *pep_read(struct sock *sk) 128002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 128102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); 128202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 128302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 128402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pipe_grant_credits(sk); 128502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return skb; 128602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 128702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 12889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_recvmsg(struct kiocb *iocb, struct sock *sk, 12899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len, int noblock, 12909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags, int *addr_len) 12919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 12929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 12939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err; 12949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 129582ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL| 129682ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont MSG_NOSIGNAL|MSG_CMSG_COMPAT)) 129782ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont return -EOPNOTSUPP; 129882ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont 12999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) 13009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOTCONN; 13019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1302c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) { 1303c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont /* Dequeue and acknowledge control request */ 1304c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1305c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 130682ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if (flags & MSG_PEEK) 130782ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont return -EOPNOTSUPP; 1308c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb = skb_dequeue(&pn->ctrlreq_queue); 1309c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (skb) { 1310c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, 1311c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont GFP_KERNEL); 1312c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont msg->msg_flags |= MSG_OOB; 1313c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto copy; 1314c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 1315c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (flags & MSG_OOB) 1316c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont return -EINVAL; 1317c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 1318c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 13199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = skb_recv_datagram(sk, flags, noblock, &err); 13209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 13219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb == NULL) { 13229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT) 13239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 13249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 13269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 13279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 13299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_grant_credits(sk); 13309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1331c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontcopy: 13329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_EOR; 13339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb->len > len) 13349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_TRUNC; 13359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 13369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont len = skb->len; 13379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); 13399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 13409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = (flags & MSG_TRUNC) ? skb->len : len; 13419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_free_datagram(sk, skb); 13439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 13449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_unhash(struct sock *sk) 13479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 13499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *skparent = NULL; 13509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 1352b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 1353b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#ifndef CONFIG_PHONET_PIPECTRLR 13549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { 13559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skparent = pn->listener; 13569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn = pep_sk(skparent); 13597dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont lock_sock(skparent); 13607dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont sk_del_node_init(sk); 13617dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont sk = skparent; 13629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 1363b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#endif 13649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Unhash a listening sock only when it is closed 13659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * and all of its active connected pipes are closed. */ 13669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hlist_empty(&pn->hlist)) 13679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_sock_unhash(&pn->pn_sk.sk); 13689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skparent) 13719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_put(skparent); 13729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct proto pep_proto = { 13759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .close = pep_sock_close, 13769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .accept = pep_sock_accept, 1377b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#ifdef CONFIG_PHONET_PIPECTRLR 1378b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi .connect = pep_sock_connect, 1379b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi#endif 13809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ioctl = pep_ioctl, 13819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .init = pep_init, 138202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .setsockopt = pep_setsockopt, 138302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .getsockopt = pep_getsockopt, 13849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sendmsg = pep_sendmsg, 13859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .recvmsg = pep_recvmsg, 13869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .backlog_rcv = pep_do_rcv, 13879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .hash = pn_sock_hash, 13889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .unhash = pep_sock_unhash, 13899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .get_port = pn_sock_get_port, 13909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .obj_size = sizeof(struct pep_sock), 13919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .owner = THIS_MODULE, 13929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .name = "PNPIPE", 13939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 13949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct phonet_protocol pep_pn_proto = { 13969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ops = &phonet_stream_ops, 13979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .prot = &pep_proto, 13989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sock_type = SOCK_SEQPACKET, 13999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 14009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 14019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int __init pep_register(void) 14029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 14039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return phonet_proto_register(PN_PROTO_PIPE, &pep_pn_proto); 14049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 14059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 14069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void __exit pep_unregister(void) 14079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 14089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont phonet_proto_unregister(PN_PROTO_PIPE, &pep_pn_proto); 14099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 14109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 14119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_init(pep_register); 14129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_exit(pep_unregister); 14139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_AUTHOR("Remi Denis-Courmont, Nokia"); 14149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_DESCRIPTION("Phonet pipe protocol"); 14159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_LICENSE("GPL"); 14169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_ALIAS_NET_PF_PROTO(PF_PHONET, PN_PROTO_PIPE); 1417