http://lxr.linux.no/linux+v2.6.30/net/ipv4/tcp_ipv4.c
144
145int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
146{
147 struct inet_sock *inet = inet_sk(sk);
148 struct tcp_sock *tp = tcp_sk(sk);
149 struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
150 struct rtable *rt;
151 __be32 daddr, nexthop;
152 int tmp;
153 int err;
154
155 if (addr_len < sizeof(struct sockaddr_in))
156 return -EINVAL;
157
158 if (usin->sin_family != AF_INET)
159 return -EAFNOSUPPORT;
160
161 nexthop = daddr = usin->sin_addr.s_addr;
162 if (inet->opt && inet->opt->srr) {
163 if (!daddr)
164 return -EINVAL;
165 nexthop = inet->opt->faddr;
166 }
167
168 tmp = ip_route_connect(&rt, nexthop, inet->saddr,
169 RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
170 IPPROTO_TCP,
171 inet->sport, usin->sin_port, sk, 1);
172 if (tmp < 0) {
173 if (tmp == -ENETUNREACH)
174 IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
175 return tmp;
176 }
177
178 if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
179 ip_rt_put(rt);
180 return -ENETUNREACH;
181 }
182
183 if (!inet->opt || !inet->opt->srr)
184 daddr = rt->rt_dst;
185
186 if (!inet->saddr)
187 inet->saddr = rt->rt_src;
188 inet->rcv_saddr = inet->saddr;
189
190 if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) {
191
192 tp->rx_opt.ts_recent = 0;
193 tp->rx_opt.ts_recent_stamp = 0;
194 tp->write_seq = 0;
195 }
196
197 if (tcp_death_row.sysctl_tw_recycle &&
198 !tp->rx_opt.ts_recent_stamp && rt->rt_dst == daddr) {
199 struct inet_peer *peer = rt_get_peer(rt);
200
201
202
203
204
205
206 if (peer != NULL &&
207 peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) {
208 tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
209 tp->rx_opt.ts_recent = peer->tcp_ts;
210 }
211 }
212
213 inet->dport = usin->sin_port;
214 inet->daddr = daddr;
215
216 inet_csk(sk)->icsk_ext_hdr_len = 0;
217 if (inet->opt)
218 inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
219
220 tp->rx_opt.mss_clamp = 536;
221
222
223
224
225
226
227 tcp_set_state(sk, TCP_SYN_SENT);
228 err = inet_hash_connect(&tcp_death_row, sk);
229 if (err)
230 goto failure;
231
232 err = ip_route_newports(&rt, IPPROTO_TCP,
233 inet->sport, inet->dport, sk);
234 if (err)
235 goto failure;
236
237
238 sk->sk_gso_type = SKB_GSO_TCPV4;
239 sk_setup_caps(sk, &rt->u.dst);
240
241 if (!tp->write_seq)
242 tp->write_seq = secure_tcp_sequence_number(inet->saddr,
243 inet->daddr,
244 inet->sport,
245 usin->sin_port);
246
247 inet->id = tp->write_seq ^ jiffies;
248
249 err = tcp_connect(sk);
250 rt = NULL;
251 if (err)
252 goto failure;
253
254 return 0;
255
256failure:
257
258
259
260
261 tcp_set_state(sk, TCP_CLOSE);
262 ip_rt_put(rt);
263 sk->sk_route_caps = 0;
264 inet->dport = 0;
265 return err;
266}
267
|