Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
68 7u83 1
#include <unistd.h>
2
#include <ctype.h>
3
#include <sys/types.h>
4
#include <sys/param.h>
5
#include <sys/time.h>
6
#include <sys/systm.h>
7
#include <vm/vm_zone.h>
8
 
9
#include <sys/malloc.h>
10
#include <machine/param.h>
11
#include <sys/mbuf.h>
12
#include <sys/protosw.h>
13
#include <sys/socket.h>
14
#include <sys/socketvar.h>
15
#include <sys/proc.h>
16
#include <net/if.h>
17
#include <net/route.h>
18
#include <netinet/in_systm.h>
19
#include <netinet/in.h>
20
#include <netinet/in_var.h>
21
#include <netinet/if_ether.h>
22
#include <netinet/ip.h>
23
#include <netinet/ip_var.h>
24
#include <netinet/in_pcb.h>
25
#include <errno.h>
26
 
27
#include <netinet/il.h>
28
#include <netinet/il_var.h>
29
 
30
struct ilpcb * il_drop(struct ilpcb *ilpcb, int errno0);
31
static struct ilpcb * il_close(struct ilpcb *ilpcb);
32
 
33
/* kernel protocol states needed */
34
static struct inpcbhead ilb;
35
static struct inpcbinfo ilbinfo;
36
 
37
u_long il_sendspace = 1024*64;
38
u_long il_recvspace = 1024*64;
39
 
40
/*
41
 * Target size of IL PCB hash tables. Must be a power of two.
42
 *
43
 * Note that this can be overridden by the kernel environment
44
 * variable net.inet.tcp.tcbhashsize
45
 */
46
#ifndef ILBHASHSIZE
47
#define ILBHASHSIZE	512
48
#endif
49
 
50
enum				/* Connection state */
51
{
52
	ILS_CLOSED,
53
	ILS_SYNCER,
54
	ILS_SYNCEE,
55
	ILS_ESTABLISHED,
56
	ILS_LISTENING,
57
	ILS_CLOSING,
58
	ILS_OPENING,		/* only for file server */
59
};
60
 
61
char	*ilstates[] = 
62
{ 
63
	"Closed",
64
	"Syncer",
65
	"Syncee",
66
	"Established",
67
	"Listening",
68
	"Closing",
69
	"Opening",		/* only for file server */
70
};
71
 
72
enum				/* Packet types */
73
{
74
	ILT_SYNC,
75
	ILT_DATA,
76
	ILT_DATAQUERY,
77
	ILT_ACK,
78
	ILT_QUERY,
79
	ILT_STATE,
80
	ILT_CLOSE
81
};
82
 
83
char	*iltype[] = 
84
{	
85
	"sync",
86
	"data",
87
	"dataquery",
88
	"ack",
89
	"query",
90
	"state",
91
	"close",
92
};
93
 
94
/*
95
 * This is the actual shape of what we allocate using the zone
96
 * allocator.  Doing it this way allows us to protect both structures
97
 * using the same generation count, and also eliminates the overhead
98
 * of allocating tcpcbs separately.  By hiding the structure here,
99
 * we avoid changing most of the rest of the code (although it needs
100
 * to be changed, eventually, for greater efficiency).
101
 */
102
#define	ALIGNMENT	32
103
#define	ALIGNM1		(ALIGNMENT - 1)
104
struct	inp_ilpcb {
105
	union {
106
		struct	inpcb inp;
107
		char	align[(sizeof(struct inpcb) + ALIGNM1) & ~ALIGNM1];
108
	} inp_tp_u;
109
	struct	ilpcb ilpcb;
110
};
111
#undef ALIGNMENT
112
#undef ALIGNM1
113
 
114
static __inline struct mbuf * il_segq_top(struct ilpcb * ilpcb)
115
{
116
  return (ilpcb->segq);
117
}
118
 
119
static __inline void il_segq_dequeue(struct ilpcb * ilpcb)
120
{
121
  struct mbuf * m = ilpcb->segq;
122
  ilpcb->segq = m->m_nextpkt;
123
  m->m_nextpkt = 0;
124
}
125
 
126
static __inline void il_segq_insert(struct ilpcb * ilpcb, struct mbuf * m, u_long seq, struct ilhdr * il)
127
{
128
  u_long pseq;
129
  struct mbuf * mp, * mq;
130
 
131
  m->m_pkthdr.header = il;
132
 
133
  mp = 0;
134
  mq = ilpcb->segq;
135
  while ( mq ) {
136
    il = mq->m_pkthdr.header;
137
    pseq = ntohl(*(u_long *)il->ilid);
138
    if( pseq > seq )
139
      break;
140
    if( pseq == seq ) { /* we already got this packet */
141
      m_freem(m);
142
      return;
143
    }
144
    mp = mq;
145
    mq = mq->m_nextpkt;
146
  }
147
 
148
  if( mp == 0 ) {
149
    m->m_nextpkt = ilpcb->segq;
150
    ilpcb->segq = m;
151
    return;
152
  }
153
  mp->m_nextpkt = m;
154
  m->m_nextpkt = mq;
155
}
156
 
