|
|
1.1 root 1: /*
2: * tcp_device.c
3: */
4:
5: #include "tcp.h"
6: #if NTCP
7: #include "../h/param.h"
8: #include "../h/systm.h"
9: #include "../h/stream.h"
10: #include "../h/inio.h"
11: #include "../h/ttyio.h"
12: #include "../h/ttyld.h"
13: #include "../h/buf.h"
14: #include "../h/conf.h"
15: #include "../h/dir.h"
16: #include "../h/user.h"
17: #include "../h/inet/in.h"
18: #include "../h/inet/mbuf.h"
19: #include "../h/inet/tcp.h"
20: #include "../h/inet/tcp_timer.h"
21: #include "../h/inet/tcp_seq.h"
22: #include "../h/inet/tcp_var.h"
23: #include "../h/inet/tcp_user.h"
24: #include "../h/inet/tcp_fsm.h"
25: #include "../h/inet/socket.h"
26:
27: extern int tcp_busy; /* set to discourage timers & ensuing panics */
28:
29: int nodev(), tcpdopen(), tcpdclose(), tcpdput();
30: int tcpdosrv(), tcpdisrv();
31: static struct qinit tcpdrinit = { nodev, tcpdisrv, tcpdopen, tcpdclose, 2048, 64 };
32: struct qinit tcpdwinit = { tcpdput, tcpdosrv, tcpdopen, tcpdclose, 2048,64};
33: struct streamtab tcpdinfo = { &tcpdrinit, &tcpdwinit };
34:
35: int Ntcp = NTCP; /* for netstat */
36: struct tcpcb tcpcb[NTCP];
37: struct socket tcpsocks[NTCP];
38:
39: tcpdopen(q, dev)
40: register struct queue *q;
41: dev_t dev;
42: {
43: struct socket *so;
44:
45: dev = minor(dev);
46: if(dev >= NTCP)
47: return(0);
48: so = &tcpsocks[dev];
49: if((dev&01) == 0 && (so->so_state&SS_ACTIVE) == 0)
50: return(0);
51: if(so->so_state&SS_WAITING)
52: return(0);
53: if((so->so_options&SO_ACCEPTCONN) && (so->so_state&SS_OPEN))
54: return(0);
55: if((so->so_state & (SS_ACTIVE|SS_OPEN|SS_PLEASEOPEN)) == SS_ACTIVE)
56: return(0);
57: if(q->ptr && dev&01) /* re-opening outgoing port */
58: return(0);
59: if(q->ptr)
60: return(1);
61: tcp_busy++;
62: if((so->so_state & SS_PLEASEOPEN) == 0){
63: bzero(so, sizeof(struct socket));
64: so->so_state |= SS_WAITING;
65: }
66: so->so_state |= SS_OPEN;
67: so->so_dev = dev;
68: so->so_rq = q;
69: so->so_wq = WR(q);
70: q->ptr = (caddr_t)so;
71: WR(q)->flag |= QNOENB|QBIGB;
72: WR(q)->ptr = (caddr_t)so;
73: --tcp_busy;
74: if(so->so_state & SS_PLEASEOPEN){
75: so->so_state &= ~SS_PLEASEOPEN;
76: qenable(WR(q)); /* to force out rcv wnd update */
77: }
78: return(1);
79: }
80:
81: tcpdclose(q)
82: register struct queue *q;
83: {
84: struct socket *so;
85: struct tcpcb *tp;
86:
87: so = (struct socket *)q->ptr;
88: tcp_busy++;
89: so->so_state &= ~(SS_OPEN|SS_WAITING);
90: so->so_rq = so->so_wq = (struct queue *) 0;
91: so->so_wcount = so->so_rcount = 0;
92: tp = so->so_tcpcb;
93: if(tp == 0){
94: --tcp_busy;
95: return;
96: }
97: if(tp->t_state > TCPS_LISTEN)
98: tcp_disconnect(tp);
99: else
100: tcp_close(tp);
101: --tcp_busy;
102: }
103:
104: tcpdput(q, bp)
105: register struct queue *q;
106: register struct block *bp;
107: {
108: struct socket *so;
109: int s, x;
110: register union stmsg *sp;
111: struct tcpcb *tp;
112: struct block *nbp;
113: struct foo {
114: int com;
115: struct tcpuser rep;
116: };
117: struct foo *fp;
118:
119: so = (struct socket *)q->ptr;
120: switch(bp->type){
121: case M_IOCTL:
122: sp = (union stmsg *)bp->rptr;
123: bp->type = M_IOCACK;
124: switch(sp->ioc0.com){
125: case TIOCSETP:
126: case TIOCSETN:
127: x = sp->ioc1.sb.sg_ispeed;
128: bp->wptr = bp->rptr;
129: bp->type = M_IOCACK;
130: qreply(q, bp);
131: if(x == 0)
132: tcp_putctl(OTHERQ(q), M_HANGUP);
133: return;
134: case TIOCGETP:
135: sp->ioc1.sb.sg_ispeed =
136: sp->ioc1.sb.sg_ospeed = B9600;
137: break;
138: case TCPGETADDR:
139: nbp = allocb(sizeof(struct foo));
140: if (nbp == NULL) {
141: bp->type = M_IOCNAK;
142: printf("tcpdput: out of blocks\n");
143: break;
144: }
145: nbp->type = M_IOCACK;
146: fp = (struct foo *)nbp->rptr;
147: fp->com = sp->ioc1.com;
148: fp->rep.lport = so->so_lport;
149: fp->rep.fport = so->so_fport;
150: fp->rep.laddr = so->so_laddr;
151: fp->rep.faddr = so->so_faddr;
152: nbp->wptr = nbp->rptr + sizeof(struct foo);
153: freeb(bp);
154: bp = nbp;
155: break;
156: case TCPIOHUP:
157: so->so_state |= SS_HANGUP;
158: bp->wptr = bp->rptr;
159: bp->type = M_IOCACK;
160: qreply(q, bp);
161: return;
162: default:
163: bp->type = M_IOCNAK;
164: }
165: qreply(q, bp);
166: return;
167: case M_DATA:
168: if(socantsendmore(so)){
169: freeb(bp);
170: return;
171: }
172: s = spl6();
173: so->so_delimcnt = 0;
174: so->so_wcount += BLEN(bp); /* BEFORE the putq */
175: putq(q, bp);
176: splx(s);
177: if((so->so_options&SO_ACCEPTCONN) == 0
178: && (so->so_state&SS_WAITING) == 0
179: && (tp = so->so_tcpcb)){
180: /* so as to invoke tcp_output() */
181: if(tp->t_state > TCPS_CLOSE_WAIT)
182: printf("data after CLOSE_WAIT?\n");
183: qenable(q);
184: }
185: break;
186: case M_DELIM:
187: if(so->so_options&SO_ACCEPTCONN){
188: printf("DELIM on listener\n");
189: } else if(so->so_state & SS_WAITING){
190: putq(q, bp);
191: /* to invoke tcpduser */
192: qenable(q);
193: } else {
194: /* two back to back delims constitute logical eof */
195: freeb(bp);
196: s = spl6();
197: if(socantsendmore(so)){
198: splx(s);
199: return;
200: }
201: if(++(so->so_delimcnt) > 1){
202: splx(s);
203: qenable(q);
204: } else
205: splx(s);
206: }
207: break;
208: default:
209: freeb(bp);
210: break;
211: }
212: }
213:
214: tcpdosrv(q)
215: struct queue *q;
216: {
217: register struct socket *so;
218: register struct tcpcb *tp;
219:
220: so = (struct socket *)q->ptr;
221: if (so->so_state&SS_WCLOSED)
222: return;
223: tcp_busy++;
224: if(so->so_delimcnt > 1){
225: so->so_state |= SS_WCLOSED;
226: if((tp = so->so_tcpcb) == 0){
227: printf("delimcnt but no tp\n");
228: --tcp_busy;
229: return;
230: }
231: tp = tcp_usrclosed(tp);
232: if(tp)
233: tcp_output(tp);
234: } else {
235: if((so->so_options&SO_ACCEPTCONN) == 0
236: && (so->so_state&SS_WAITING) == 0
237: && (tp = so->so_tcpcb)){
238: tcp_output(tp);
239: } else {
240: tcpduser(so);
241: }
242: }
243: --tcp_busy;
244: }
245:
246: tcpdrint(bp, so)
247: register struct block *bp;
248: struct socket *so;
249: {
250: register struct block *bp1;
251: register struct queue *q;
252:
253: q = so->so_rq;
254: if(q){
255: while(bp){
256: bp1 = bp->next;
257: so->so_rcount += bp->wptr - bp->rptr;
258: if(bp->wptr == bp->rptr)
259: freeb(bp);
260: else
261: putq(q, bp);
262: bp = bp1;
263: }
264: } else {
265: printf("tcpdrint but no so->so_rq\n");
266: bp_free(bp);
267: }
268: }
269:
270: tcpdisrv(q)
271: struct queue *q;
272: {
273: struct socket *so = (struct socket *)(q->ptr);
274: struct block *bp;
275:
276: while((q->next->flag&QFULL) == 0){
277: if(bp = getq(q)){
278: if(bp->type == M_DATA)
279: so->so_rcount -= bp->wptr - bp->rptr;
280: if(so->so_rcount < 0)
281: panic("so_rcount");
282: (*q->next->qinfo->putp)(q->next, bp);
283: } else
284: break;
285: }
286: if(q->count <= q->qinfo->lolimit)
287: qenable(OTHERQ(q)); /* update remote send window */
288: }
289:
290: /*
291: * imitation tcp_usrreq
292: */
293: tcpduser(so)
294: register struct socket *so;
295: {
296: extern struct ipif *ip_ifwithaddr();
297: struct tcpuser *tu;
298: struct block *bp, *bp1, *head;
299: register struct tcpcb *tp;
300:
301: bp = bp1 = head = NULL;
302: while(bp = getq(so->so_wq)){
303: if(bp->type != M_DATA){
304: freeb(bp);
305: } else if(bp1 == NULL){
306: bp1 = head = bp;
307: bp->next = NULL;
308: } else {
309: bp1->next = bp;
310: bp1 = bp;
311: bp->next = NULL;
312: }
313: }
314: if(head == NULL)
315: return;
316: so->so_wcount = 0;
317: bp = head;
318: if(BLEN(bp) < sizeof(struct tcpuser)){
319: /*
320: printf("tcpuser short\n");
321: */
322: bp_free(bp);
323: return;
324: }
325: tu = (struct tcpuser *)bp->rptr;
326: if(so->so_tcpcb)
327: printf("%d: tcpduser w/ tcpcb\n", so->so_dev);
328: switch(tu->code){
329: case TCPC_CONNECT:
330: if(so->so_state&SS_ACTIVE)
331: goto bad;
332: if (tu->laddr != INADDR_ANY) {
333: /* has the user has specified a legal local address? */
334: if (ip_ifwithaddr(tu->laddr) == 0)
335: goto bad;
336: } else {
337: /* pick a local address related to the destination */
338: tu->laddr = ip_hoston(tu->faddr);
339: if(tu->laddr == INADDR_ANY)
340: goto bad;
341: }
342: if(tcp_attach(so))
343: goto bad;
344: if(sobind(so, tu->laddr, tu->lport))
345: goto bad;
346: tp = so->so_tcpcb;
347: so->so_fport = tu->fport;
348: so->so_faddr = tu->faddr;
349: so->so_options = tu->param;
350: if (so->so_options & SO_KEEPALIVE)
351: tcp_timers(tp, TCPT_KEEP);
352: tp->t_template = tcp_template(tp);
353: if(tp->t_template == 0)
354: goto bad;
355: soisconnecting(so);
356: tp->t_state = TCPS_SYN_SENT;
357: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
358: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
359: tcp_sendseqinit(tp);
360: so->so_state &= ~SS_WAITING;
361: tcp_output(tp);
362: break;
363: case TCPC_LISTEN:
364: if(so->so_state&SS_ACTIVE)
365: goto bad;
366: if (tu->laddr != INADDR_ANY) {
367: /* has the user has specified a legal local address? */
368: if (ip_ifwithaddr(tu->laddr) == 0)
369: goto bad;
370: }
371: if(tcp_attach(so))
372: goto bad;
373: if(sobind(so, tu->laddr, tu->lport))
374: goto bad;
375: tp = so->so_tcpcb;
376: tp->t_state = TCPS_LISTEN;
377: so->so_options |= SO_ACCEPTCONN;
378: so->so_fport = tu->fport==0 ? TCPPORT_ANY : tu->fport;
379: so->so_faddr = tu->faddr;
380: so->so_state &= ~SS_WAITING;
381: tcp_isconnected(so);
382: break;
383: default:
384: goto bad;
385: }
386: bp_free(bp);
387: return;
388: bad:
389: bp_free(bp);
390: tcp_hungup(so);
391: }
392:
393: tcp_attach(so)
394: struct socket *so;
395: {
396: register struct tcpcb *tp;
397: extern struct tcpcb *tcp_newtcpcb();
398:
399: tp = tcp_newtcpcb(so);
400: if(tp == 0)
401: return(1);
402: tp->t_socket = so;
403: tp->t_state = TCPS_CLOSED;
404: return(0);
405: }
406:
407: struct tcpcb *
408: tcp_disconnect(tp)
409: register struct tcpcb *tp;
410: {
411: struct socket *so = tp->t_socket;
412:
413: if(tp->t_state < TCPS_ESTABLISHED)
414: tp = tcp_close(tp);
415: else {
416: soisdisconnecting(so);
417: tp = tcp_usrclosed(tp);
418: if(tp)
419: tcp_output(tp);
420: }
421: return(tp);
422: }
423:
424: struct tcpcb *
425: tcp_usrclosed(tp)
426: register struct tcpcb *tp;
427: {
428:
429: switch(tp->t_state){
430:
431: case TCPS_CLOSED:
432: case TCPS_LISTEN:
433: case TCPS_SYN_SENT:
434: tp->t_state = TCPS_CLOSED;
435: tp = tcp_close(tp);
436: break;
437:
438: case TCPS_SYN_RECEIVED:
439: case TCPS_ESTABLISHED:
440: tp->t_state = TCPS_FIN_WAIT_1;
441: tp->t_socket->so_options |= SO_KEEPALIVE;
442: tcp_timers(tp, TCPT_KEEP);
443: break;
444:
445: case TCPS_CLOSE_WAIT:
446: tp->t_state = TCPS_LAST_ACK;
447: tp->t_socket->so_options |= SO_KEEPALIVE;
448: tcp_timers(tp, TCPT_KEEP);
449: break;
450: }
451: if(tp && tp->t_state >= TCPS_FIN_WAIT_2)
452: soisdisconnected(tp->t_socket);
453: return(tp);
454: }
455:
456: tcp_isconnected(so)
457: struct socket *so;
458: {
459: struct block *bp;
460: struct tcpuser *tu;
461: struct socket *rso;
462:
463: if(so->so_head)
464: rso = so->so_head;
465: else
466: rso = so;
467: if((rso->so_state & SS_OPEN) == 0){
468: printf("isconnected, no fd ref\n");
469: return;
470: }
471: bp = allocb(64);
472: if(bp == 0)
473: return;
474: bp->next = NULL;
475: bp->type = M_DATA;
476: bp->wptr += sizeof(struct tcpuser);
477: tu = (struct tcpuser *)bp->rptr;
478: tu->code = TCPC_OK;
479: tu->fport = so->so_fport;
480: tu->faddr = so->so_faddr;
481: tu->lport = so->so_lport;
482: tu->laddr = so->so_laddr;
483: tu->param = so->so_dev;
484: tcpdrint(bp, rso);
485: }
486:
487: tcp_hungup(so)
488: register struct socket *so;
489: {
490: register struct queue *q;
491:
492: q = so->so_rq;
493: if(q == 0)
494: return;
495: tcp_putctl(q, M_HANGUP);
496: }
497:
498: /*
499: * find a spare odd tcp device for a new passive-end
500: * connection.
501: */
502: struct socket *
503: tcp_newconn(so)
504: struct socket *so;
505: {
506: struct socket *nso;
507:
508: if(so->so_rq && (so->so_rq->flag&QFULL)){
509: printf("listen %d q full\n", so->so_lport);
510: return(0);
511: }
512: for(nso = &tcpsocks[0]; nso < &tcpsocks[NTCP]; nso += 2){
513: if((nso->so_state & (SS_OPEN|SS_ACTIVE)) == 0){
514: bzero(nso, sizeof(struct socket));
515: nso->so_head = so;
516: nso->so_dev = nso - tcpsocks;
517: return(nso);
518: }
519: }
520: return(0);
521: }
522:
523: struct socket *
524: so_lookup(faddr, fport, laddr, lport)
525: in_addr faddr, laddr;
526: tcp_port fport, lport;
527: {
528: register struct socket *so, *match = 0;
529: int highscore = 0, score;
530:
531: for(so = &tcpsocks[0]; so < &tcpsocks[NTCP]; so++){
532: if(so->so_tcpcb == 0)
533: continue;
534: if((so->so_state&(SS_OPEN|SS_ACTIVE)) == 0)
535: continue;
536: if(so->so_state & SS_WAITING)
537: continue;
538: score = 11;
539: if(so->so_faddr != faddr) {
540: if(so->so_faddr != INADDR_ANY)
541: continue;
542: else
543: score -=4;
544: }
545: if(so->so_fport != fport) {
546: if(so->so_fport != TCPPORT_ANY)
547: continue;
548: else
549: score -=4;
550: }
551: if(so->so_laddr != laddr) {
552: if(so->so_laddr != INADDR_ANY)
553: continue;
554: else
555: score -=1;
556: }
557: if(so->so_lport != lport) {
558: if(so->so_lport != TCPPORT_ANY)
559: continue;
560: else
561: score -=2;
562: }
563: if (score==11)
564: return so;
565: if (score<highscore)
566: continue;
567: match = so;
568: highscore = score;
569: }
570: return(match);
571: }
572:
573: /* n chars were acked; drop them now */
574: sbsnddrop(so, n)
575: register struct socket *so;
576: register int n;
577: {
578: register struct queue *q;
579: register int i;
580: register struct block *bp;
581:
582: q = so->so_wq;
583: if(q == 0)
584: return;
585: bp = 0;
586: while(n > 0 && (bp = getq(q))){
587: i = MIN(BLEN(bp), n);
588: bp->rptr += i;
589: n -= i;
590: so->so_wcount -= i;
591: if(bp->rptr >= bp->wptr){
592: freeb(bp);
593: bp = 0;
594: } else if(n > 0){
595: panic("sbsnddrop");
596: }
597: }
598: if(bp)
599: putbq(q, bp);
600: }
601:
602: static tcp_port portnext[] = { 600, 1024 };
603: static tcp_port portlow[] = { 600, 1024 };
604: static tcp_port porthigh[] = { 1024, 2048 };
605:
606: sobind(so, addr, port)
607: register struct socket *so;
608: register in_addr addr;
609: register tcp_port port;
610: {
611: register struct socket *sp;
612: register int i;
613:
614: so->so_lport = 0;
615: if(port){
616: /* what about, for instance, restarting rlogind when
617: * people are rlogin'd here?
618: */
619: for(sp = &tcpsocks[0]; sp < &tcpsocks[NTCP]; sp++){
620: if(sp->so_tcpcb == 0)
621: continue;
622: if((sp->so_state&(SS_OPEN|SS_ACTIVE)) == 0)
623: continue;
624: if(sp->so_lport == port && sp->so_laddr == addr) {
625: return(1);
626: }
627: }
628: so->so_lport = port;
629: so->so_laddr = addr;
630: return(0);
631: }
632: /* pick one for him */
633: i = u.u_uid==0 ? 0 : 1;
634: if(portnext[i] >= porthigh[i])
635: portnext[i] = portlow[i];
636: port = portnext[i];
637: while(1){
638: if(sobind(so, addr, portnext[i]) == 0){
639: portnext[i]++;
640: return(0);
641: }
642: portnext[i]++;
643: if(portnext[i] >= porthigh[i])
644: portnext[i] = portlow[i];
645: if(portnext[i] == port) /* tried them all */
646: break;
647: }
648: return(1);
649: }
650:
651: tcp_cantrcvmore(so)
652: register struct socket *so;
653: {
654: register struct queue *q;
655:
656: q = so->so_rq;
657: if(q == NULL)
658: return;
659: if(so->so_state & SS_HANGUP)
660: tcp_putctl(q, M_HANGUP);
661: else {
662: /* two delims ensure a zero length read at the process */
663: tcp_putctl(q, M_DELIM);
664: tcp_putctl(q, M_DELIM);
665: }
666: }
667:
668: tcp_putctl(q, c)
669: register struct queue *q;
670: {
671: register struct block *bp;
672:
673: if ((bp = allocb(0)) == NULL) {
674: printf("tcp_putctl: no more blocks\n");
675: return(0);
676: }
677: bp->type = c;
678: putq(q, bp);
679: return(1);
680: }
681: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.