tcpoutput()

tcpoutput()

概要

引数

戻り値

  • なし

実装

 2391: /*
 2392:  *  always enters and exits with the s locked.  We drop
 2393:  *  the lock to ipoput the packet so some care has to be
 2394:  *  taken by callers.
 2395:  */
 2396: void
 2397: tcpoutput(Conv *s)
 2398: {
 2399:         Tcp seg;
 2400:         int msgs;
 2401:         Tcpctl *tcb;
 2402:         Block *hbp, *bp;
 2403:         int sndcnt, n;
 2404:         ulong ssize, dsize, usable, sent;
 2405:         Fs *f;
 2406:         Tcppriv *tpriv;
 2407:         uchar version;
 2408: 
 2409:         f = s->p->f;
 2410:         tpriv = s->p->priv;
 2411:         version = s->ipversion;
 2412: 
 2413:         for(msgs = 0; msgs < 100; msgs++) {
 2414:                 tcb = (Tcpctl*)s->ptcl;
 2415:         
 2416:                 switch(tcb->state) {
 2417:                 case Listen:
 2418:                 case Closed:
 2419:                 case Finwait2:
 2420:                         return;
  • Listen,Closed,Finwait2状態の場合は何もしない.
 2421:                 }
 2422:         
 2423:                 /* force an ack when a window has opened up */
 2424:                 if(tcb->rcv.blocked && tcb->rcv.wnd > 0){
 2425:                         tcb->rcv.blocked = 0;
 2426:                         tcb->flags |= FORCE;
 2427:                 }
 2428:         
 2429:                 sndcnt = qlen(s->wq)+tcb->flgcnt;
 2430:                 sent = tcb->snd.ptr - tcb->snd.una;
 2431: 
 2432:                 /* Don't send anything else until our SYN has been acked */
 2433:                 if(tcb->snd.ptr != tcb->iss && (tcb->flags & SYNACK) == 0)
 2434:                         break;
 2435: 
 2436:                 /* Compute usable segment based on offered window and limit
 2437:                  * window probes to one
 2438:                  */
 2439:                 if(tcb->snd.wnd == 0){
 2440:                         if(sent != 0) {
 2441:                                 if((tcb->flags&FORCE) == 0)
 2442:                                         break;
 2443: //                              tcb->snd.ptr = tcb->snd.una;
 2444:                         }
 2445:                         usable = 1;
 2446:                 }
 2447:                 else {
 2448:                         usable = tcb->cwind;
 2449:                         if(tcb->snd.wnd < usable)
 2450:                                 usable = tcb->snd.wnd;
 2451:                         usable -= sent;
 2452:                 }
 2453:                 ssize = sndcnt-sent;
 2454:                 if(ssize && usable < 2)
 2455:                         netlog(s->p->f, Logtcp, "throttled snd.wnd %lud cwind %lud\n",
 2456:                                 tcb->snd.wnd, tcb->cwind);
 2457:                 if(usable < ssize)
 2458:                         ssize = usable;
 2459:                 if(tcb->mss < ssize)
 2460:                         ssize = tcb->mss;
 2461:                 dsize = ssize;
 2462:                 seg.urg = 0;
 2463: 
 2464:                 if(ssize == 0)
 2465:                 if((tcb->flags&FORCE) == 0)
 2466:                         break;
 2467: 
 2468:                 tcb->flags &= ~FORCE;
 2469:                 tcprcvwin(s);
 2470: 
 2471:                 /* By default we will generate an ack */
 2472:                 tcphalt(tpriv, &tcb->acktimer);
 2473:                 tcb->rcv.una = 0;
 2474:                 seg.source = s->lport;
 2475:                 seg.dest = s->rport;
 2476:                 seg.flags = ACK;
 2477:                 seg.mss = 0;
 2478:                 seg.ws = 0;
 2479:                 switch(tcb->state){
 2480:                 case Syn_sent:
 2481:                         seg.flags = 0;
 2482:                         if(tcb->snd.ptr == tcb->iss){
 2483:                                 seg.flags |= SYN;
 2484:                                 dsize--;
 2485:                                 seg.mss = tcb->mss;
 2486:                                 seg.ws = tcb->scale;
 2487:                         }
 2488:                         break;
 2489:                 case Syn_received:
 2490:                         /*
 2491:                          *  don't send any data with a SYN/ACK packet
 2492:                          *  because Linux rejects the packet in its
 2493:                          *  attempt to solve the SYN attack problem
 2494:                          */
 2495:                         if(tcb->snd.ptr == tcb->iss){
 2496:                                 seg.flags |= SYN;
 2497:                                 dsize = 0;
 2498:                                 ssize = 1;
 2499:                                 seg.mss = tcb->mss;
 2500:                                 seg.ws = tcb->scale;
 2501:                         }
 2502:                         break;
 2503:                 }
 2504:                 seg.seq = tcb->snd.ptr;
 2505:                 seg.ack = tcb->rcv.nxt;
 2506:                 seg.wnd = tcb->rcv.wnd;
 2507: 
 2508:                 /* Pull out data to send */
 2509:                 bp = nil;
 2510:                 if(dsize != 0) {
 2511:                         bp = qcopy(s->wq, dsize, sent);
 2512:                         if(BLEN(bp) != dsize) {
 2513:                                 seg.flags |= FIN;
 2514:                                 dsize--;
 2515:                         }
 2516:                 }
 2517: 
 2518:                 if(sent+dsize == sndcnt)
 2519:                         seg.flags |= PSH;
 2520: 
 2521:                 /* keep track of balance of resent data */
 2522:                 if(seq_lt(tcb->snd.ptr, tcb->snd.nxt)) {
 2523:                         n = tcb->snd.nxt - tcb->snd.ptr;
 2524:                         if(ssize < n)
 2525:                                 n = ssize;
 2526:                         tcb->resent += n;
 2527:                         netlog(f, Logtcp, "rexmit: %I.%d -> %I.%d ptr %lux nxt %lux\n",
 2528:                                 s->raddr, s->rport, s->laddr, s->lport, tcb->snd.ptr, tcb->snd.nxt);
 2529:                         tpriv->stats[RetransSegs]++;
 2530:                 }
 2531: 
 2532:                 tcb->snd.ptr += ssize;
 2533: 
 2534:                 /* Pull up the send pointer so we can accept acks
 2535:                  * for this window
 2536:                  */
 2537:                 if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
 2538:                         tcb->snd.nxt = tcb->snd.ptr;
 2539: 
 2540:                 /* Build header, link data and compute cksum */
 2541:                 switch(version){
 2542:                 case V4:
 2543:                         tcb->protohdr.tcp4hdr.vihl = IP_VER4;
 2544:                         hbp = htontcp4(&seg, bp, &tcb->protohdr.tcp4hdr, tcb);
 2545:                         if(hbp == nil) {
 2546:                                 freeblist(bp);
 2547:                                 return;
 2548:                         }
 2549:                         break;
 2550:                 case V6:
 2551:                         tcb->protohdr.tcp6hdr.vcf[0] = IP_VER6;
 2552:                         hbp = htontcp6(&seg, bp, &tcb->protohdr.tcp6hdr, tcb);
 2553:                         if(hbp == nil) {
 2554:                                 freeblist(bp);
 2555:                                 return;
 2556:                         }
 2557:                         break;
 2558:                 default:
 2559:                         hbp = nil;   /* to suppress a warning */
 2560:                         panic("tcpoutput: version %d", version);
 2561:                 }
 2562: 
 2563:                 /* Start the transmission timers if there is new data and we
 2564:                  * expect acknowledges
 2565:                  */
 2566:                 if(ssize != 0){
 2567:                         if(tcb->timer.state != TcptimerON)
 2568:                                 tcpgo(tpriv, &tcb->timer);
 2569: 
 2570:                         /*  If round trip timer isn't running, start it.
 2571:                          *  measure the longest packet only in case the
 2572:                          *  transmission time dominates RTT
 2573:                          */
 2574:                         if(tcb->rtt_timer.state != TcptimerON)
 2575:                         if(ssize == tcb->mss) {
 2576:                                 tcpgo(tpriv, &tcb->rtt_timer);
 2577:                                 tcb->rttseq = tcb->snd.ptr;
 2578:                         }
 2579:                 }
 2580: 
 2581:                 tpriv->stats[OutSegs]++;
 2582: 
 2583:                 /* put off the next keep alive */
 2584:                 tcpgo(tpriv, &tcb->katimer);
 2585: 
 2586:                 switch(version){
  • IPのバージョンによって,IP出力処理を行うためにipoput4()かipoput6()?を呼び出す.これらに失敗した場合は,localclose()を実行する.
  • 詳細はipoput4()を参照
  • 詳細はipoput6()?を参照
  • 詳細はlocalclose()を参照
 2587:                 case V4:
 2588:                         if(ipoput4(f, hbp, 0, s->ttl, s->tos, s) < 0){
 2589:                                 /* a negative return means no route */
 2590:                                 localclose(s, "no route");
 2591:                         }
 2592:                         break;
 2593:                 case V6:
 2594:                         if(ipoput6(f, hbp, 0, s->ttl, s->tos, s) < 0){
 2595:                                 /* a negative return means no route */
 2596:                                 localclose(s, "no route");
 2597:                         }
 2598:                         break;
 2599:                 default:
 2600:                         panic("tcpoutput2: version %d", version);
 2601:                 }
 2602:                 if((msgs%4) == 1){
 2603:                         qunlock(s);
 2604:                         sched();
 2605:                         qlock(s);
 2606:                 }
 2607:         }
 2608: }