157
void il_init()
158
{  
159
  LIST_INIT(&ilb);
160
  ilbinfo.listhead = &ilb;
161
  ilbinfo.hashbase = hashinit(ILBHASHSIZE, M_PCB, &ilbinfo.hashmask);
162
  ilbinfo.porthashbase = hashinit(ILBHASHSIZE, M_PCB,
163
				  &ilbinfo.porthashmask);
164
  ilbinfo.ipi_zone = zinit("ilpcb", sizeof(struct inp_ilpcb), maxsockets,
165
			   ZONE_INTERRUPT, 0);
166
}
167
 
168
/* fill in il header and cksum, ip src/dst addresses */
169
static int il_output(struct ilpcb * ilpcb, struct mbuf *m, int type, u_long seq, u_char spec)
170
{
171
  struct ilhdr * il;
172
  struct ip * ip;
173
  int illen;
174
  struct inpcb * inp;
175
  struct socket * so;
176
 
177
  /* XXX: check total size is less than IP_MAXPACKET */
178
 
179
  if( m == 0 ) {
180
    inp = ilpcb->inpcb;
181
    so = inp->inp_socket;
182
    m = m_copypacket(so->so_snd.sb_mb, M_DONTWAIT);
183
  } 
184
 
185
  /*
186
   * Calculate data length and get a mbuf
187
   * for IL and IP headers.
188
   */
189
  illen = m->m_pkthdr.len; /* size of il payload */
190
  M_PREPEND(m, sizeof(struct ip) + sizeof(struct ilhdr), M_DONTWAIT);
191
  if( m == 0 )
192
    return ENOBUFS;
193
 
194
  ip = mtod(m, struct ip *);
195
  il = (struct ilhdr *) (ip+1);
196
  bzero(ip, sizeof(*ip));
197
 
198
  ip->ip_p = IPPROTO_IL;
199
  ip->ip_src = ilpcb->inpcb->inp_laddr;
200
  ip->ip_dst = ilpcb->inpcb->inp_faddr;
201
  ip->ip_len = m->m_pkthdr.len;
202
  ip->ip_ttl = ilpcb->inpcb->inp_ip_ttl;	/* XXX */
203
  ip->ip_tos = ilpcb->inpcb->inp_ip_tos;	/* XXX */
204
 
205
  *(u_short *)il->illen = htons(illen + sizeof(struct ilhdr));
206
  il->iltype = type;
207
  il->ilspec = spec;
208
  *(u_short *)il->ilsrc = ilpcb->inpcb->inp_lport;
209
  *(u_short *)il->ildst = ilpcb->inpcb->inp_fport;
210
  if ( type != ILT_SYNC )
211
    *(u_long *)il->ilid = htonl(seq);
212
  else
213
    *(u_long *)il->ilid = htonl(ilpcb->start);
214
 
215
  if( type != ILT_ACK && type != ILT_STATE) {
216
    if( ilpcb->rxt_timer == 0 )
217
      ilpcb->rxt_timer = ilpcb->rxt_timer_cur;
218
    if( ilpcb->death_timer == 0 )
219
      ilpcb->death_timer = ilpcb->death_timer_cur;
220
  }
221
 
222
  *(u_long *)il->ilack = htonl(ilpcb->recvd);
223
  il->ilsum[0] = il->ilsum[1] = 0;
224
 
225
  /* IL checksum does not cover IP header */
226
  m->m_data += sizeof(struct ip);
227
  m->m_len  -= sizeof(struct ip);
228
  *(u_short *)il->ilsum = in_cksum(m, illen + sizeof(struct ilhdr));
229
  m->m_data -= sizeof(struct ip);
230
  m->m_len  += sizeof(struct ip);
231
 
232
  return ip_output(m, ilpcb->inpcb->inp_options, &ilpcb->inpcb->inp_route, 
233
		   ilpcb->inpcb->inp_socket->so_options & SO_DONTROUTE ,0);
234
}
235
 
236
static int il_send_empty(struct ilpcb * ilpcb, int type, u_char spec)
237
{
238
  struct mbuf * m0;
239
 
240
  MGETHDR(m0, M_DONTWAIT, MT_DATA);
241
  m0->m_len = 0;
242
  m0->m_pkthdr.len = 0;
243
  MH_ALIGN(m0, 0); /* leave space for the packet header */
244
 
245
  return il_output(ilpcb, m0, type, ilpcb->next, spec);
246
}
247
 
