pep.c revision bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04c
19641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* 29641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * File: pep.c 39641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 49641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Phonet pipe protocol end point socket 59641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 69641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Copyright (C) 2008 Nokia Corporation. 79641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 89641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> 99641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * This program is free software; you can redistribute it and/or 119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * modify it under the terms of the GNU General Public License 129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * version 2 as published by the Free Software Foundation. 139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * This program is distributed in the hope that it will be useful, but 159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * WITHOUT ANY WARRANTY; without even the implied warranty of 169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 179641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * General Public License for more details. 189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * You should have received a copy of the GNU General Public License 209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * along with this program; if not, write to the Free Software 219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * 02110-1301 USA 239641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/kernel.h> 265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/socket.h> 289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/sock.h> 299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <net/tcp_states.h> 309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <asm/ioctls.h> 319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont#include <linux/phonet.h> 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", 2769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont (unsigned)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", 3089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont (unsigned)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 err = skb->len; 466c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_tail(queue, skb); 467c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 468c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont sk->sk_data_ready(sk, err); 4690ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont return NET_RX_SUCCESS; 4709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Destroy connected sock. */ 4739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pipe_destruct(struct sock *sk) 4749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 475c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 476c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 4779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_queue_purge(&sk->sk_receive_queue); 478c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_purge(&pn->ctrlreq_queue); 4799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 4809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 4818f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmontstatic u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) 4828f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont{ 4838f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont unsigned i; 4848f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 final_fc = PN_NO_FLOW_CONTROL; 4858f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 4868f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont for (i = 0; i < n; i++) { 4878f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 fc = fcs[i]; 4888f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 4898f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (fc > final_fc && fc < PN_MAX_FLOW_CONTROL) 4908f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont final_fc = fc; 4918f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 4928f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return final_fc; 4938f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont} 4948f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 495b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvistatic int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) 496b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi{ 497b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 4988f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont struct pnpipehdr *hdr; 4998f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 n_sb; 5008f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5018f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (!pskb_pull(skb, sizeof(*hdr) + 4)) 5028f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return -EINVAL; 5038f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5048f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont hdr = pnp_hdr(skb); 505297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (hdr->error_code != PN_PIPE_NO_ERROR) 506297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return -ECONNREFUSED; 5078f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5088f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont /* Parse sub-blocks */ 5098f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont n_sb = hdr->data[4]; 5108f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont while (n_sb > 0) { 5118f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont u8 type, buf[6], len = sizeof(buf); 5128f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 5138f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5148f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (data == NULL) 5158f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont return -EINVAL; 5168f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5178f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont switch (type) { 5188f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont case PN_PIPE_SB_REQUIRED_FC_TX: 5198f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (len < 2 || len < data[0]) 5208f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5218f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont pn->tx_fc = pipe_negotiate_fc(data + 2, len - 2); 5228f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5238f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5248f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont case PN_PIPE_SB_PREFERRED_FC_RX: 5258f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont if (len < 2 || len < data[0]) 5268f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5278f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont pn->rx_fc = pipe_negotiate_fc(data + 2, len - 2); 5288f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont break; 5298f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont 5308f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 5318f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont n_sb--; 5328f44fcc72a454c5eb7cbc138bd53f0963f23e87fRémi Denis-Courmont } 533b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 53444c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont return pipe_handler_send_created_ind(sk); 535b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi} 536297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 537bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharmastatic int pep_enableresp_rcv(struct sock *sk, struct sk_buff *skb) 538bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma{ 539bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma struct pnpipehdr *hdr = pnp_hdr(skb); 540bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 541bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (hdr->error_code != PN_PIPE_NO_ERROR) 542bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return -ECONNREFUSED; 543bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 544bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return pep_indicate(sk, PNS_PIPE_ENABLED_IND, 0 /* sub-blocks */, 545bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma NULL, 0, GFP_ATOMIC); 546bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 547bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma} 548bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 549bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharmastatic void pipe_start_flow_control(struct sock *sk) 550bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma{ 551bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma struct pep_sock *pn = pep_sk(sk); 552bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 553bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (!pn_flow_safe(pn->tx_fc)) { 554bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma atomic_set(&pn->tx_credits, 1); 555bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_write_space(sk); 556bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma } 557bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pipe_grant_credits(sk, GFP_ATOMIC); 558bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma} 559bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 560297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont/* Queue an skb to an actively connected sock. 561297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont * Socket lock must be held. */ 562297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmontstatic int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) 563297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont{ 564297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 565297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont struct pnpipehdr *hdr = pnp_hdr(skb); 566297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont int err = NET_RX_SUCCESS; 567297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 568297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont switch (hdr->message_id) { 569297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PIPE_ALIGNED_DATA: 570297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont __skb_pull(skb, 1); 571297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* fall through */ 572297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PIPE_DATA: 573297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont __skb_pull(skb, 3); /* Pipe data header */ 574297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!pn_flow_safe(pn->rx_fc)) { 575297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = sock_queue_rcv_skb(sk, skb); 576297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!err) 577297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return NET_RX_SUCCESS; 578297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = NET_RX_DROP; 579297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 580297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 581297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 582297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (pn->rx_credits == 0) { 583297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont atomic_inc(&sk->sk_drops); 584297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = NET_RX_DROP; 585297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 586297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 587297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->rx_credits--; 588297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont skb->dev = NULL; 589297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont skb_set_owner_r(skb, sk); 590297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = skb->len; 591297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont skb_queue_tail(&sk->sk_receive_queue, skb); 592297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 593297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_data_ready(sk, err); 594297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return NET_RX_SUCCESS; 595297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 596297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PEP_CONNECT_RESP: 597297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (sk->sk_state != TCP_SYN_SENT) 598297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 599297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 600297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_state_change(sk); 601297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (pep_connresp_rcv(sk, skb)) { 602297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_state = TCP_CLOSE_WAIT; 603297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 604297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 605bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (pn->init_enable == PN_PIPE_DISABLE) 606bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_SYN_RECV; 607bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else { 608bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_ESTABLISHED; 609bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pipe_start_flow_control(sk); 610bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma } 611bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 612297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 613bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNS_PEP_ENABLE_RESP: 614bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (sk->sk_state != TCP_SYN_SENT) 615bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 616bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 617bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (pep_enableresp_rcv(sk, skb)) { 618bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_CLOSE_WAIT; 619bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 620297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 621bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 622bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_ESTABLISHED; 623bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pipe_start_flow_control(sk); 624297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 625297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 626297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PEP_DISCONNECT_RESP: 627297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* sock should already be dead, nothing to do */ 628297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 629297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 630297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont case PNS_PEP_STATUS_IND: 631297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pipe_rcv_status(sk, skb); 632297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont break; 633297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 634297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont kfree_skb(skb); 635297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return err; 636297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont} 637b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 6389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* Listening sock must be locked */ 6399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct sock *pep_find_pipe(const struct hlist_head *hlist, 6409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont const struct sockaddr_pn *dst, 6419641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle) 6429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct hlist_node *node; 6449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 6459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u16 dobj = pn_sockaddr_get_object(dst); 6469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_for_each(sknode, node, hlist) { 6489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pnnode = pep_sk(sknode); 6499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Ports match, but addresses might not: */ 6519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pn_sk.sobject != dobj) 6529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 6539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pnnode->pipe_handle != pipe_handle) 6549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 6559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode->sk_state == TCP_CLOSE_WAIT) 6569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont continue; 6579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sknode); 6599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sknode; 6609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 6619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return NULL; 6629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 6639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* 6659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Deliver an skb to a listening sock. 6669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * Socket lock must be held. 6679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * We then queue the skb to the right connected sock (if any). 6689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont */ 6699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_do_rcv(struct sock *sk, struct sk_buff *skb) 6709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 6719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 6729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *sknode; 6732ddc1ac1b9f00096869a48b97c28de72386200d2Rémi Denis-Courmont struct pnpipehdr *hdr; 6749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sockaddr_pn dst; 6759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont u8 pipe_handle; 6769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr))) 6789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 6799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont hdr = pnp_hdr(skb); 6819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 6829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (pipe_handle == PN_PIPE_INVALID_HANDLE) 6839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto drop; 6849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 6869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Look for an existing pipe handle */ 6889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle); 6899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sknode) 6909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return sk_receive_skb(sknode, skb, 1); 6919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 6929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (hdr->message_id) { 6939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CONNECT_REQ: 694f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (sk->sk_state != TCP_LISTEN || sk_acceptq_is_full(sk)) { 695f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, 696f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont GFP_ATOMIC); 697f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 698f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 699f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont skb_queue_head(&sk->sk_receive_queue, skb); 700f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk_acceptq_added(sk); 701f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!sock_flag(sk, SOCK_DEAD)) 702f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk->sk_data_ready(sk, 0); 703f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont return NET_RX_SUCCESS; 7049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISCONNECT_REQ: 7069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 7079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 7089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_CTRL_REQ: 710c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC); 7119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont break; 7129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_RESET_REQ: 7149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_ENABLE_REQ: 7159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case PNS_PEP_DISABLE_REQ: 7169641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* invalid handle is not even allowed here! */ 7170ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont break; 718297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 719297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont default: 720297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if ((1 << sk->sk_state) 721297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont & ~(TCPF_CLOSE|TCPF_LISTEN|TCPF_CLOSE_WAIT)) 722297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* actively connected socket */ 723297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return pipe_handler_do_rcv(sk, skb); 7249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 7259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdrop: 7269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 7270ebbf318635bf354bdb046419dd10e9a00667f37Rémi Denis-Courmont return NET_RX_SUCCESS; 7289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7306482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmontstatic int pipe_do_remove(struct sock *sk) 7316482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont{ 7326482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 7336482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct pnpipehdr *ph; 7346482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont struct sk_buff *skb; 7356482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 73644c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont skb = pep_alloc_skb(sk, NULL, 0, GFP_KERNEL); 7376482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont if (!skb) 7386482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont return -ENOMEM; 7396482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 7406482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph = pnp_hdr(skb); 7416482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->utid = 0; 7426482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->message_id = PNS_PIPE_REMOVE_REQ; 7436482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 7446482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont ph->data[0] = PAD; 74514ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont return pn_skb_send(sk, skb, NULL); 7466482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont} 7476482f554e2b9cbe733d63124765104f29cf0c9adRémi Denis-Courmont 7489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont/* associated socket ceases to exist */ 7499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_close(struct sock *sk, long timeout) 7509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 7519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 75202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int ifindex = 0; 7539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 754e513480e28cdfd868755f05c1a654fcfcee58070Rémi Denis-Courmont sock_hold(sk); /* keep a reference after sk_common_release() */ 7559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_common_release(sk); 7569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 7579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 758f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { 759297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (sk->sk_backlog_rcv == pipe_do_rcv) 760297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont /* Forcefully remove dangling Phonet pipe */ 761297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pipe_do_remove(sk); 762297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont else 763297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, 764297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont NULL, 0); 7652feb61816f7f0be57f4bc61137555e9a8cb4f322Rémi Denis-Courmont } 766f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk->sk_state = TCP_CLOSE; 767b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 76802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ifindex = pn->ifindex; 76902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 7709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 77102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 77202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (ifindex) 77302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 774e513480e28cdfd868755f05c1a654fcfcee58070Rémi Denis-Courmont sock_put(sk); 7759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 7769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 777f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmontstatic struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) 7789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 779f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk), *newpn; 780f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct sock *newsk = NULL; 781f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct sk_buff *skb; 782f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct pnpipehdr *hdr; 783f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont struct sockaddr_pn dst, src; 784f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont int err; 785f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u16 peer_type; 786f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u8 pipe_handle, enabled, n_sb; 787f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u8 aligned = 0; 7889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 789f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp); 790f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!skb) 791f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont return NULL; 7929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 793f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont lock_sock(sk); 794f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (sk->sk_state != TCP_LISTEN) { 795f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = -EINVAL; 796f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 7979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 798f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk_acceptq_removed(sk); 7999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 800f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = -EPROTO; 801f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) 802f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 8039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 804f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont hdr = pnp_hdr(skb); 805f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pipe_handle = hdr->pipe_handle; 806f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont switch (hdr->state_after_connect) { 807f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_DISABLE: 808f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont enabled = 0; 809f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 810f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_ENABLE: 811f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont enabled = 1; 812f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 813f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont default: 814f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM, 815f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont GFP_KERNEL); 816f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 817f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 818f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont peer_type = hdr->other_pep_type << 8; 8199641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 820f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont /* Parse sub-blocks (options) */ 821f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont n_sb = hdr->data[4]; 822f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont while (n_sb > 0) { 823f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont u8 type, buf[1], len = sizeof(buf); 824f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont const u8 *data = pep_get_sb(skb, &type, &len, buf); 8259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 826f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (data == NULL) 827f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 828f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont switch (type) { 829f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE: 830f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (len < 1) 831f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 832f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont peer_type = (peer_type & 0xff00) | data[0]; 833f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 834f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont case PN_PIPE_SB_ALIGNED_DATA: 835f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont aligned = data[0] != 0; 836f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont break; 837f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 838f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont n_sb--; 839f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 8409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 841f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont /* Check for duplicate pipe handle */ 842f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk = pep_find_pipe(&pn->hlist, &dst, pipe_handle); 843f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (unlikely(newsk)) { 844f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont __sock_put(newsk); 8459641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont newsk = NULL; 846f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_KERNEL); 847f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 8489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 8499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 850f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont /* Create a new to-be-accepted sock */ 851f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot); 852f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (!newsk) { 853f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pep_reject_conn(sk, skb, PN_PIPE_ERR_OVERLOAD, GFP_KERNEL); 854f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = -ENOBUFS; 855f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 856f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 857f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont 858f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sock_init_data(NULL, newsk); 859f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_state = TCP_SYN_RECV; 860f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_backlog_rcv = pipe_do_rcv; 861f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_protocol = sk->sk_protocol; 862f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk->sk_destruct = pipe_destruct; 863f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont 864f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn = pep_sk(newsk); 865f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pn_skb_get_dst_sockaddr(skb, &dst); 866f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont pn_skb_get_src_sockaddr(skb, &src); 867f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); 868f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pn_sk.dobject = pn_sockaddr_get_object(&src); 869f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst); 8709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_hold(sk); 871f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->listener = sk; 872f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont skb_queue_head_init(&newpn->ctrlreq_queue); 873f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->pipe_handle = pipe_handle; 874f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont atomic_set(&newpn->tx_credits, 0); 875f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->ifindex = 0; 876f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->peer_type = peer_type; 877f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->rx_credits = 0; 878f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 879f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->init_enable = enabled; 880f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newpn->aligned = aligned; 8819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 882f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont err = pep_accept_conn(newsk, skb); 883f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont if (err) { 884f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sock_put(newsk); 885f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont newsk = NULL; 886f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont goto drop; 887f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont } 8889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sk_add_node(newsk, &pn->hlist); 889f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmontdrop: 8909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 891f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont kfree_skb(skb); 8929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont *errp = err; 8939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return newsk; 8949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 8959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 896b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvistatic int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) 897b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi{ 898b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi struct pep_sock *pn = pep_sk(sk); 899297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont int err; 90044c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; 901b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 902bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (pn->pipe_handle == PN_PIPE_INVALID_HANDLE) 903bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ 904bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 905297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, 906bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->init_enable, data, 4); 907297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (err) { 908297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 909297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return err; 910297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont } 911bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 912297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont sk->sk_state = TCP_SYN_SENT; 913bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 914bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return 0; 915bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma} 916bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 917bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharmastatic int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len) 918bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma{ 919bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma int err; 920bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 921bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma err = pipe_handler_request(sk, PNS_PEP_ENABLE_REQ, PAD, 922bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma NULL, 0); 923bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (err) 924bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return err; 925bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 926bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma sk->sk_state = TCP_SYN_SENT; 927bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 928297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont return 0; 929b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi} 930b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 9319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) 9329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 933c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int answ; 935bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma int ret = -ENOIOCTLCMD; 9369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont switch (cmd) { 9389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont case SIOCINQ: 939bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (sk->sk_state == TCP_LISTEN) { 940bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = -EINVAL; 941bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 942bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma } 9439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9449641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 945f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches if (sock_flag(sk, SOCK_URGINLINE) && 946f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches !skb_queue_empty(&pn->ctrlreq_queue)) 947c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont answ = skb_peek(&pn->ctrlreq_queue)->len; 948c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont else if (!skb_queue_empty(&sk->sk_receive_queue)) 9499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = skb_peek(&sk->sk_receive_queue)->len; 9509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 9519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont answ = 0; 9529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 953bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = put_user(answ, (int __user *)arg); 954bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 955bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 956bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case SIOCPNENABLEPIPE: 957bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma lock_sock(sk); 958bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if (sk->sk_state == TCP_SYN_SENT) 959bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = -EBUSY; 960bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else if (sk->sk_state == TCP_ESTABLISHED) 961bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = -EISCONN; 962bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else 963bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma ret = pep_sock_enable(sk, NULL, 0); 964bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma release_sock(sk); 965bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 9669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 9679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 968bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma return ret; 9699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 9719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_init(struct sock *sk) 9729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 9739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 9749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 975f7ae8d59f66154df0424fd94035c89981fed3379Rémi Denis-Courmont sk->sk_destruct = pipe_destruct; 9769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont INIT_HLIST_HEAD(&pn->hlist); 977297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->listener = NULL; 978c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb_queue_head_init(&pn->ctrlreq_queue); 979297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont atomic_set(&pn->tx_credits, 0); 980297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->ifindex = 0; 981297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->peer_type = 0; 9829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn->pipe_handle = PN_PIPE_INVALID_HANDLE; 983297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->rx_credits = 0; 984297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; 985297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->init_enable = 1; 986297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->aligned = 0; 9879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return 0; 9889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 9899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 99002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_setsockopt(struct sock *sk, int level, int optname, 991b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Miller char __user *optval, unsigned int optlen) 99202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 99302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 99402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int val = 0, err = 0; 99502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 99602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 99702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 99802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (optlen >= sizeof(int)) { 99902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(val, (int __user *) optval)) 100002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 100102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 100202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 100302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont lock_sock(sk); 100402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 100502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 100602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val && val != PNPIPE_ENCAP_IP) { 100702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EINVAL; 100802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 100902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 101002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!pn->ifindex == !val) 101102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; /* Nothing to do! */ 101202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!capable(CAP_NET_ADMIN)) { 101302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -EPERM; 101402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 101502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 101602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (val) { 101702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 101802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = gprs_attach(sk); 101902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (err > 0) { 102002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = err; 102102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 102202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 102302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } else { 102402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont pn->ifindex = 0; 102502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 102602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont gprs_detach(sk); 102702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = 0; 102802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 102902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont goto out_norel; 103003789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 1031bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNPIPE_HANDLE: 1032bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma if ((sk->sk_state == TCP_CLOSE) && 1033bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma (val >= 0) && (val < PN_PIPE_INVALID_HANDLE)) 1034bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->pipe_handle = val; 1035bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma else 1036bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma err = -EINVAL; 1037bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 1038bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 1039bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNPIPE_INITSTATE: 1040bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma pn->init_enable = !!val; 1041bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 1042bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 104302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 104402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = -ENOPROTOOPT; 104502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 104602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont release_sock(sk); 104702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 104802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontout_norel: 104902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return err; 105002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 105102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 105202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pep_getsockopt(struct sock *sk, int level, int optname, 105302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont char __user *optval, int __user *optlen) 105402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 105502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 105602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int len, val; 105702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 105802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (level != SOL_PNPIPE) 105902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 106002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (get_user(len, optlen)) 106102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 106202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 106302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont switch (optname) { 106402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont case PNPIPE_ENCAP: 106502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; 106602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont break; 10678d98efa84b790bdd62248eb0dfff17e9baf5c844Kumar Sanghvi 106803789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont case PNPIPE_IFINDEX: 106903789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont val = pn->ifindex; 107003789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont break; 107103789f26722a15ccfe6f191e9fb3d356f2f18a1eRémi Denis-Courmont 1072acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont case PNPIPE_HANDLE: 1073acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont val = pn->pipe_handle; 1074acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont if (val == PN_PIPE_INVALID_HANDLE) 1075acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont return -EINVAL; 1076acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont break; 1077acaf7df610ff3faf1778ce40d601fc3dd4a41b40Rémi Denis-Courmont 1078bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma case PNPIPE_INITSTATE: 1079bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma val = pn->init_enable; 1080bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma break; 1081bdb6e697b2a76c541960b86ab8fda88f3de1adf2Dinesh Kumar Sharma 108202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont default: 108302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOPROTOOPT; 108402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 108502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 108602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont len = min_t(unsigned int, sizeof(int), len); 108702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(len, optlen)) 108802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 108902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (put_user(val, (int __user *) optval)) 109002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -EFAULT; 109102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return 0; 109202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 109302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 109402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstatic int pipe_skb_send(struct sock *sk, struct sk_buff *skb) 109502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 109602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 109702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pnpipehdr *ph; 1098e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont int err; 109902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1100be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont if (pn_flow_safe(pn->tx_fc) && 1101be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont !atomic_add_unless(&pn->tx_credits, -1, 0)) { 1102be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont kfree_skb(skb); 1103be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return -ENOBUFS; 1104be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont } 1105be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont 1106fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont skb_push(skb, 3 + pn->aligned); 110702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reset_transport_header(skb); 110802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph = pnp_hdr(skb); 110902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->utid = 0; 1110fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont if (pn->aligned) { 1111fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->message_id = PNS_PIPE_ALIGNED_DATA; 1112fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->data[0] = 0; /* padding */ 1113fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont } else 1114fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont ph->message_id = PNS_PIPE_DATA; 111502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont ph->pipe_handle = pn->pipe_handle; 111614ba8faebcc241e4d60a4ef4a7d3fdef1c2e846fRémi Denis-Courmont err = pn_skb_send(sk, skb, NULL); 1117e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont 1118e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont if (err && pn_flow_safe(pn->tx_fc)) 1119e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont atomic_inc(&pn->tx_credits); 1120e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont return err; 1121e1a5964f0c32a75b17360cfc565d25aaedbff747Rémi Denis-Courmont 112202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 112302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 11249641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 11259641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len) 11269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 11279641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1128b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont struct sk_buff *skb; 11299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont long timeo; 11309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags = msg->msg_flags; 11319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err, done; 11329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1133bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04cSasha Levin if (len > USHRT_MAX) 1134bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04cSasha Levin return -EMSGSIZE; 1135bcf1b70ac6eb0ed8286c66e6bf37cb747cbaa04cSasha Levin 113682ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if ((msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL| 113782ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont MSG_CMSG_COMPAT)) || 113882ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont !(msg->msg_flags & MSG_EOR)) 11399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -EOPNOTSUPP; 11409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1141b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, 1142b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont flags & MSG_DONTWAIT, &err); 1143b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont if (!skb) 114402ac3268a581639af241c254579160909373e12cRémi Denis-Courmont return err; 1145b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont 1146638be344593b66ccca6802c6076a5b3d9200829dRémi Denis-Courmont skb_reserve(skb, MAX_PHONET_HEADER + 3 + pn->aligned); 1147b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); 1148b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont if (err < 0) 1149b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont goto outfree; 1150b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmont 11519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 11529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 11539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) { 11549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ENOTCONN; 11559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) { 11589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until the pipe gets to enabled state */ 11599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontdisabled: 11609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sk_stream_wait_connect(sk, &timeo); 11619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err) 11629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_CLOSE_WAIT) { 11659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 11669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont BUG_ON(sk->sk_state != TCP_ESTABLISHED); 11709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Wait until flow control allows TX */ 1172be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = atomic_read(&pn->tx_credits); 11739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont while (!done) { 11749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont DEFINE_WAIT(wait); 11759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!timeo) { 11779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -EAGAIN; 11789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11799641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11809641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (signal_pending(current)) { 11819641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = sock_intr_errno(timeo); 11829641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto out; 11839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 118543815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet prepare_to_wait(sk_sleep(sk), &wait, 11869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont TASK_INTERRUPTIBLE); 1187be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); 118843815482370c510c569fd18edb57afcb0fa8cab6Eric Dumazet finish_wait(sk_sleep(sk), &wait); 11899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 11909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state != TCP_ESTABLISHED) 11919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont goto disabled; 11929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 11939641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 119402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont err = pipe_skb_send(sk, skb); 11959641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err >= 0) 11969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = len; /* success! */ 11979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = NULL; 11989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontout: 11999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1200b1704374fd525e50c44e1a03098728f64231a6f5Rémi Denis-Courmontoutfree: 12019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont kfree_skb(skb); 12029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 12039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 12049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 120502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_writeable(struct sock *sk) 120602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 120702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 120802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1209be677730a0ccb6bedced6f65f2ba8f57a3c607baRémi Denis-Courmont return atomic_read(&pn->tx_credits); 121002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 121102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 121202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontint pep_write(struct sock *sk, struct sk_buff *skb) 121302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 121402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *rskb, *fs; 121502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont int flen = 0; 121602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 1217fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont if (pep_sk(sk)->aligned) 1218fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont return pipe_skb_send(sk, skb); 1219fea93ecef619b5779ca6984568517b1685079b05Rémi Denis-Courmont 122002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); 122102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (!rskb) { 122202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont kfree_skb(skb); 122302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return -ENOMEM; 122402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont } 122502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_shinfo(rskb)->frag_list = skb; 122602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->len += skb->len; 122702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->data_len += rskb->len; 122802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont rskb->truesize += rskb->len; 122902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 123002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont /* Avoid nested fragments */ 12315c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_walk_frags(skb, fs) 123202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont flen += fs->len; 123302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->next = skb_shinfo(skb)->frag_list; 12345c313e9a7773ec4d7ac554e841fba583f7c63abaDavid S. Miller skb_frag_list_init(skb); 123502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->len -= flen; 123602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->data_len -= flen; 123702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb->truesize -= flen; 123802a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 123902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont skb_reserve(rskb, MAX_PHONET_HEADER + 3); 124002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return pipe_skb_send(sk, rskb); 124102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 124202a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 124302a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmontstruct sk_buff *pep_read(struct sock *sk) 124402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont{ 124502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); 124602a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 124702a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 124844c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pipe_grant_credits(sk, GFP_ATOMIC); 124902a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont return skb; 125002a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont} 125102a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont 12529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int pep_recvmsg(struct kiocb *iocb, struct sock *sk, 12539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct msghdr *msg, size_t len, int noblock, 12549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int flags, int *addr_len) 12559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 12569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sk_buff *skb; 12579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont int err; 12589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 125982ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if (flags & ~(MSG_OOB|MSG_PEEK|MSG_TRUNC|MSG_DONTWAIT|MSG_WAITALL| 126082ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont MSG_NOSIGNAL|MSG_CMSG_COMPAT)) 126182ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont return -EOPNOTSUPP; 126282ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont 12639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE))) 12649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return -ENOTCONN; 12659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 1266c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) { 1267c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont /* Dequeue and acknowledge control request */ 1268c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 1269c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 127082ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont if (flags & MSG_PEEK) 127182ecbcb9c6b5257929968d5b0ed536772a9b4ac5Rémi Denis-Courmont return -EOPNOTSUPP; 1272c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont skb = skb_dequeue(&pn->ctrlreq_queue); 1273c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (skb) { 1274c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR, 1275c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont GFP_KERNEL); 1276c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont msg->msg_flags |= MSG_OOB; 1277c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont goto copy; 1278c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 1279c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont if (flags & MSG_OOB) 1280c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont return -EINVAL; 1281c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont } 1282c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmont 12839641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb = skb_recv_datagram(sk, flags, noblock, &err); 12849641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 12859641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb == NULL) { 12869641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT) 12879641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = -ECONNRESET; 12889641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 12899641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 12909641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 12919641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 12929641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (sk->sk_state == TCP_ESTABLISHED) 129344c9ab16d29a50af6ed9ae084b75774570de512aRémi Denis-Courmont pipe_grant_credits(sk, GFP_KERNEL); 12949641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 1295c41bd97f815720f9404f97da0c4f4400b52c243dRémi Denis-Courmontcopy: 12969641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_EOR; 12979641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skb->len > len) 12989641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont msg->msg_flags |= MSG_TRUNC; 12999641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont else 13009641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont len = skb->len; 13019641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13029641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); 13039641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (!err) 13049641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont err = (flags & MSG_TRUNC) ? skb->len : len; 13059641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13069641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skb_free_datagram(sk, skb); 13079641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return err; 13089641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13099641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13109641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void pep_sock_unhash(struct sock *sk) 13119641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13129641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct pep_sock *pn = pep_sk(sk); 13139641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont struct sock *skparent = NULL; 13149641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13159641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont lock_sock(sk); 1316b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi 1317297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont if (pn->listener != NULL) { 13189641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont skparent = pn->listener; 1319297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont pn->listener = NULL; 13209641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13219641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13229641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn = pep_sk(skparent); 13237dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont lock_sock(skparent); 13247dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont sk_del_node_init(sk); 13257dfde179c38056b91d51e60f3d50902387f27c84Rémi Denis-Courmont sk = skparent; 13269641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont } 1327297edb6003268c1d60da8c21eb76bf39b6428213Rémi Denis-Courmont 13289641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont /* Unhash a listening sock only when it is closed 13299641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont * and all of its active connected pipes are closed. */ 13309641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (hlist_empty(&pn->hlist)) 13319641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont pn_sock_unhash(&pn->pn_sk.sk); 13329641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont release_sock(sk); 13339641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13349641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont if (skparent) 13359641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont sock_put(skparent); 13369641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13379641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13389641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct proto pep_proto = { 13399641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .close = pep_sock_close, 13409641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .accept = pep_sock_accept, 1341b3d6255388de0680a14f0907deb7b7f4fa0d25d5Kumar Sanghvi .connect = pep_sock_connect, 13429641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ioctl = pep_ioctl, 13439641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .init = pep_init, 134402a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .setsockopt = pep_setsockopt, 134502a47617cdce440f60c71a51f3a93f9f5fcc5a7aRémi Denis-Courmont .getsockopt = pep_getsockopt, 13469641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sendmsg = pep_sendmsg, 13479641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .recvmsg = pep_recvmsg, 13489641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .backlog_rcv = pep_do_rcv, 13499641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .hash = pn_sock_hash, 13509641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .unhash = pep_sock_unhash, 13519641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .get_port = pn_sock_get_port, 13529641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .obj_size = sizeof(struct pep_sock), 13539641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .owner = THIS_MODULE, 13549641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .name = "PNPIPE", 13559641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 13569641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13579641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic struct phonet_protocol pep_pn_proto = { 13589641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .ops = &phonet_stream_ops, 13599641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .prot = &pep_proto, 13609641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont .sock_type = SOCK_SEQPACKET, 13619641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont}; 13629641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13639641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic int __init pep_register(void) 13649641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13659641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont return phonet_proto_register(PN_PROTO_PIPE, &pep_pn_proto); 13669641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13679641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13689641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontstatic void __exit pep_unregister(void) 13699641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont{ 13709641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont phonet_proto_unregister(PN_PROTO_PIPE, &pep_pn_proto); 13719641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont} 13729641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmont 13739641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_init(pep_register); 13749641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-Courmontmodule_exit(pep_unregister); 13759641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_AUTHOR("Remi Denis-Courmont, Nokia"); 13769641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_DESCRIPTION("Phonet pipe protocol"); 13779641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_LICENSE("GPL"); 13789641458d3ec42def729fde64669abf07f3220cd5Rémi Denis-CourmontMODULE_ALIAS_NET_PF_PROTO(PF_PHONET, PN_PROTO_PIPE); 1379