Coverage Report

Created: 2025-10-28 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openthread/third_party/tcplp/bsdtcp/tcp_subr.c
Line
Count
Source
1
/*-
2
 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
3
 *  The Regents of the University of California.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 4. Neither the name of the University nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 *  @(#)tcp_subr.c  8.2 (Berkeley) 5/24/95
30
 */
31
32
#include <errno.h>
33
#include <stddef.h>
34
#include <string.h>
35
36
#include "../tcplp.h"
37
#include "ip.h"
38
#include "ip6.h"
39
#include "tcp.h"
40
#include "tcp_fsm.h"
41
#include "tcp_var.h"
42
#include "tcp_seq.h"
43
#include "tcp_timer.h"
44
#include "sys/queue.h"
45
#include "../lib/bitmap.h"
46
#include "../lib/cbuf.h"
47
#include "cc.h"
48
#include "tcp_fastopen.h"
49
50
#include "tcp_const.h"
51
52
static void reinitialize_tcb(struct tcpcb* tp);
53
54
/*
55
 * samkumar: This is rewritten to have the host network stack to generate the
56
 * ISN with appropriate randomness.
57
 */
58
0
tcp_seq tcp_new_isn(struct tcpcb* tp) {
59
0
  return (uint32_t) tcplp_sys_generate_isn();
60
0
}
61
62
/*
63
 * samkumar: There used to be a function, void tcp_init(void), that would
64
 * initialize global state for TCP, including a hash table to store TCBs,
65
 * allocating memory zones for sockets, and setting global configurable state.
66
 * In FreeBSD 12.0, it also makes a call to the function tcp_fastopen_init.
67
 * None of that is needed for TCPlp: TCB allocation and matching is done by
68
 * the host system and global configurable state is removed with hardcoded
69
 * values in order to save memory, for example. Thus, I've removed the function
70
 * entirely.
71
 */
72
73
/*
74
 * A subroutine which makes it easy to track TCP state changes with DTrace.
75
 * This function shouldn't be called for t_state initializations that don't
76
 * correspond to actual TCP state transitions.
77
 */
78
void
79
tcp_state_change(struct tcpcb *tp, int newstate)
80
0
{
81
#if 0
82
#if defined(KDTRACE_HOOKS)
83
  int pstate = tp->t_state;
84
#endif
85
#endif
86
0
  tcplp_sys_log("Socket %p: %s --> %s", tp, tcpstates[tp->t_state], tcpstates[newstate]);
87
0
  tp->t_state = newstate;
88
89
  // samkumar: may need to do other actions too, so call into the host
90
0
  tcplp_sys_on_state_change(tp, newstate);
91
#if 0
92
  TCP_PROBE6(state__change, NULL, tp, NULL, tp, NULL, pstate);
93
#endif
94
0
}
95
96
 /* samkumar: Based on tcp_newtcb in tcp_subr.c, and tcp_usr_attach in tcp_usrreq.c. */