248
static int il_respond(struct ilpcb * ilpcb, struct ip * ip, struct ilhdr *il, int type, u_char spec)
249
{
250
  struct mbuf * m;
251
  int illen;
252
  struct ip * ip0;
253
  struct ilhdr *il0;
254
  struct route * ro;
255
  struct route sro;
256
 
257
  if( ilpcb ) {
258
    ro = & ilpcb->inpcb->inp_route;
259
  } else {
260
    ro = &sro;
261
    bzero(ro, sizeof *ro);
262
  }
263
 
264
  MGETHDR(m, M_DONTWAIT, MT_DATA);
265
  m->m_len = 0;
266
  m->m_pkthdr.len = 0;
267
  MH_ALIGN(m, 0); /* leave space for the packet header */
268
  illen = m->m_pkthdr.len; /* size of il payload */
269
  M_PREPEND(m, sizeof(struct ip) + sizeof(struct ilhdr), M_DONTWAIT);
270
  if( m == 0 )
271
    return ENOBUFS;
272
 
273
  ip0 = mtod(m, struct ip *);
274
  il0 = (struct ilhdr *) (ip0+1);
275
  bzero(ip0, sizeof(*ip0));
276
 
277
  ip0->ip_p = IPPROTO_IL;
278
  ip0->ip_src = ip->ip_dst;
279
  ip0->ip_dst = ip->ip_src;
280
  ip0->ip_ttl = ip_defttl;
281
  ip0->ip_len = sizeof(struct ip) + sizeof(struct ilhdr);
282
  *(u_short *)il0->illen = htons(illen + sizeof(struct ilhdr));
283
  il0->iltype = type;
284
  il0->ilspec = spec;
285
  bcopy(il->ilsrc, il0->ildst, 2);
286
  bcopy(il->ildst, il0->ilsrc, 2);
287
  *(u_long *)il0->ilid = 0;
288
  bcopy(il->ilid, il0->ilack, 4);
289
  il0->ilsum[0] = il0->ilsum[1] = 0;
290
 
291
  /* IL checksum does not cover IP header */
292
  m->m_data += sizeof(struct ip);
293
  m->m_len  -= sizeof(struct ip);
294
  *(u_short *)il0->ilsum = in_cksum(m, illen + sizeof(struct ilhdr));
295
  m->m_data -= sizeof(struct ip);
296
  m->m_len  += sizeof(struct ip);
297
 
298
  return ip_output(m, 0, ro, 0 ,0);
299
}
300
 
301
static struct ilpcb *
302
il_newconn(struct ilpcb * ilpcb, struct in_addr ti_dst, u_short ti_dport,
303
	   struct in_addr ti_src, u_short ti_sport)
304
{
305
  register struct ilpcb * ilpcb0;
306
  struct socket *so2, * so;
307
  struct inpcb * inp;
308
  struct sockaddr_in sin;
309
 
310
  so = ilpcb->inpcb->inp_socket;
311
  so2 = sonewconn(so, 0);
312
  if (so2 == 0) {
313
    so2 = sodropablereq(so);
314
    if (so2) {
315
      il_drop(sotoilpcb(so2), ETIMEDOUT);
316
      so2 = sonewconn(so, 0);
317
    }
318
    if (!so2)
319
      return 0;
320
  }
321
  so = so2;
322
 
323
  inp = (struct inpcb *)so->so_pcb;
324
  inp->inp_laddr = ti_dst;
325
  inp->inp_lport = ti_dport;
326
  if (in_pcbinshash(inp) != 0) {
327
				/*
328
				 * Undo the assignments above if we failed to put
329
				 * the PCB on the hash lists.
330
				 */
331
    inp->inp_laddr.s_addr = INADDR_ANY;
332
    inp->inp_lport = 0;
333
 
334
    soabort(so);
335
    return 0;
336
  }
337
 
338
  bzero((char *)&sin, sizeof(sin));
339
  sin.sin_family = AF_INET;
340
  sin.sin_len = sizeof(sin);
341
  sin.sin_addr = ti_src;
342
  sin.sin_port = ti_sport;
343
  if (in_pcbconnect(inp, (struct sockaddr *)&sin, &proc0)) {
344
    inp->inp_laddr.s_addr = INADDR_ANY;
345
    soabort(so);
346
    return 0;
347
  }
348
 
349
  ilpcb0 = intoilpcb(inp);
350
  ilpcb0->state = ILS_LISTENING;
351
 
352
  return ilpcb0;
353
}
354
 
355
/* ack processing */
356
static void il_proc_ack(struct ilpcb * ilpcb, struct socket * so, u_long ack)
357
{
358
  if( ack >= ilpcb->unacked ) {
359
    ilpcb->rxt_timer = 0;
360
    ilpcb->death_timer = 0;
361
 
362
    /* the rxt timer is not prop. to RTT */
363
    /* reset it so that the first rxt is always 1 second */
364
    ilpcb->rxt_timer_cur = 2;
365
 
366
    if( ack >= ilpcb->next )
367
      ack = ilpcb->next - 1;
368
    while (ilpcb->unacked <= ack ) {
369
      sbdroprecord(&so->so_snd);
370
      ilpcb->unacked++;
371
    }
372
    if( ilpcb->unacked != ilpcb->next ) {
373
      ilpcb->rxt_timer = ilpcb->rxt_timer_cur;
374
      ilpcb->death_timer = ilpcb->death_timer_cur; /* do we need this here? */
375
    }
376
    sowwakeup(so);
377
  }
378
}
379
 
380
static int il_proc_data(struct ilpcb * ilpcb, struct socket * so, struct mbuf * m, u_long seq, int spec)
381
{
382
  struct mbuf * m0;
383
  struct ip * ip;
384
  int hlen = sizeof(struct ip) + sizeof(struct ilhdr);
385
  struct ilhdr * il;
386
  int needack = 0;
387
 
388
  ip = mtod(m, struct ip *);
389
  il = (struct ilhdr *)(ip+1);
390
  if( seq == ilpcb->recvd + 1 ) {
391
    needack = 1;
392
    while(1) {
393
      ilpcb->recvd = seq;
394
 
395
      m->m_len -= hlen;
396
      m->m_pkthdr.len -= hlen;
397
      m->m_data += hlen;
398
      sbappendrecord(&so->so_rcv, m);
399
 
400
      if( (m0 = il_segq_top(ilpcb)) == 0 )
401
	break;
402
      ip = mtod(m0, struct ip *);
403
      il = (struct ilhdr *)(ip+1);
404
      seq = ntohl(*(u_long *)il->ilid);
405
      if( seq != ilpcb->recvd + 1 )
406
	break;
407
      il_segq_dequeue(ilpcb);
408
      m = m0;
409
    };      
410
    sorwakeup(so);
411
  } else {
412
    if( seq > ilpcb->recvd ) 
413
      il_segq_insert(ilpcb, m, seq, il);
414
    else
415
      m_freem(m);
416
  }
417
 
418
  return needack;
419
}
420
 
