source: G950F DSE4
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / net / mptcp / mptcp_ndiffports.c
CommitLineData
1cac41cb
MB
1#include <linux/module.h>
2
3#include <net/mptcp.h>
4#include <net/mptcp_v4.h>
5
6#if IS_ENABLED(CONFIG_IPV6)
7#include <net/mptcp_v6.h>
8#endif
9
10struct ndiffports_priv {
11 /* Worker struct for subflow establishment */
12 struct work_struct subflow_work;
13
14 struct mptcp_cb *mpcb;
15};
16
17static int num_subflows __read_mostly = 2;
18module_param(num_subflows, int, 0644);
19MODULE_PARM_DESC(num_subflows, "choose the number of subflows per MPTCP connection");
20
21/**
22 * Create all new subflows, by doing calls to mptcp_initX_subsockets
23 *
24 * This function uses a goto next_subflow, to allow releasing the lock between
25 * new subflows and giving other processes a chance to do some work on the
26 * socket and potentially finishing the communication.
27 **/
28static void create_subflow_worker(struct work_struct *work)
29{
30 const struct ndiffports_priv *pm_priv = container_of(work,
31 struct ndiffports_priv,
32 subflow_work);
33 struct mptcp_cb *mpcb = pm_priv->mpcb;
34 struct sock *meta_sk = mpcb->meta_sk;
35 int iter = 0;
36
37next_subflow:
38 if (iter) {
39 release_sock(meta_sk);
40 mutex_unlock(&mpcb->mpcb_mutex);
41
42 cond_resched();
43 }
44 mutex_lock(&mpcb->mpcb_mutex);
45 lock_sock_nested(meta_sk, SINGLE_DEPTH_NESTING);
46
47 iter++;
48
49 if (sock_flag(meta_sk, SOCK_DEAD))
50 goto exit;
51
52 if (mpcb->master_sk &&
53 !tcp_sk(mpcb->master_sk)->mptcp->fully_established)
54 goto exit;
55
56 if (num_subflows > iter && num_subflows > mpcb->cnt_subflows) {
57 if (meta_sk->sk_family == AF_INET ||
58 mptcp_v6_is_v4_mapped(meta_sk)) {
59 struct mptcp_loc4 loc;
60 struct mptcp_rem4 rem;
61
62 loc.addr.s_addr = inet_sk(meta_sk)->inet_saddr;
63 loc.loc4_id = 0;
64 loc.low_prio = 0;
65
66 rem.addr.s_addr = inet_sk(meta_sk)->inet_daddr;
67 rem.port = inet_sk(meta_sk)->inet_dport;
68 rem.rem4_id = 0; /* Default 0 */
69
70 mptcp_init4_subsockets(meta_sk, &loc, &rem);
71 } else {
72#if IS_ENABLED(CONFIG_IPV6)
73 struct mptcp_loc6 loc;
74 struct mptcp_rem6 rem;
75
76 loc.addr = inet6_sk(meta_sk)->saddr;
77 loc.loc6_id = 0;
78 loc.low_prio = 0;
79
80 rem.addr = meta_sk->sk_v6_daddr;
81 rem.port = inet_sk(meta_sk)->inet_dport;
82 rem.rem6_id = 0; /* Default 0 */
83
84 mptcp_init6_subsockets(meta_sk, &loc, &rem);
85#endif
86 }
87 goto next_subflow;
88 }
89
90exit:
91 release_sock(meta_sk);
92 mutex_unlock(&mpcb->mpcb_mutex);
93 sock_put(meta_sk);
94}
95
96static void ndiffports_new_session(const struct sock *meta_sk)
97{
98 struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb;
99 struct ndiffports_priv *fmp = (struct ndiffports_priv *)&mpcb->mptcp_pm[0];
100
101 /* Initialize workqueue-struct */
102 INIT_WORK(&fmp->subflow_work, create_subflow_worker);
103 fmp->mpcb = mpcb;
104}
105
106static void ndiffports_create_subflows(struct sock *meta_sk)
107{
108 const struct mptcp_cb *mpcb = tcp_sk(meta_sk)->mpcb;
109 struct ndiffports_priv *pm_priv = (struct ndiffports_priv *)&mpcb->mptcp_pm[0];
110
111 if (mpcb->infinite_mapping_snd || mpcb->infinite_mapping_rcv ||
112 mpcb->send_infinite_mapping ||
113 mpcb->server_side || sock_flag(meta_sk, SOCK_DEAD))
114 return;
115
116 if (!work_pending(&pm_priv->subflow_work)) {
117 sock_hold(meta_sk);
118 queue_work(mptcp_wq, &pm_priv->subflow_work);
119 }
120}
121
122static int ndiffports_get_local_id(sa_family_t family, union inet_addr *addr,
123 struct net *net, bool *low_prio)
124{
125 return 0;
126}
127
128static struct mptcp_pm_ops ndiffports __read_mostly = {
129 .new_session = ndiffports_new_session,
130 .fully_established = ndiffports_create_subflows,
131 .get_local_id = ndiffports_get_local_id,
132 .name = "ndiffports",
133 .owner = THIS_MODULE,
134};
135
136/* General initialization of MPTCP_PM */
137static int __init ndiffports_register(void)
138{
139 BUILD_BUG_ON(sizeof(struct ndiffports_priv) > MPTCP_PM_SIZE);
140
141 if (mptcp_register_path_manager(&ndiffports))
142 goto exit;
143
144 return 0;
145
146exit:
147 return -1;
148}
149
150static void ndiffports_unregister(void)
151{
152 mptcp_unregister_path_manager(&ndiffports);
153}
154
155module_init(ndiffports_register);
156module_exit(ndiffports_unregister);
157
158MODULE_AUTHOR("Christoph Paasch");
159MODULE_LICENSE("GPL");
160MODULE_DESCRIPTION("NDIFF-PORTS MPTCP");
161MODULE_VERSION("0.88");