97
1
void initialize_tcb(struct tcpcb* tp) {
98
1
  uint32_t ticks = tcplp_sys_get_ticks();
99
100
  /* samkumar: Clear all fields starting laddr; rest are initialized by the host. */
101
1
  memset(((uint8_t*) tp) + offsetof(struct tcpcb, laddr), 0x00, sizeof(struct tcpcb) - offsetof(struct tcpcb, laddr));
102
1
  tp->reass_fin_index = -1;
103
104
  /*
105
   * samkumar: Only New Reno congestion control is implemented at the moment,
106
   * so there's no need to record the congestion control algorithm used for
107
   * each TCB.
108
   */
109
  // CC_ALGO(tp) = CC_DEFAULT();
110
  // tp->ccv->type = IPPROTO_TCP;
111
1
  tp->ccv->ccvc.tcp = tp;
112
113
  /*
114
   * samkumar: The original code used to choose a different constant
115
   * depending on whether it's an IPv4 or IPv6 connection. In TCPlp, we
116
   * unconditionally choose the IPv6 branch.
117
   */
118
1
  tp->t_maxseg = tp->t_maxopd =
119
//#ifdef INET6
120
1
    /*isipv6 ? */V_tcp_v6mssdflt /*:*/
121
//#endif /* INET6 */
122
1
    /*V_tcp_mssdflt*/;
123
124
1
  if (V_tcp_do_rfc1323)
125
1
    tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
126
1
  if (V_tcp_do_sack)
127
1
    tp->t_flags |= TF_SACK_PERMIT;
128
1
  TAILQ_INIT(&tp->snd_holes);
129
130
  /*
131
   * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
132
   * rtt estimate.  Set rttvar so that srtt + 4 * rttvar gives
133
   * reasonable initial retransmit time.
134
   */
135
1
  tp->t_srtt = TCPTV_SRTTBASE;
136
1
  tp->t_rttvar = ((TCPTV_RTOBASE - TCPTV_SRTTBASE) << TCP_RTTVAR_SHIFT) / 4;
137
1
  tp->t_rttmin = TCPTV_MIN < 1 ? 1 : TCPTV_MIN; /* samkumar: used to be tcp_rexmit_min, which was set in tcp_init */
138
1
  tp->t_rxtcur = TCPTV_RTOBASE;
139
1
  tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
140
1
  tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
141
1
  tp->t_rcvtime = ticks;
142
143
  /* samkumar: Taken from tcp_usr_attach in tcp_usrreq.c. */
144
1
  tp->t_state = TCP6S_CLOSED;
145
146
  /* samkumar: Added to initialize the per-TCP sackhole pool. */
147
1
  tcp_sack_init(tp);
148
1
}
149
150
/* Re-initialize the TCB. */
151
static void reinitialize_tcb(struct tcpcb* tp)
152
0
{
153
0
  uint32_t ntraversed;
154
0
  lbuf_pop(&tp->sendbuf, lbuf_used_space(&tp->sendbuf), &ntraversed);
155
0
  cbuf_pop(&tp->recvbuf, cbuf_used_space(&tp->recvbuf));
156
0
  tp->accepted_from = NULL;
157
0
  initialize_tcb(tp);
158
0
}
159
160
/*
161
 * samkumar: Most of this function was no longer needed. It did things like
162
 * reference-counting for the TCB, updating host cache stats for better
163
 * starting values of, e.g., ssthresh, for new connections, freeing resources
164
 * for TCP offloading, etc. There's no host cache in TCPlp and the host system
165
 * is responsible for managing TCB memory, so much of this isn't needed. I just
166
 * kept (and adpated) the few parts of the function that appeared to be needed
167
 * for TCPlp.
168
 */
169
void
170
tcp_discardcb(struct tcpcb *tp)
171
0
{
172
0
  tcp_cancel_timers(tp);
173
174
  /* Allow the CC algorithm to clean up after itself. */
175
0
  if (CC_ALGO(tp)->cb_destroy != NULL)
176
0
    CC_ALGO(tp)->cb_destroy(tp->ccv);
177
178
0
  tcp_free_sackholes(tp);
179
180
0
  reinitialize_tcb(tp);
181
0
}
182
183
184
 /*
185
 * Attempt to close a TCP control block, marking it as dropped, and freeing
186
 * the socket if we hold the only reference.
187
 */
188
/*
189
 * samkumar: Most of this function has to do with dropping the reference to
190
 * the inpcb, freeing resources at the socket layer and marking it as
191
 * disconnected, and miscellaneous cleanup. I've rewritten this to do what is
192
 * needed for TCP.
193
 */
194
struct tcpcb *
195
tcp_close_tcb(struct tcpcb *tp)
196
0
{
197
  /* samkumar: Eliminate the TFO pending counter. */
198
  /*
199
  if (tp->t_tfo_pending) {
200
    tcp_fastopen_decrement_counter(tp->t_tfo_pending);
201
    tp->t_tfo_pending = NULL;
202
  }
203
  */
204
0
  tcp_state_change(tp, TCP6S_CLOSED); // for the print statement
205
0
  tcp_discardcb(tp);
206
  // Don't reset the TCB by calling initialize_tcb, since that overwrites the buffer contents.
207
0
  return tp;
208
0
}
209
210
/*
211
 * Create template to be used to send tcp packets on a connection.
212
 * Allocates an mbuf and fills in a skeletal tcp/ip header.  The only
213
 * use for this function is in keepalives, which use tcp_respond.
214
 */
215
/*
216
 * samkumar: I changed the signature of this function. Instead of allocating
217
 * the struct tcptemp using malloc, populating it, and then returning it, I
218
 * have the caller allocate it. This function merely populates it now.
219
 */