421
/* assume we only have one connection */
422
void il_input(struct mbuf * m, int iphlen)
423
{
424
  struct ilhdr * il;
425
  struct ilpcb * ilpcb = 0;
426
  int len, type;
427
  u_long seq, ack;
428
  struct ip * ip;
429
  struct inpcb * inp;
430
  u_short sport, dport;
431
  struct socket * so;
432
  u_char spec;
433
 
434
  /*
435
   * Strip IP options, if any; should skip this,
436
   * make available to user, and use on returned packets,
437
   * but we don't yet have a way to check the checksum
438
   * with options still present.
439
   */
440
  if (iphlen > sizeof (struct ip)) {
441
    ip_stripoptions(m, (struct mbuf *)0);
442
    iphlen = sizeof(struct ip);
443
  }
444
 
445
  /*
446
   * Get IP and IL header together in first mbuf.
447
   */
448
  ip = mtod(m, struct ip *);
449
  if (m->m_len < iphlen + sizeof(struct ilhdr)) {
450
    if ((m = m_pullup(m, iphlen + sizeof(struct ilhdr))) == 0) {
451
      return;
452
    }
453
    ip = mtod(m, struct ip *);
454
  }
455
  il = (struct ilhdr *)((caddr_t)ip + iphlen);
456
 
457
  len = ntohs(*(u_short *)il->illen);
458
  seq = ntohl(*(u_long *)il->ilid);
459
  ack = ntohl(*(u_long *)il->ilack);
460
  sport = *(u_short *)il->ilsrc;
461
  dport = *(u_short *)il->ildst;  
462
  type = il->iltype;
463
  spec = il->ilspec;
464
 
465
  inp = in_pcblookup_hash(&ilbinfo, ip->ip_src, sport, ip->ip_dst, dport, 1);
466
  if ( inp == 0 && type == ILT_SYNC )
467
    goto dropwithrest;
468
  if( inp == 0 )
469
    goto drop;
470
 
471
  ilpcb = intoilpcb(inp);
472
  if( ilpcb == 0 )
473
    goto drop;
474
 
475
  so = inp->inp_socket;
476
  if( type == ILT_QUERY ) { /* XXX: can we use the same mbuf to send? */
477
    il_send_empty(ilpcb, ILT_STATE, il->ilspec);
478
    goto drop;
479
  }  
480
 
481
 again:
482
  /* FSM transition */
483
  switch( ilpcb->state ) {
484
  case ILS_SYNCER:
485
    if( ack != ilpcb->start )
486
      goto drop;
487
    switch( type ) {
488
    case ILT_SYNC:
489
      ilpcb->unacked++;
490
      ilpcb->recvd = seq;
491
      il_send_empty(ilpcb, ILT_ACK, 0);
492
      ilpcb->state = ILS_ESTABLISHED;
493
      ilpcb->rxt_timer = 0;
494
      ilpcb->death_timer = 0;
495
      soisconnected(inp->inp_socket);
496
      break;
497
    case ILT_CLOSE:
498
      il_drop(ilpcb, ECONNREFUSED);
499
      break;
500
    }
501
    break;
502
 
503
  case ILS_LISTENING:
504
    if( type == ILT_SYNC && ack == 0 && so->so_options & SO_ACCEPTCONN ) {
505
      ilpcb = il_newconn(ilpcb, ip->ip_dst, dport, ip->ip_src, sport);
506
 
507
      ilpcb->next = ilpcb->start = random();
508
      ilpcb->unacked = ilpcb->next;
509
      ilpcb->rstart = ilpcb->recvd = seq;
510
      ilpcb->state = ILS_SYNCEE;
511
      il_send_empty(ilpcb, ILT_SYNC, 0);
512
      ilpcb->next++;
513
    } else
514
      il_respond(ilpcb, ip, il, ILT_CLOSE, 0);
515
    break;
516
 
517
  case ILS_SYNCEE:
518
    if( ack == ilpcb->start ) {      
519
      ilpcb->rxt_timer = 0;
520
      ilpcb->unacked++;
521
      ilpcb->state = ILS_ESTABLISHED;
522
      soisconnected(so);
523
      goto again;
524
      break;
525
    }
526
    if( type == ILT_SYNC && seq == ilpcb->recvd && ack == 0 )
527
      il_send_empty(ilpcb, ILT_SYNC, 0);
528
    break;
529
 
530
  case ILS_ESTABLISHED:
531
    il_proc_ack(ilpcb, so, ack);
532
    switch( type ) {
533
    case ILT_DATA:
534
      if( il_proc_data(ilpcb, so, m, seq, spec) ) 
535
	ilpcb->flags |= ILF_NEEDACK;
536
      goto done;
537
      break;
538
    case ILT_DATAQUERY:
539
      il_proc_data(ilpcb, so, m, seq, spec);
540
      il_send_empty(ilpcb, ILT_STATE, spec);
541
      goto done;
542
      break;
543
    case ILT_CLOSE:
544
      if( ack < ilpcb->next && ack >= ilpcb->start ) {
545
	if( ilpcb->recvd+1 == seq )
546
	  ilpcb->recvd = seq;
547
	il_send_empty(ilpcb, ILT_CLOSE, 0);
548
	ilpcb->state = ILS_CLOSING;
549
      }
550
      break;
551
    case ILT_STATE:
552
      if( ack < ilpcb->rxt_max ) {
553
	ilpcb->rxt_max = ilpcb->next;
554
	il_output(ilpcb, 0, ILT_DATAQUERY, ilpcb->unacked, 1);
555
      }
556
      break;
557
    case ILT_SYNC:
558
      il_send_empty(ilpcb, ILT_ACK, 0);
559
      break;
560
    }
561
    break;
562
 
563
  case	ILS_CLOSED:
564
    goto drop;
565
    break;
566
 
567
  case ILS_CLOSING:
568
    if( type == ILT_CLOSE ) {
569
      if( ilpcb->recvd+1 == seq )
570
	ilpcb->recvd = seq;
571
      il_send_empty(ilpcb, ILT_CLOSE, 0);
572
      ilpcb->state = ILS_CLOSED;
573
      il_close(ilpcb);
574
    }
575
    break;
576
  }
577
 
578
  m_freem(m);
579
 done:
580
  return;
581
 
582
 dropwithrest:
583
  il_respond(ilpcb, ip, il, ILT_CLOSE, 0);
584
 drop:
585
  m_freem(m);
586
}
587
 
