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 * 831fdc5553b42abd7e29bb7b89f6ba07514eb4763Rémi Denis-Courmont * Author: Rémi Denis-Courmont 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> 333a9a231d977222eea36eae091df2c358e03ac839Paul Gortmaker#include <linux/module.h> 349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/phonet/phonet.h> 359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/phonet/pep.h> 3602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont#include <net/phonet/gprs.h> 379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* sk_state values: 399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_CLOSE sock not in use yet 409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_CLOSE_WAIT disconnected pipe 419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_LISTEN listening pipe endpoint 429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_SYN_RECV connected pipe in disabled state 439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * TCP_ESTABLISHED connected pipe in enabled state 449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * pep_sock locking: 46f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont * - sk_state, hlist: sock lock needed 479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - listener: read only 489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * - pipe_handle: read only 499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define CREDITS_MAX 10 529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define CREDITS_THR 7 539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */ 559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Get the next TLV sub-block. */ 579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen, 589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont void *buf) 599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont void *data = NULL; 619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct { 629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 sb_type; 639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 sb_len; 649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } *ph, h; 659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int buflen = *plen; 669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = skb_header_pointer(skb, 0, 2, &h); 689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len)) 699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->sb_len -= 2; 719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *ptype = ph->sb_type; 729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *plen = ph->sb_len; 739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (buflen > ph->sb_len) 759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont buflen = ph->sb_len; 769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont data = skb_header_pointer(skb, 2, buflen, buf); 779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, 2 + ph->sb_len); 789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return data; 799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 8144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmontstatic struct sk_buff *pep_alloc_skb(struct sock *sk, const void *payload, 8244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont int len, gfp_t priority) 8344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont{ 8444c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont struct sk_buff *skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); 8544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont if (!skb) 8644c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont return NULL; 8744c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb_set_owner_w(skb, sk); 8844c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont 8944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb_reserve(skb, MAX_PNPIPE_HEADER); 9044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont __skb_put(skb, len); 9144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb_copy_to_linear_data(skb, payload, len); 9244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont __skb_push(skb, sizeof(struct pnpipehdr)); 9344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb_reset_transport_header(skb); 9444c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont return skb; 9544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont} 9644c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont 9744c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmontstatic int pep_reply(struct sock *sk, struct sk_buff *oskb, u8 code, 9844c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont const void *data, int len, gfp_t priority) 999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct pnpipehdr *oph = pnp_hdr(oskb); 1019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 1029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 10314ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont struct sockaddr_pn peer; 1049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 10544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb = pep_alloc_skb(sk, data, len, priority); 1069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 1079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 1089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph = pnp_hdr(skb); 1109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = oph->utid; 1119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = oph->message_id + 1; /* REQ -> RESP */ 1129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = oph->pipe_handle; 1139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->error_code = code; 1149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont pn_skb_get_src_sockaddr(oskb, &peer); 11614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, &peer); 1179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmontstatic int pep_indicate(struct sock *sk, u8 id, u8 code, 12044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont const void *data, int len, gfp_t priority) 1218d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 12244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1238d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct pnpipehdr *ph; 1248d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct sk_buff *skb; 1258d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 12644c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb = pep_alloc_skb(sk, data, len, priority); 1278d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (!skb) 1288d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi return -ENOMEM; 1298d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1308d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph = pnp_hdr(skb); 13144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph->utid = 0; 13244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph->message_id = id; 133b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi ph->pipe_handle = pn->pipe_handle; 13444c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph->data[0] = code; 13514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 1368d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi} 1378d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 13844c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont#define PAD 0x00 13944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont 14044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmontstatic int pipe_handler_request(struct sock *sk, u8 id, u8 code, 14144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont const void *data, int len) 1428d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 14344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1448d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct pnpipehdr *ph; 1458d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi struct sk_buff *skb; 1468d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 14744c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb = pep_alloc_skb(sk, data, len, GFP_KERNEL); 1488d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi if (!skb) 1498d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi return -ENOMEM; 1508d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1518d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi ph = pnp_hdr(skb); 15244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph->utid = id; /* whatever */ 15344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph->message_id = id; 154b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi ph->pipe_handle = pn->pipe_handle; 15544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph->data[0] = code; 15614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 1578d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi} 1588d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 15944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmontstatic int pipe_handler_send_created_ind(struct sock *sk) 1608d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi{ 161b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 16244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont u8 data[4] = { 16344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont PN_PIPE_SB_NEGOTIATED_FC, pep_sb_size(2), 16444c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pn->tx_fc, pn->rx_fc, 16544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont }; 1668d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 16744c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont return pep_indicate(sk, PNS_PIPE_CREATED_IND, 1 /* sub-blocks */, 16844c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont data, 4, GFP_ATOMIC); 16944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont} 1708d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 1719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_accept_conn(struct sock *sk, struct sk_buff *skb) 1729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont static const u8 data[20] = { 1749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, PAD, PAD, 2 /* sub-blocks */, 1759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_PIPE_SB_REQUIRED_FC_TX, pep_sb_size(5), 3, PAD, 1769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_MULTI_CREDIT_FLOW_CONTROL, 1779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_ONE_CREDIT_FLOW_CONTROL, 1789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_LEGACY_FLOW_CONTROL, 1799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, 1809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_PIPE_SB_PREFERRED_FC_RX, pep_sb_size(5), 3, PAD, 1819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_MULTI_CREDIT_FLOW_CONTROL, 1829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_ONE_CREDIT_FLOW_CONTROL, 1839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PN_LEGACY_FLOW_CONTROL, 1849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont PAD, 1859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont }; 1869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont might_sleep(); 1889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pep_reply(sk, skb, PN_PIPE_NO_ERROR, data, sizeof(data), 1899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont GFP_KERNEL); 1909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 192f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmontstatic int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code, 193f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont gfp_t priority) 1949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 1959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ }; 1969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont WARN_ON(code == PN_PIPE_NO_ERROR); 197f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont return pep_reply(sk, skb, code, data, sizeof(data), priority); 1989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 1999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Control requests are not sent by the pipe service and have a specific 2019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * message format. */ 202c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontstatic int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, 203c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont gfp_t priority) 2049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct pnpipehdr *oph = pnp_hdr(oskb); 2069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 2079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *ph; 2089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 20944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont u8 data[4] = { 21044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont oph->data[0], /* PEP type */ 21144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont code, /* error code, at an unusual offset */ 21244c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont PAD, PAD, 21344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont }; 2149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 21544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb = pep_alloc_skb(sk, data, 4, priority); 2169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!skb) 2179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOMEM; 2189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 21944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont ph = pnp_hdr(skb); 2209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->utid = oph->utid; 2219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->message_id = PNS_PEP_CTRL_RESP; 2229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->pipe_handle = oph->pipe_handle; 2239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont ph->data[0] = oph->data[1]; /* CTRL id */ 2249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_src_sockaddr(oskb, &dst); 2269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return pn_skb_send(sk, skb, &dst); 2279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) 2309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 23144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont u8 data[4] = { type, PAD, PAD, status }; 2329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 23344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont return pep_indicate(sk, PNS_PEP_STATUS_IND, PN_PEP_TYPE_COMMON, 23444c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont data, 4, priority); 2359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Send our RX flow control information to the sender. 2389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket must be locked. */ 23944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmontstatic void pipe_grant_credits(struct sock *sk, gfp_t priority) 2409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 2429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 2449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (pn->rx_fc) { 2469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_LEGACY_FLOW_CONTROL: /* TODO */ 2479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_ONE_CREDIT_FLOW_CONTROL: 24944c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont if (pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL, 25044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont PEP_IND_READY, priority) == 0) 25144c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pn->rx_credits = 1; 2529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_MULTI_CREDIT_FLOW_CONTROL: 2549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX) 2559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS, 2579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont CREDITS_MAX - pn->rx_credits, 25844c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont priority) == 0) 2599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = CREDITS_MAX; 2609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 2639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) 2659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 2669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 267a91e7d471e2e384035b9746ea707ccdcd353f5ddKumar Sanghvi struct pnpipehdr *hdr; 268be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont int wake = 0; 2699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) 2719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 2729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 273a91e7d471e2e384035b9746ea707ccdcd353f5ddKumar Sanghvi hdr = pnp_hdr(skb); 2749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hdr->data[0] != PN_PEP_TYPE_COMMON) { 2759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n", 27695c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet (unsigned int)hdr->data[0]); 2779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 2789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 2809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->data[1]) { 2819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PEP_IND_FLOW_CONTROL: 2829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (pn->tx_fc) { 2839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_LEGACY_FLOW_CONTROL: 2849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->data[4]) { 2859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PEP_IND_BUSY: 286be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 2879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PEP_IND_READY: 289be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, wake = 1); 2909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_ONE_CREDIT_FLOW_CONTROL: 2949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hdr->data[4] == PEP_IND_READY) 295be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, wake = 1); 2969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 2989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 2999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: 3019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) 3029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 303be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_add(wake = hdr->data[4], &pn->tx_credits); 3049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 3079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n", 30895c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet (unsigned int)hdr->data[1]); 3099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 3109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 311be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (wake) 3129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_write_space(sk); 3139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 3149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 3159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_rcv_created(struct sock *sk, struct sk_buff *skb) 3179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 3189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 3199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 3209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 n_sb = hdr->data[0]; 3219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; 3239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, sizeof(*hdr)); 3249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (n_sb > 0) { 3259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 type, buf[2], len = sizeof(buf); 3269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 *data = pep_get_sb(skb, &type, &len, buf); 3279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (data == NULL) 3299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EINVAL; 3309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (type) { 3319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_SB_NEGOTIATED_FC: 3329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (len < 2 || (data[0] | data[1]) > 3) 3339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->tx_fc = data[0] & 3; 3359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_fc = data[1] & 3; 3369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont n_sb--; 3399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 3419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 3429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Queue an skb to a connected sock. 3449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. */ 3459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) 3469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 3479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 3489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 349c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct sk_buff_head *queue; 3509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err = 0; 3519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); 3539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 3559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 356f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_ATOMIC); 3579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 3609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 3619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_CLOSE_WAIT; 3629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 3639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state_change(sk); 3649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 3679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ 3689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 3699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 3729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->state_after_reset) { 3739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_DISABLE: 3749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->init_enable = 0; 3759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PN_PIPE_ENABLE: 3779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->init_enable = 1; 3789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: /* not allowed to send an error here!? */ 3809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EINVAL; 3819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 3829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 3839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 3849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 385be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 3869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 3879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 3889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 3899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 3902e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { 3912e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont atomic_inc(&sk->sk_drops); 392c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont break; 3932e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont } 394c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont __skb_pull(skb, 4); 395c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont queue = &pn->ctrlreq_queue; 396c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto queue; 3979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 398fc6a110754476362f9f4fa3199a637f2331c5993Rémi Denis-Courmont case PNS_PIPE_ALIGNED_DATA: 399fc6a110754476362f9f4fa3199a637f2331c5993Rémi Denis-Courmont __skb_pull(skb, 1); 400fc6a110754476362f9f4fa3199a637f2331c5993Rémi Denis-Courmont /* fall through */ 4019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_DATA: 4029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont __skb_pull(skb, 3); /* Pipe data header */ 4039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn_flow_safe(pn->rx_fc)) { 4049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_queue_rcv_skb(sk, skb); 4059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 4060ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont return NET_RX_SUCCESS; 4070ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont err = -ENOBUFS; 4089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pn->rx_credits == 0) { 4122e2fb4b33d62c742019774c5e6e47711a3d60505Rémi Denis-Courmont atomic_inc(&sk->sk_drops); 4139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOBUFS; 4149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits--; 417c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont queue = &sk->sk_receive_queue; 418c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto queue; 4199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_STATUS_IND: 4219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_rcv_status(sk, skb); 4229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_REDIRECTED_IND: 4259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pipe_rcv_created(sk, skb); 4269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_CREATED_IND: 4299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = pipe_rcv_created(sk, skb); 4309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 4319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 4339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_RESET_IND: 4349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn->init_enable) 4359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* fall through */ 4379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_ENABLED_IND: 4389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pn_flow_safe(pn->tx_fc)) { 439be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont atomic_set(&pn->tx_credits, 1); 4409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_write_space(sk); 4419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 4439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; /* Nothing to do */ 4449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_ESTABLISHED; 44544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pipe_grant_credits(sk, GFP_ATOMIC); 4469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PIPE_DISABLED_IND: 4499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk->sk_state = TCP_SYN_RECV; 4509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->rx_credits = 0; 4519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 4529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont default: 4549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n", 4559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr->message_id); 4569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EINVAL; 4579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 4589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 4599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 4600ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont return (err == -ENOBUFS) ? NET_RX_DROP : NET_RX_SUCCESS; 461c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 462c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontqueue: 463c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb->dev = NULL; 464c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_set_owner_r(skb, sk); 465c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_tail(queue, skb); 466c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 467676d23690fb62b5d51ba5d659935e9f7d9da9f8eDavid S. Miller sk->sk_data_ready(sk); 4680ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont return NET_RX_SUCCESS; 4699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Destroy connected sock. */ 4729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pipe_destruct(struct sock *sk) 4739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 474c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 475c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 4769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_purge(&sk->sk_receive_queue); 477c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_purge(&pn->ctrlreq_queue); 4789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 48095c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazetstatic u8 pipe_negotiate_fc(const u8 *fcs, unsigned int n) 4818f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont{ 48295c961747284a6b83a5e2d81240e214b0fa3464dEric Dumazet unsigned int i; 4838f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 final_fc = PN_NO_FLOW_CONTROL; 4848f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 4858f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont for (i = 0; i < n; i++) { 4868f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 fc = fcs[i]; 4878f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 4888f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (fc > final_fc && fc < PN_MAX_FLOW_CONTROL) 4898f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont final_fc = fc; 4908f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 4918f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return final_fc; 4928f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont} 4938f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 494b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvistatic int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) 495b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi{ 496b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 4978f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont struct pnpipehdr *hdr; 4988f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 n_sb; 4998f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5008f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (!pskb_pull(skb, sizeof(*hdr) + 4)) 5018f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return -EINVAL; 5028f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5038f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont hdr = pnp_hdr(skb); 504297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (hdr->error_code != PN_PIPE_NO_ERROR) 505297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return -ECONNREFUSED; 5068f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5078f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont /* Parse sub-blocks */ 5088f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont n_sb = hdr->data[4]; 5098f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont while (n_sb > 0) { 5108f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 type, buf[6], len = sizeof(buf); 5118f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 5128f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5138f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (data == NULL) 5148f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return -EINVAL; 5158f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5168f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont switch (type) { 5178f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont case PN_PIPE_SB_REQUIRED_FC_TX: 5188f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (len < 2 || len < data[0]) 5198f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5208f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont pn->tx_fc = pipe_negotiate_fc(data + 2, len - 2); 5218f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5228f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5238f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont case PN_PIPE_SB_PREFERRED_FC_RX: 5248f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (len < 2 || len < data[0]) 5258f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5268f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont pn->rx_fc = pipe_negotiate_fc(data + 2, len - 2); 5278f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5288f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5298f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 5308f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont n_sb--; 5318f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 532b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 53344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont return pipe_handler_send_created_ind(sk); 534b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi} 535297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 536bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharmastatic int pep_enableresp_rcv(struct sock *sk, struct sk_buff *skb) 537bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma{ 538bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma struct pnpipehdr *hdr = pnp_hdr(skb); 539bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 540bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (hdr->error_code != PN_PIPE_NO_ERROR) 541bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return -ECONNREFUSED; 542bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 543bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return pep_indicate(sk, PNS_PIPE_ENABLED_IND, 0 /* sub-blocks */, 544bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma NULL, 0, GFP_ATOMIC); 545bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 546bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma} 547bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 548bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharmastatic void pipe_start_flow_control(struct sock *sk) 549bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma{ 550bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma struct pep_sock *pn = pep_sk(sk); 551bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 552bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (!pn_flow_safe(pn->tx_fc)) { 553bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma atomic_set(&pn->tx_credits, 1); 554bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_write_space(sk); 555bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma } 556bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pipe_grant_credits(sk, GFP_ATOMIC); 557bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma} 558bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 559297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont/* Queue an skb to an actively connected sock. 560297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont * Socket lock must be held. */ 561297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmontstatic int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) 562297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont{ 563297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 564297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 565297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont int err = NET_RX_SUCCESS; 566297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 567297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont switch (hdr->message_id) { 568297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PIPE_ALIGNED_DATA: 569297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont __skb_pull(skb, 1); 570297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* fall through */ 571297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PIPE_DATA: 572297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont __skb_pull(skb, 3); /* Pipe data header */ 573297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!pn_flow_safe(pn->rx_fc)) { 574297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = sock_queue_rcv_skb(sk, skb); 575297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!err) 576297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return NET_RX_SUCCESS; 577297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = NET_RX_DROP; 578297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 579297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 580297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 581297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (pn->rx_credits == 0) { 582297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont atomic_inc(&sk->sk_drops); 583297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = NET_RX_DROP; 584297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 585297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 586297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->rx_credits--; 587297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont skb->dev = NULL; 588297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont skb_set_owner_r(skb, sk); 589297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont skb_queue_tail(&sk->sk_receive_queue, skb); 590297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 591676d23690fb62b5d51ba5d659935e9f7d9da9f8eDavid S. Miller sk->sk_data_ready(sk); 592297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return NET_RX_SUCCESS; 593297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 594297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PEP_CONNECT_RESP: 595297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (sk->sk_state != TCP_SYN_SENT) 596297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 597297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 598297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_state_change(sk); 599297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (pep_connresp_rcv(sk, skb)) { 600297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_state = TCP_CLOSE_WAIT; 601297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 602297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 603bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (pn->init_enable == PN_PIPE_DISABLE) 604bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_SYN_RECV; 605bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else { 606bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_ESTABLISHED; 607bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pipe_start_flow_control(sk); 608bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma } 609bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 610297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 611bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNS_PEP_ENABLE_RESP: 612bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (sk->sk_state != TCP_SYN_SENT) 613bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 614bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 615bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (pep_enableresp_rcv(sk, skb)) { 616bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_CLOSE_WAIT; 617bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 618297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 619bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 620bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_ESTABLISHED; 621bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pipe_start_flow_control(sk); 622297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 623297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 624297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PEP_DISCONNECT_RESP: 625297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* sock should already be dead, nothing to do */ 626297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 627297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 628297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PEP_STATUS_IND: 629297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pipe_rcv_status(sk, skb); 630297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 631297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 632297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont kfree_skb(skb); 633297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return err; 634297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont} 635b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 6369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Listening sock must be locked */ 6379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct sock *pep_find_pipe(const struct hlist_head *hlist, 6389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct sockaddr_pn *dst, 6399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle) 6409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 6429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u16 dobj = pn_sockaddr_get_object(dst); 6439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 644b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin sk_for_each(sknode, hlist) { 6459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pnnode = pep_sk(sknode); 6469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Ports match, but addresses might not: */ 6489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pn_sk.sobject != dobj) 6499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 6509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pipe_handle != pipe_handle) 6519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 6529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode->sk_state == TCP_CLOSE_WAIT) 6539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 6549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sknode); 6569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sknode; 6579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 6599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 6609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* 6629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Deliver an skb to a listening sock. 6639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. 6649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * We then queue the skb to the right connected sock (if any). 6659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 6669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_do_rcv(struct sock *sk, struct sk_buff *skb) 6679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 6699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 6702ddc1ac1b9f00096869a48b97c28de72386200d2Rémi Denis-Courmont struct pnpipehdr *hdr; 6719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 6729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle; 6739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr))) 6759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 6769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr = pnp_hdr(skb); 6789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 6799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_handle == PN_PIPE_INVALID_HANDLE) 6809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 6819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 6839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Look for an existing pipe handle */ 6859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle); 6869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode) 6879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sk_receive_skb(sknode, skb, 1); 6889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 6909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 691f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (sk->sk_state != TCP_LISTEN || sk_acceptq_is_full(sk)) { 692f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, 693f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont GFP_ATOMIC); 694f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 695f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 696f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont skb_queue_head(&sk->sk_receive_queue, skb); 697f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk_acceptq_added(sk); 698f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 699676d23690fb62b5d51ba5d659935e9f7d9da9f8eDavid S. Miller sk->sk_data_ready(sk); 700f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont return NET_RX_SUCCESS; 7019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 7039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 7049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 7059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 707c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC); 7089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 7099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 7119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 7129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 7139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* invalid handle is not even allowed here! */ 7140ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont break; 715297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 716297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont default: 717297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if ((1 << sk->sk_state) 718297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont & ~(TCPF_CLOSE|TCPF_LISTEN|TCPF_CLOSE_WAIT)) 719297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* actively connected socket */ 720297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return pipe_handler_do_rcv(sk, skb); 7219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdrop: 7239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 7240ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont return NET_RX_SUCCESS; 7259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7276482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmontstatic int pipe_do_remove(struct sock *sk) 7286482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont{ 7296482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 7306482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct pnpipehdr *ph; 7316482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct sk_buff *skb; 7326482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 73344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb = pep_alloc_skb(sk, NULL, 0, GFP_KERNEL); 7346482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont if (!skb) 7356482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont return -ENOMEM; 7366482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 7376482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph = pnp_hdr(skb); 7386482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->utid = 0; 7396482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->message_id = PNS_PIPE_REMOVE_REQ; 7406482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 7416482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->data[0] = PAD; 74214ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 7436482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont} 7446482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 7459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* associated socket ceases to exist */ 7469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_close(struct sock *sk, long timeout) 7479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 7489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 74902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int ifindex = 0; 7509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 751e513480e28cdfd868755f05c1a654fcfcee58070Rémi Denis-Courmont sock_hold(sk); /* keep a reference after sk_common_release() */ 7529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_common_release(sk); 7539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 755f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { 756297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (sk->sk_backlog_rcv == pipe_do_rcv) 757297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* Forcefully remove dangling Phonet pipe */ 758297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pipe_do_remove(sk); 759297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont else 760297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, 761297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont NULL, 0); 7622feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont } 763f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk->sk_state = TCP_CLOSE; 764b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 76502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ifindex = pn->ifindex; 76602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 7679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 76802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 76902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (ifindex) 77002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 771e513480e28cdfd868755f05c1a654fcfcee58070Rémi Denis-Courmont sock_put(sk); 7729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 774f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmontstatic struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) 7759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 776f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk), *newpn; 777f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct sock *newsk = NULL; 778f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct sk_buff *skb; 779f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct pnpipehdr *hdr; 780f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct sockaddr_pn dst, src; 781f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont int err; 782f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u16 peer_type; 783f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u8 pipe_handle, enabled, n_sb; 784f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u8 aligned = 0; 7859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 786f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp); 787f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!skb) 788f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont return NULL; 7899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 790f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont lock_sock(sk); 791f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (sk->sk_state != TCP_LISTEN) { 792f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = -EINVAL; 793f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 7949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 795f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk_acceptq_removed(sk); 7969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 797f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = -EPROTO; 798f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) 799f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 8009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 801f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont hdr = pnp_hdr(skb); 802f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 803f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont switch (hdr->state_after_connect) { 804f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_DISABLE: 805f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont enabled = 0; 806f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 807f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_ENABLE: 808f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont enabled = 1; 809f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 810f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont default: 811f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM, 812f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont GFP_KERNEL); 813f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 814f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 815f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont peer_type = hdr->other_pep_type << 8; 8169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 817f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont /* Parse sub-blocks (options) */ 818f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont n_sb = hdr->data[4]; 819f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont while (n_sb > 0) { 820f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u8 type, buf[1], len = sizeof(buf); 821f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 8229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 823f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (data == NULL) 824f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 825f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont switch (type) { 826f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE: 827f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (len < 1) 828f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 829f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont peer_type = (peer_type & 0xff00) | data[0]; 830f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 831f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_SB_ALIGNED_DATA: 832f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont aligned = data[0] != 0; 833f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 834f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 835f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont n_sb--; 836f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 8379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 838f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont /* Check for duplicate pipe handle */ 839f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk = pep_find_pipe(&pn->hlist, &dst, pipe_handle); 840f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (unlikely(newsk)) { 841f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont __sock_put(newsk); 8429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = NULL; 843f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_KERNEL); 844f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 8459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 847f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont /* Create a new to-be-accepted sock */ 848f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot); 849f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!newsk) { 850f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_OVERLOAD, GFP_KERNEL); 851f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = -ENOBUFS; 852f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 853f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 854f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont 855f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sock_init_data(NULL, newsk); 856f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_state = TCP_SYN_RECV; 857f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_backlog_rcv = pipe_do_rcv; 858f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_protocol = sk->sk_protocol; 859f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_destruct = pipe_destruct; 860f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont 861f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn = pep_sk(newsk); 862f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 863f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pn_skb_get_src_sockaddr(skb, &src); 864f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); 865f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pn_sk.dobject = pn_sockaddr_get_object(&src); 866f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst); 8679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sk); 868f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->listener = sk; 869f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont skb_queue_head_init(&newpn->ctrlreq_queue); 870f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pipe_handle = pipe_handle; 871f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont atomic_set(&newpn->tx_credits, 0); 872f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->ifindex = 0; 873f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->peer_type = peer_type; 874f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->rx_credits = 0; 875f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 876f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->init_enable = enabled; 877f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->aligned = aligned; 8789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 879f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = pep_accept_conn(newsk, skb); 880f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (err) { 881f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sock_put(newsk); 882f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk = NULL; 883f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 884f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 8859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_add_node(newsk, &pn->hlist); 886f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmontdrop: 8879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 888f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont kfree_skb(skb); 8899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *errp = err; 8909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return newsk; 8919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 8929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 893b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvistatic int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) 894b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi{ 895b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 896297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont int err; 89744c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; 898b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 899bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (pn->pipe_handle == PN_PIPE_INVALID_HANDLE) 900bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ 901bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 902297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, 903bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->init_enable, data, 4); 904297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (err) { 905297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 906297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return err; 907297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 908bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 909297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_state = TCP_SYN_SENT; 910bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 911bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return 0; 912bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma} 913bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 914bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharmastatic int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len) 915bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma{ 916bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma int err; 917bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 918bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma err = pipe_handler_request(sk, PNS_PEP_ENABLE_REQ, PAD, 919bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma NULL, 0); 920bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (err) 921bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return err; 922bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 923bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_SYN_SENT; 924bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 925297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return 0; 926b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi} 927b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 9289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) 9299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 930c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int answ; 932bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma int ret = -ENOIOCTLCMD; 9339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (cmd) { 9359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case SIOCINQ: 936bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (sk->sk_state == TCP_LISTEN) { 937bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = -EINVAL; 938bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 939bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma } 9409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 942f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches if (sock_flag(sk, SOCK_URGINLINE) && 943f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches !skb_queue_empty(&pn->ctrlreq_queue)) 944c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont answ = skb_peek(&pn->ctrlreq_queue)->len; 945c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont else if (!skb_queue_empty(&sk->sk_receive_queue)) 9469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = skb_peek(&sk->sk_receive_queue)->len; 9479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 9489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = 0; 9499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 950bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = put_user(answ, (int __user *)arg); 951bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 952bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 953bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case SIOCPNENABLEPIPE: 954bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma lock_sock(sk); 955bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (sk->sk_state == TCP_SYN_SENT) 956bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = -EBUSY; 957bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else if (sk->sk_state == TCP_ESTABLISHED) 958bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = -EISCONN; 959bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else 960bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = pep_sock_enable(sk, NULL, 0); 961bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma release_sock(sk); 962bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 9639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 9649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 965bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return ret; 9669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_init(struct sock *sk) 9699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 9709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 972f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk->sk_destruct = pipe_destruct; 9739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont INIT_HLIST_HEAD(&pn->hlist); 974297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->listener = NULL; 975c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_head_init(&pn->ctrlreq_queue); 976297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 977297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->ifindex = 0; 978297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->peer_type = 0; 9799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 980297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->rx_credits = 0; 981297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; 982297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->init_enable = 1; 983297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->aligned = 0; 9849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 9859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 98702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_setsockopt(struct sock *sk, int level, int optname, 988b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Miller char __user *optval, unsigned int optlen) 98902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 99002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 99102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int val = 0, err = 0; 99202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 99302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 99402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 99502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (optlen >= sizeof(int)) { 99602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(val, (int __user *) optval)) 99702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 99802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 99902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 100002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont lock_sock(sk); 100102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 100202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 100302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val && val != PNPIPE_ENCAP_IP) { 100402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EINVAL; 100502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 100602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 100702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!pn->ifindex == !val) 100802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; /* Nothing to do! */ 100902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!capable(CAP_NET_ADMIN)) { 101002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EPERM; 101102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 101202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 101302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val) { 101402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 101502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = gprs_attach(sk); 101602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (err > 0) { 101702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = err; 101802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 101902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 102002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } else { 102102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 102202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 102302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 102402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 102502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 102602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont goto out_norel; 102703789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 1028bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNPIPE_HANDLE: 1029bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if ((sk->sk_state == TCP_CLOSE) && 1030bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma (val >= 0) && (val < PN_PIPE_INVALID_HANDLE)) 1031bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->pipe_handle = val; 1032bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else 1033bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma err = -EINVAL; 1034bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 1035bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 1036bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNPIPE_INITSTATE: 1037bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->init_enable = !!val; 1038bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 1039bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 104002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 104102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -ENOPROTOOPT; 104202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 104302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 104402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 104502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontout_norel: 104602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return err; 104702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 104802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 104902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_getsockopt(struct sock *sk, int level, int optname, 105002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont char __user *optval, int __user *optlen) 105102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 105202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 105302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int len, val; 105402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 105502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 105602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 105702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(len, optlen)) 105802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 105902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 106002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 106102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 106202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; 106302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 10648d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 106503789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont case PNPIPE_IFINDEX: 106603789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont val = pn->ifindex; 106703789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont break; 106803789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 1069acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont case PNPIPE_HANDLE: 1070acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont val = pn->pipe_handle; 1071acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont if (val == PN_PIPE_INVALID_HANDLE) 1072acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont return -EINVAL; 1073acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont break; 1074acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont 1075bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNPIPE_INITSTATE: 1076bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma val = pn->init_enable; 1077bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 1078bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 107902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 108002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 108102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 108202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 108302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont len = min_t(unsigned int, sizeof(int), len); 108402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(len, optlen)) 108502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 108602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(val, (int __user *) optval)) 108702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 108802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return 0; 108902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 109002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 109102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pipe_skb_send(struct sock *sk, struct sk_buff *skb) 109202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 109302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 109402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pnpipehdr *ph; 1095e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont int err; 109602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1097be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (pn_flow_safe(pn->tx_fc) && 1098be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont !atomic_add_unless(&pn->tx_credits, -1, 0)) { 1099be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont kfree_skb(skb); 1100be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return -ENOBUFS; 1101be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont } 1102be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont 1103fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont skb_push(skb, 3 + pn->aligned); 110402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reset_transport_header(skb); 110502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph = pnp_hdr(skb); 110602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->utid = 0; 1107fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont if (pn->aligned) { 1108fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->message_id = PNS_PIPE_ALIGNED_DATA; 1109fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->data[0] = 0; /* padding */ 1110fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont } else 1111fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->message_id = PNS_PIPE_DATA; 111202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 111314ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont err = pn_skb_send(sk, skb, NULL); 1114e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont 1115e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont if (err && pn_flow_safe(pn->tx_fc)) 1116e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont atomic_inc(&pn->tx_credits); 1117e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont return err; 1118e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont 111902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 112002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 11219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 11229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len) 11239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 11249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1125b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont struct sk_buff *skb; 11269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont long timeo; 11279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags = msg->msg_flags; 11289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err, done; 11299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1130bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04cSasha Levin if (len > USHRT_MAX) 1131bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04cSasha Levin return -EMSGSIZE; 1132bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04cSasha Levin 113382ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL| 113482ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont MSG_CMSG_COMPAT)) || 113582ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont !(msg->msg_flags & MSG_EOR)) 11369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 11379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1138b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, 1139b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont flags & MSG_DONTWAIT, &err); 1140b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont if (!skb) 114102ac3268a581639af241c254579160909373e12cRémi Denis-Courmont return err; 1142b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont 1143638be344593b66ccca6802c6076a5b3d9200829dRémi Denis-Courmont skb_reserve(skb, MAX_PHONET_HEADER + 3 + pn->aligned); 1144b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); 1145b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont if (err < 0) 1146b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont goto outfree; 1147b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont 11489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 11499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 11509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { 11519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOTCONN; 11529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) { 11559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until the pipe gets to enabled state */ 11569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdisabled: 11579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sk_stream_wait_connect(sk, &timeo); 11589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 11599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_CLOSE_WAIT) { 11629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 11639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 11679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until flow control allows TX */ 1169be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = atomic_read(&pn->tx_credits); 11709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (!done) { 11719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont DEFINE_WAIT(wait); 11729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!timeo) { 11749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EAGAIN; 11759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (signal_pending(current)) { 11789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_intr_errno(timeo); 11799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 118243815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet prepare_to_wait(sk_sleep(sk), &wait, 11839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont TASK_INTERRUPTIBLE); 1184be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); 118543815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet finish_wait(sk_sleep(sk), &wait); 11869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) 11889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto disabled; 11899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 119102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = pipe_skb_send(sk, skb); 11929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err >= 0) 11939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = len; /* success! */ 11949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = NULL; 11959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 11969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1197b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmontoutfree: 11989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 11999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 12009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 12019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 120202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_writeable(struct sock *sk) 120302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 120402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 120502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1206be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return atomic_read(&pn->tx_credits); 120702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 120802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 120902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_write(struct sock *sk, struct sk_buff *skb) 121002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 121102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *rskb, *fs; 121202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int flen = 0; 121302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1214fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont if (pep_sk(sk)->aligned) 1215fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont return pipe_skb_send(sk, skb); 1216fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont 121702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); 121802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!rskb) { 121902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont kfree_skb(skb); 122002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOMEM; 122102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 122202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_shinfo(rskb)->frag_list = skb; 122302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->len += skb->len; 122402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->data_len += rskb->len; 122502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->truesize += rskb->len; 122602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 122702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont /* Avoid nested fragments */ 12285c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_walk_frags(skb, fs) 122902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont flen += fs->len; 123002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->next = skb_shinfo(skb)->frag_list; 12315c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_frag_list_init(skb); 123202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->len -= flen; 123302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->data_len -= flen; 123402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->truesize -= flen; 123502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 123602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reserve(rskb, MAX_PHONET_HEADER + 3); 123702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return pipe_skb_send(sk, rskb); 123802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 123902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 124002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstruct sk_buff *pep_read(struct sock *sk) 124102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 124202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); 124302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 124402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 124544c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pipe_grant_credits(sk, GFP_ATOMIC); 124602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return skb; 124702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 124802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 12499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_recvmsg(struct kiocb *iocb, struct sock *sk, 12509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len, int noblock, 12519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags, int *addr_len) 12529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 12539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 12549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err; 12559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 125682ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL| 125782ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont MSG_NOSIGNAL|MSG_CMSG_COMPAT)) 125882ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont return -EOPNOTSUPP; 125982ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont 12609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) 12619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOTCONN; 12629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1263c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) { 1264c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont /* Dequeue and acknowledge control request */ 1265c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1266c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 126782ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if (flags & MSG_PEEK) 126882ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont return -EOPNOTSUPP; 1269c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb = skb_dequeue(&pn->ctrlreq_queue); 1270c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (skb) { 1271c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, 1272c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont GFP_KERNEL); 1273c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont msg->msg_flags |= MSG_OOB; 1274c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto copy; 1275c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 1276c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (flags & MSG_OOB) 1277c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont return -EINVAL; 1278c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 1279c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 12809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = skb_recv_datagram(sk, flags, noblock, &err); 12819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 12829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb == NULL) { 12839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT) 12849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 12859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 12869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 12879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 129044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pipe_grant_credits(sk, GFP_KERNEL); 12919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1292c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontcopy: 12939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_EOR; 12949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb->len > len) 12959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_TRUNC; 12969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 12979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont len = skb->len; 12989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); 13009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 13019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = (flags & MSG_TRUNC) ? skb->len : len; 13029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_free_datagram(sk, skb); 13049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 13059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_unhash(struct sock *sk) 13089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 13109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *skparent = NULL; 13119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 1313b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 1314297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (pn->listener != NULL) { 13159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skparent = pn->listener; 1316297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->listener = NULL; 13179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn = pep_sk(skparent); 13207dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont lock_sock(skparent); 13217dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont sk_del_node_init(sk); 13227dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont sk = skparent; 13239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 1324297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 13259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Unhash a listening sock only when it is closed 13269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * and all of its active connected pipes are closed. */ 13279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hlist_empty(&pn->hlist)) 13289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_sock_unhash(&pn->pn_sk.sk); 13299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skparent) 13329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_put(skparent); 13339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct proto pep_proto = { 13369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .close = pep_sock_close, 13379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .accept = pep_sock_accept, 1338b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi .connect = pep_sock_connect, 13399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ioctl = pep_ioctl, 13409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .init = pep_init, 134102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .setsockopt = pep_setsockopt, 134202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .getsockopt = pep_getsockopt, 13439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sendmsg = pep_sendmsg, 13449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .recvmsg = pep_recvmsg, 13459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .backlog_rcv = pep_do_rcv, 13469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .hash = pn_sock_hash, 13479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .unhash = pep_sock_unhash, 13489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .get_port = pn_sock_get_port, 13499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .obj_size = sizeof(struct pep_sock), 13509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .owner = THIS_MODULE, 13519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .name = "PNPIPE", 13529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 13539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct phonet_protocol pep_pn_proto = { 13559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ops = &phonet_stream_ops, 13569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .prot = &pep_proto, 13579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sock_type = SOCK_SEQPACKET, 13589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 13599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int __init pep_register(void) 13619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return phonet_proto_register(PN_PROTO_PIPE, &pep_pn_proto); 13639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void __exit pep_unregister(void) 13669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont phonet_proto_unregister(PN_PROTO_PIPE, &pep_pn_proto); 13689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_init(pep_register); 13719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_exit(pep_unregister); 13729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_AUTHOR("Remi Denis-Courmont, Nokia"); 13739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_DESCRIPTION("Phonet pipe protocol"); 13749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_LICENSE("GPL"); 13759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_ALIAS_NET_PF_PROTO(PF_PHONET, PN_PROTO_PIPE); 1376