220
void
221
tcpip_maketemplate(struct tcpcb* tp, struct tcptemp* t)
222
0
{
223
0
  tcpip_fillheaders(tp, (void *)&t->tt_ipgen, (void *)&t->tt_t);
224
0
}
225
226
/*
227
 * Fill in the IP and TCP headers for an outgoing packet, given the tcpcb.
228
 * tcp_template used to store this data in mbufs, but we now recopy it out
229
 * of the tcpcb each time to conserve mbufs.
230
 */
231
/*
232
 * samkumar: This has a different signature from the original function in
233
 * tcp_subr.c. In particular, IP header information is filled into an
234
 * otMessageInfo rather than into a struct representing the on-wire header
235
 * format. Additionally, I have changed it to always assume IPv6; I removed the
236
 * code for IPv4.
237
 */
238
void
239
tcpip_fillheaders(struct tcpcb* tp, otMessageInfo* ip_ptr, void *tcp_ptr)
240
0
{
241
0
  struct tcphdr *th = (struct tcphdr *)tcp_ptr;
242
243
  /* Fill in the IP header */
244
245
    /* samkumar: The old IPv6 code, for reference. */
246
  // ip6 = (struct ip6_hdr *)ip_ptr;
247
  // ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
248
  //     (inp->inp_flow & IPV6_FLOWINFO_MASK);
249
  // ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
250
  //     (IPV6_VERSION & IPV6_VERSION_MASK);
251
  // ip6->ip6_nxt = IPPROTO_TCP;
252
  // ip6->ip6_plen = htons(sizeof(struct tcphdr));
253
  // ip6->ip6_src = inp->in6p_laddr;
254
  // ip6->ip6_dst = inp->in6p_faddr;
255
256
0
  memset(ip_ptr, 0x00, sizeof(otMessageInfo));
257
0
  memcpy(&ip_ptr->mSockAddr, &tp->laddr, sizeof(ip_ptr->mSockAddr));
258
0
  memcpy(&ip_ptr->mPeerAddr, &tp->faddr, sizeof(ip_ptr->mPeerAddr));
259
260
  /* Fill in the TCP header */
261
  /* samkumar: I kept the old code commented out, for reference. */
262
  //th->th_sport = inp->inp_lport;
263
  //th->th_dport = inp->inp_fport;
264
0
  th->th_sport = tp->lport;
265
0
  th->th_dport = tp->fport;
266
0
  th->th_seq = 0;
267
0
  th->th_ack = 0;
268
  // th->th_x2 = 0;
269
  // th->th_off = 5;
270
0
  th->th_off_x2 = (5 << TH_OFF_SHIFT);
271
0
  th->th_flags = 0;
272
0
  th->th_win = 0;
273
0
  th->th_urp = 0;
274
0
  th->th_sum = 0;   /* in_pseudo() is called later for ipv4 */
275
0
}
276
277
/*
278
 * Send a single message to the TCP at address specified by
279
 * the given TCP/IP header.  If m == NULL, then we make a copy
280
 * of the tcpiphdr at th and send directly to the addressed host.
281
 * This is used to force keep alive messages out using the TCP
282
 * template for a connection.  If flags are given then we send
283
 * a message back to the TCP which originated the segment th,
284
 * and discard the mbuf containing it and any other attached mbufs.
285
 *
286
 * In any case the ack and sequence number of the transmitted
287
 * segment are as specified by the parameters.
288
 *
289
 * NOTE: If m != NULL, then th must point to *inside* the mbuf.
290
 */
291
/* samkumar: Original signature was
292
void
293
tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
294
  tcp_seq ack, tcp_seq seq, int flags)
295
*/
296
/*
297
 * samkumar: Essentially all of the code had to be discarded/rewritten since I
298
 * have to send out packets by allocating buffers from the host system,
299
 * populating them, and passing them back to the host system to send out. I
300
 * simplified the code by only using the logic that was fully necessary,
301
 * eliminating the code for IPv4 packets and keeping only the code for IPv6
302
 * packets. I also removed all of the mbuf logic, instead using the logic for
303
 * using the host system's buffering (in particular, the code to reuse the
304
 * provided mbuf is no longer there).
305
 */
306
void
307
tcp_respond(struct tcpcb *tp, otInstance* instance, struct ip6_hdr* ip6gen, struct tcphdr *thgen,
308
  tcp_seq ack, tcp_seq seq, int flags)