588
static void il_sendseqinit(struct ilpcb * ilpcb)
589
{
590
  ilpcb->start = ilpcb->next = random();
591
  ilpcb->unacked = ilpcb->next;
592
  ilpcb->state = ILS_SYNCER;
593
  ilpcb->next++;
594
}
595
 
596
static void il_rxt_timeout(struct ilpcb * ilpcb)
597
{
598
  switch ( ilpcb->state ) {
599
  case ILS_ESTABLISHED:
600
    il_output(ilpcb, 0, ILT_DATAQUERY, ilpcb->unacked, 1);
601
    ilpcb->rxtot++;
602
    break;
603
  case ILS_SYNCER:
604
  case ILS_SYNCEE:
605
    il_send_empty(ilpcb, ILT_SYNC, 0);
606
    break;
607
  case ILS_CLOSING:
608
    il_send_empty(ilpcb, ILT_CLOSE, 0);
609
    break;
610
  }
611
  ilpcb->rxt_timer = ilpcb->rxt_timer_cur;
612
}
613
 
614
void il_ctlinput(int cmd, struct sockaddr *sa, void *vip)
615
{}
616
 
617
int  il_ctloutput(struct socket *so, struct sockopt *sopt)
618
{ return 0; }
619
 
620
void il_drain()
621
{}
622
 
623
void il_slowtimo()
624
{
625
  struct ilpcb * ilpcb;
626
  struct inpcb * inp;
627
  int s;
628
 
629
  s = splnet();
630
  for(inp = ilb.lh_first; inp; inp = inp->inp_list.le_next) {
631
    ilpcb = intoilpcb(inp);
632
    if(ilpcb->death_timer &&  --ilpcb->death_timer == 0 )
633
      il_drop(ilpcb, ETIMEDOUT);
634
 
635
    if(ilpcb->rxt_timer &&  --ilpcb->rxt_timer == 0 ) {
636
      ilpcb->rxt_timer_cur <<= 1;
637
      il_rxt_timeout(ilpcb);
638
    }
639
  }
640
  splx(s);
641
}
642
 
643
void il_fasttimo()
644
{
645
  struct ilpcb * ilpcb;
646
  struct inpcb * inp;
647
  int s;
648
 
649
  s = splnet();
650
  for(inp = ilb.lh_first; inp; inp = inp->inp_list.le_next) {
651
    ilpcb = intoilpcb(inp);
652
    if(ilpcb->flags & ILF_NEEDACK) {
653
      ilpcb->flags &= ~ILF_NEEDACK;
654
      il_send_empty(ilpcb, ILT_ACK, 0);
655
    }
656
  }
657
  splx(s);
658
}
659
 
660
static struct ilpcb * il_newilpcb(struct inpcb * inp)
661
{
662
  struct inp_ilpcb *it;
663
  register struct ilpcb *ilpcb;
664
 
665
  it = (struct inp_ilpcb *)inp;
666
  ilpcb = &it->ilpcb;
667
  bzero((char *) ilpcb, sizeof(struct ilpcb));
668
 
669
  ilpcb->state = ILS_CLOSED;
670
  ilpcb->inpcb = inp;
671
  ilpcb->rxt_timer_cur = 2;
672
  ilpcb->death_timer_cur = 20;
673
 
674
  ilpcb->inpcb = inp;	/* XXX */
675
  inp->inp_ip_ttl = ip_defttl;
676
  inp->inp_ppcb = (caddr_t)ilpcb;
677
  return (ilpcb);		/* XXX */
678
}
679
 
680
/*
681
 * Common subroutine to open a TCP connection to remote host specified
682
 * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local
683
 * port number if needed.  Call in_pcbladdr to do the routing and to choose
684
 * a local host address (interface).  If there is an existing incarnation
685
 * of the same connection in TIME-WAIT state and if the remote host was
686
 * sending CC options and if the connection duration was < MSL, then
687
 * truncate the previous TIME-WAIT state and proceed.
688
 * Initialize connection parameters and enter SYN-SENT state.
689
 */
690
static int
691
il_connect(struct ilpcb *ilpcb, struct sockaddr *nam, struct proc *p)
692
{
693
	struct inpcb *inp = ilpcb->inpcb, *oinp;
694
	struct socket *so = inp->inp_socket;
695
	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
696
	struct sockaddr_in *ifaddr;
697
	int error;
698
 
699
	if (inp->inp_lport == 0) {
700
		error = in_pcbbind(inp, (struct sockaddr *)0, p);
701
		if (error)
702
			return error;
703
	}
704
 
705
	/*
706
	 * Cannot simply call in_pcbconnect, because there might be an
707
	 * earlier incarnation of this same connection still in
708
	 * TIME_WAIT state, creating an ADDRINUSE error.
709
	 */
710
	error = in_pcbladdr(inp, nam, &ifaddr);
711
	if (error)
712
		return error;
713
	oinp = in_pcblookup_hash(inp->inp_pcbinfo,
714
	    sin->sin_addr, sin->sin_port,
715
	    inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr
716
						: ifaddr->sin_addr,
717
	    inp->inp_lport,  0);
718
	if (oinp) {
719
			return EADDRINUSE;
720
	}
721
	if (inp->inp_laddr.s_addr == INADDR_ANY)
722
		inp->inp_laddr = ifaddr->sin_addr;
723
	inp->inp_faddr = sin->sin_addr;
724
	inp->inp_fport = sin->sin_port;
725
	in_pcbrehash(inp);
726
 
727
#if 0
728
	ilpcb->t_template = tcp_template(tp);
729
	if (ilpcb->t_template == 0) {
730
		in_pcbdisconnect(inp);
731
		return ENOBUFS;
732
	}
733
#endif
734
 
735
	soisconnecting(so);
736
	il_sendseqinit(ilpcb);
737
 
738
	return 0;
739
}
740
 
741
static int il_usr_send(struct socket *so, int flags, struct mbuf * m, struct sockaddr *addr, struct mbuf *control, struct proc *p)
742
{
743
  struct ilpcb * ilpcb;
744
  struct inpcb * inp = sotoinpcb(so);
745
  int error;
746
  struct mbuf * m0;
747
 
748
  if (inp == 0) {
749
    m_freem(m);
750
    return EINVAL;
751
  }
752
  ilpcb = intoilpcb(inp);
753
 
754
  if (sbspace(&so->so_snd) < -512) {
755
    m_freem(m);
756
    error = ENOBUFS;
757
    goto out;
758
  }
759
 
760
  sbappendrecord(&so->so_snd, m);
761
  m0 = m_copypacket(m, M_DONTWAIT);
762
  error = il_output(ilpcb, m0, ILT_DATA, ilpcb->next++, 0); 
763
 
764
 out:
765
  return error;
766
}
767
 
768
static int il_usr_attach(struct socket *so, int proto, struct proc *p)
769
{
770
  int s = splnet();
771
  int error = 0;
772
  struct inpcb *inp = sotoinpcb(so);
773
  struct ilpcb *ilpcb = 0;
774
 
775
  if (inp) {
776
    error = EISCONN;
777
    goto out;
778
  }
779
 
780
  if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
781
    error = soreserve(so, il_sendspace, il_recvspace);
782
    if (error)
783
      goto out;
784
  }
785
 
786
  error = in_pcballoc(so, &ilbinfo, p);
787
 
788
  if (error)
789
    goto out;
790
 
791
  inp = sotoinpcb(so);
792
  ilpcb = il_newilpcb(inp);
793
  if (ilpcb == 0) {
794
    int nofd = so->so_state & SS_NOFDREF;	/* XXX */
795
 
796
    so->so_state &= ~SS_NOFDREF;	/* don't free the socket yet */
797
    in_pcbdetach(inp);
798
    so->so_state |= nofd;
799
    error = ENOBUFS;
800
    goto out;
801
  }
802
  ilpcb->state = ILS_CLOSED;
803
  ilpcb->segq = 0;
804
 
805
 out:
806
  splx(s);
807
  return error;
808
 
809
}
810
 
811
static int il_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
812
{
813
  int s = splnet();
814
  int error = 0;
815
  struct inpcb *inp = sotoinpcb(so);
816
  struct ilpcb *ilpcb;
817
  struct sockaddr_in *sinp;
818
 
819
  if (inp == 0) {
820
    splx(s);
821
    return EINVAL;
822
  }
823
  ilpcb = intoilpcb(inp);
824
 
825
	/*
826
	 * Must check for multicast addresses and disallow binding
827
	 * to them.
828
	 */
829
  sinp = (struct sockaddr_in *)nam;
830
  if (sinp->sin_family == AF_INET &&
831
      IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
832
    error = EAFNOSUPPORT;
833
    goto out;
834
  }
835
  error = in_pcbbind(inp, nam, p);
836
 out: splx(s); 
837
  return error; 
838
}
839
 