309
42
{
310
42
  otMessage* message = tcplp_sys_new_message(instance);
311
42
  if (message == NULL) {
312
0
    return;
313
0
  }
314
42
  if (otMessageSetLength(message, sizeof(struct tcphdr)) != OT_ERROR_NONE) {
315
0
    tcplp_sys_free_message(instance, message);
316
0
    return;
317
0
  }
318
319
42
  struct tcphdr th;
320
42
  struct tcphdr* nth = &th;
321
42
  otMessageInfo ip6info;
322
42
  int win = 0;
323
42
  if (tp != NULL) {
324
0
    if (!(flags & TH_RST)) {
325
0
      win = cbuf_free_space(&tp->recvbuf);
326
0
      if (win > (long)TCP_MAXWIN << tp->rcv_scale)
327
0
        win = (long)TCP_MAXWIN << tp->rcv_scale;
328
0
    }
329
0
  }
330
42
  memset(&ip6info, 0x00, sizeof(otMessageInfo));
331
42
  memcpy(&ip6info.mSockAddr, &ip6gen->ip6_dst, sizeof(ip6info.mSockAddr));
332
42
  memcpy(&ip6info.mPeerAddr, &ip6gen->ip6_src, sizeof(ip6info.mPeerAddr));
333
42
  nth->th_sport = thgen->th_dport;
334
42
  nth->th_dport = thgen->th_sport;
335
42
  nth->th_seq = htonl(seq);
336
42
  nth->th_ack = htonl(ack);
337
  /* samkumar: original code for setting th_x2 and th_off, for reference. */
338
  // nth->th_x2 = 0;
339
  // nth->th_off = (sizeof (struct tcphdr) + optlen) >> 2;
340
42
  nth->th_off_x2 = (sizeof(struct tcphdr) >> 2) << TH_OFF_SHIFT;
341
42
  nth->th_flags = flags;
342
42
  if (tp != NULL)
343
0
    nth->th_win = htons((uint16_t) (win >> tp->rcv_scale));
344
42
  else
345
42
    nth->th_win = htons((uint16_t)win);
346
42
  nth->th_urp = 0;
347
42
  nth->th_sum = 0;
348
349
42
  otMessageWrite(message, 0, &th, sizeof(struct tcphdr));
350
351
42
  tcplp_sys_send_message(instance, message, &ip6info);
352
42
}
353
354
/*
355
 * Drop a TCP connection, reporting
356
 * the specified error.  If connection is synchronized,
357
 * then send a RST to peer.
358
 */
359
/*
360
 * samkumar: I changed the parameter "errno" to "errnum" since it caused
361
 * problems during compilation. I also the code for asserting locks,
362
 * incermenting stats, and managing the sockets layer.
363
 */
364
struct tcpcb *
365
tcp_drop(struct tcpcb *tp, int errnum)
366
0
{
367
0
  if (TCPS_HAVERCVDSYN(tp->t_state)) {
368
0
    tcp_state_change(tp, TCP6S_CLOSED);
369
0
    (void) tcplp_output(tp);
370
0
  }
371
0
  if (errnum == ETIMEDOUT && tp->t_softerror)
372
0
    errnum = tp->t_softerror;
373
0
  tp = tcp_close_tcb(tp);
374
0
  tcplp_sys_connection_lost(tp, errnum);
375
0
  return tp;
376
0
}
377
378
/*
379
 * Look-up the routing entry to the peer of this inpcb.  If no route
380
 * is found and it cannot be allocated, then return 0.  This routine
381
 * is called by TCP routines that access the rmx structure and by
382
 * tcp_mss_update to get the peer/interface MTU.
383
 */
384
/*
385
 * samkumar: In TCPlp, we don't bother with keeping track of the MTU for each
386
 * route. The MSS we choose for the 6LoWPAN/802.15.4 network is probably the
387
 * bottleneck, so we just use that. (I also removed the struct in_conninfo *
388
 * that was formerly the first argument).
389
 */
390
uint64_t
391
tcp_maxmtu6(struct tcpcb* tp, struct tcp_ifcap *cap)
392
0
{
393
0
  uint64_t maxmtu = 0;
394
395
0
  KASSERT (tp != NULL, ("tcp_maxmtu6 with NULL tcpcb pointer"));
396
0
  if (!IN6_IS_ADDR_UNSPECIFIED(&tp->faddr)) {
397
0
    maxmtu = FRAMES_PER_SEG * FRAMECAP_6LOWPAN;
398
0
  }
399
400
0
  return (maxmtu);
401
0
}