840
/*
841
 * Initiate connection to peer.
842
 * Create a template for use in transmissions on this connection.
843
 * Enter SYN_SENT state, and mark socket as connecting.
844
 * Start keep-alive timer, and seed output sequence space.
845
 * Send initial segment on connection.
846
 */
847
static int
848
il_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
849
{
850
  int s = splnet();
851
  int error = 0;
852
  struct inpcb *inp = sotoinpcb(so);
853
  struct ilpcb *ilpcb;
854
  struct sockaddr_in *sinp;
855
 
856
  if (inp == 0) {
857
    splx(s);
858
    return EINVAL;
859
  }
860
  ilpcb = intoilpcb(inp);
861
 
862
  /*
863
   * Must disallow TCP ``connections'' to multicast addresses.
864
   */
865
  sinp = (struct sockaddr_in *)nam;
866
  if (sinp->sin_family == AF_INET
867
      && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
868
    error = EAFNOSUPPORT;
869
    goto out;
870
  }
871
 
872
  if ((error = il_connect(ilpcb, nam, p)) != 0)
873
    goto out;
874
 
875
  error = il_send_empty(ilpcb, ILT_SYNC, 0);
876
 
877
 out: splx(s); 
878
  return error; 
879
}
880
 
881
/*
882
 * Close a TCP control block:
883
 *	discard all space held by the tcp
884
 *	discard internet protocol block
885
 *	wake up any sleepers
886
 */
887
static struct ilpcb *
888
il_close(struct ilpcb *ilpcb)
889
{
890
	register struct mbuf *q;
891
	register struct mbuf *nq;
892
	struct inpcb *inp = ilpcb->inpcb;
893
	struct socket *so = inp->inp_socket;
894
 
895
	/* free the reassembly queue, if any */
896
	for (q = ilpcb->segq; q; q = nq) {
897
		nq = q->m_nextpkt;
898
		ilpcb->segq = nq;
899
		m_freem(q);
900
	}
901
	inp->inp_ppcb = NULL;
902
	soisdisconnected(so);
903
	in_pcbdetach(inp);
904
	return ((struct ilpcb *)0);
905
}
906
 
907
/*
908
 * User issued close, and wish to trail through shutdown states:
909
 * if never received SYN, just forget it.  If got a SYN from peer,
910
 * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
911
 * If already got a FIN from peer, then almost done; go to LAST_ACK
912
 * state.  In all other cases, have already sent FIN to peer (e.g.
913
 * after PRU_SHUTDOWN), and just have to play tedious game waiting
914
 * for peer to send FIN or not respond to keep-alives, etc.
915
 * We can let the user exit from the close as soon as the FIN is acked.
916
 */
917
static struct ilpcb *
918
il_usrclosed(struct ilpcb *ilpcb)
919
{
920
 
921
	switch (ilpcb->state) {
922
	case ILS_CLOSED:
923
	case ILS_LISTENING:
924
		ilpcb->state = ILS_CLOSED;
925
		ilpcb = il_close(ilpcb);
926
		break;
927
 
928
	case ILS_SYNCER:
929
	case ILS_SYNCEE:
930
	case ILS_ESTABLISHED:
931
	  il_send_empty(ilpcb, ILT_CLOSE, 0);
932
	  ilpcb->state = ILS_CLOSING;
933
	  break;
934
 
935
	case ILS_CLOSING:
936
		break;
937
	}
938
	return (ilpcb);
939
}
940
 
941
/*
942
 * Drop a TCP connection, reporting
943
 * the specified error.  If connection is synchronized,
944
 * then send a RST to peer.
945
 */
946
struct ilpcb *
947
il_drop(ilpcb, errno0)
948
     register struct ilpcb *ilpcb;
949
     int errno0;
950
{
951
  struct socket *so = ilpcb->inpcb->inp_socket;
952
 
953
  panic("il_drop");
954
 
955
  switch(ilpcb->state) {
956
  case ILS_SYNCEE:
957
  case ILS_ESTABLISHED:
958
  case ILS_CLOSING:
959
    il_send_empty(ilpcb, ILT_CLOSE, 0);
960
  default:
961
    break;
962
  }
963
  ilpcb->state = ILS_CLOSED;
964
  so->so_error = errno0;
965
  return (il_close(ilpcb));
966
}
967
 
968
/*
969
 * Initiate (or continue) disconnect.
970
 * If embryonic state, just send reset (once).
971
 * If in ``let data drain'' option and linger null, just drop.
972
 * Otherwise (hard), mark socket disconnecting and drop
973
 * current input data; switch states based on user close, and
974
 * send segment to peer (with FIN).
975
 */
976
static struct ilpcb *
977
il_disconnect(struct ilpcb *ilpcb)
978
{
979
  struct socket *so = ilpcb->inpcb->inp_socket;
980
 
981
  soisdisconnecting(so);
982
  sbflush(&so->so_rcv);
983
  ilpcb = il_usrclosed(ilpcb);
984
 
985
  return (ilpcb);
986
}
987
 
988
 
989
/*
990
 * pru_detach() detaches the IL protocol from the socket.
991
 * If the protocol state is non-embryonic, then can't
992
 * do this directly: have to initiate a pru_disconnect(),
993
 * which may finish later; embryonic TCB's can just
994
 * be discarded here.
995
 */
996
static int
997
il_usr_detach(struct socket *so)
998
{
999
	int s = splnet();
1000
	int error = 0;
1001
	struct inpcb *inp = sotoinpcb(so);
1002
	struct ilpcb *ilpcb;
1003
 
1004
	if (inp == 0) {
1005
		splx(s);
1006
		return EINVAL;	/* XXX */
1007
	}
1008
	ilpcb = intoilpcb(inp);
1009
	ilpcb = il_disconnect(ilpcb);
1010
	splx(s);
1011
	return error;
1012
}
1013
 
1014
/*
1015
 * Mark the connection as being incapable of further output.
1016
 */
1017
static int
1018
il_usr_shutdown(struct socket *so)
1019
{
1020
	int s = splnet();
1021
	int error = 0;
1022
	struct inpcb *inp = sotoinpcb(so);
1023
	struct ilpcb *ilpcb;
1024
 
1025
  if (inp == 0) {
1026
    splx(s);
1027
    return EINVAL;
1028
  }
1029
  ilpcb = intoilpcb(inp);
1030
 
1031
  socantsendmore(so);
1032
  ilpcb = il_usrclosed(ilpcb);
1033
  splx(s); 
1034
  return error;
1035
}
1036
 
1037
/*
1038
 * Initiate disconnect from peer.
1039
 * If connection never passed embryonic stage, just drop;
1040
 * else if don't need to let data drain, then can just drop anyways,
1041
 * else have to begin TCP shutdown process: mark socket disconnecting,
1042
 * drain unread data, state switch to reflect user close, and
1043
 * send segment (e.g. FIN) to peer.  Socket will be really disconnected
1044
 * when peer sends FIN and acks ours.
1045
 *
1046
 * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
1047
 */
1048
static int
1049
il_usr_disconnect(struct socket *so)
1050
{
1051
  int s = splnet();
1052
  int error = 0;
1053
  struct inpcb *inp = sotoinpcb(so);
1054
  struct ilpcb * ilpcb;
1055
 
1056
  if (inp == 0) {
1057
    splx(s);
1058
    return EINVAL;
1059
  }
1060
  ilpcb = intoilpcb(inp);
1061
 
1062
  il_disconnect(ilpcb);
1063
  splx(s); 
1064
  return error;
1065
}
1066
 
1067
/*
1068
 * Abort the TCP.
1069
 */
1070
static int
1071
il_usr_abort(struct socket *so)
1072
{
1073
	int s = splnet();
1074
	int error = 0;
1075
	struct inpcb *inp = sotoinpcb(so);
1076
	struct ilpcb * ilpcb;
1077
 
1078
  if (inp == 0) {
1079
    splx(s);
1080
    return EINVAL;
1081
  }
1082
  ilpcb = intoilpcb(inp);
1083
 
1084
  ilpcb = il_drop(ilpcb, ECONNABORTED);
1085
  splx(s); 
1086
  return error;
1087
 
1088
}
1089
 
1090
/*
1091
 * Prepare to accept connections.
1092
 */
1093
static int
1094
il_usr_listen(struct socket *so, struct proc *p)
1095
{
1096
  int s = splnet();
1097
  int error = 0;
1098
  struct inpcb *inp = sotoinpcb(so);
1099
  struct ilpcb *ilpcb;
1100
 
1101
  if (inp == 0) {
1102
    splx(s);
1103
    return EINVAL;
1104
  }
1105
  ilpcb = intoilpcb(inp);
1106
 
1107
  if (inp->inp_lport == 0)
1108
    error = in_pcbbind(inp, (struct sockaddr *)0, p);
1109
  if (error == 0)
1110
    ilpcb->state = ILS_LISTENING;
1111
 
1112
  splx(s); 
1113
  return error;
1114
}
1115
 
1116
/*
1117
 * Accept a connection.  Essentially all the work is
1118
 * done at higher levels; just return the address
1119
 * of the peer, storing through addr.
1120
 */
1121
static int
1122
il_usr_accept(struct socket *so, struct sockaddr **nam)
1123
{
1124
  int s = splnet();
1125
  int error = 0;
1126
  struct inpcb *inp = sotoinpcb(so);
1127
  struct ilpcb * ilpcb;
1128
 
1129
  if (inp == 0) {
1130
    splx(s);
1131
    return EINVAL;
1132
  }
1133
  ilpcb = intoilpcb(inp);
1134
 
1135
  in_setpeeraddr(so, nam);
1136
  splx(s); 
1137
  return error;
1138
}
1139
 
1140
/* xxx - should be const */
1141
struct pr_usrreqs il_usrreqs = {
1142
	il_usr_abort, il_usr_accept, il_usr_attach, il_usr_bind,
1143
	il_usr_connect, pru_connect2_notsupp, in_control, il_usr_detach,
1144
	il_usr_disconnect, il_usr_listen, in_setpeeraddr, pru_rcvd_notsupp,
1145
	pru_rcvoob_notsupp, il_usr_send, pru_sense_null, il_usr_shutdown,
1146
	in_setsockaddr, sosend, soreceive, sopoll
1147
};