RIGHT:''&counter(all); - &counter(yesterday); - &counter(today); - &online;''
CENTER:&size(28){&color(darkgreen){''Mesのソース解析''};};
#br
----
#contents
----

**power onからのソース解析 [#jef2af35]
-power onプロセスの書いてあるところ(30xxcrt0.S)
 setup stack pointer
 move initial data from ROM to RAM
 clear non-initial RAM area
 call main routine
-main routineの書いてあるところ(main.c)
 set config (bus width etc.)
 init_device();
 if MODE != 5 then user1_start
 else user2_start (MES/main.c)
-user2_startの書いてあるところ(MES/main.c)
 init();       device open, set_handle(task_sw)
 ip_init();    arp_init(); udp_init(); tcp_init();
 task_init();  task_attach(initial());

**TRAPAからのソース解析 [#l33c6a7c]
-trapaが書いてあるところ(handle_h8.s)
     .h8300h
     .section .text
     .align 1
     .global _int_wovi
     .global _int_trap0
     .global _int_trap1
     .global _int_trap2
 _int_wovi:
 _int_trap0:
     push.l  er0                  いろいろPUSH
     push.l  er1
     push.l  er2
     push.l  er3
     push.l  er4
     push.l  er5
     push.l  er6
     mov.l   @_stackpp,er0        SPをstackppに設定
     mov.l   sp,@er0
     mov.l   @_handlefunc,er0     handlefuncをcall
     jsr @er0
 _int_trap2:
     mov.l   @_stackpp,er0        SPをstackppに設定
     mov.l   @er0,sp
     pop.l   er6                  いろいろPOP
     pop.l   er5
     pop.l   er4
     pop.l   er3
     pop.l   er2
     pop.l   er1
     pop.l   er0
     rte                           リターン
 _int_trap1:
     mov.l   @_curtaskp,er0        curtaskpをer0に入れて
     mov.l   @er0,er0
     rte                           リターン
     .end

-handlefunc, stackpp, curtaskpが書いてあるところ(set_handle.c)
 int (*handlefunc)();
 void    *stackpp, *curtaskp;
 
 void set_handle(int (*func)(), void *spp, void *ctp) {
     handlefunc = func;
     stackpp = spp;
     curtaskp = ctp;
 }

-set_handle()を呼んでいるところ(MES/main.c)
    set_handle(task_sw, &stackptr, &curtask);

つまり、curtaskにtask_sw()を登録してから、
task_init()を呼ぶ(initial()が呼ばれる)

**get_ipinfo()とget_ip() [#v09e8801]
単純に自分のIP, MASK, MACを返すだけ

**sock構造体の状態変数の推移 [#aee608d8]
-sock構造体(本名tcp_info)
 typedef struct {
     uint32_t rem_ip;    // Remote IP address
     uint32_t send_unacked;
     uint32_t send_next;
     uint32_t receive_next;
     uint32_t packet_size;
     uint32_t next_packet_size;
     uint32_t recv_packet_size;
     STRING   packet;
     STRING   next_packet;
     STRING   recv_packet;
     int32_t  (*event_listener)(uint32_t, Byte, uint32_t, uint16_t);
     uint16_t remport;   // Remote TCP port
     uint16_t locport;   // Local TCP port
     uint16_t id;        // task id
     uint16_t send_mtu;
     Byte    state;
     Byte    type;
     Byte    flags;      // State machine flags
     Byte    myflags;    // My flags to be Txed
     Byte    close_count;
     Byte    resend_timer;
     Byte    ack_timer;
     Byte    fin_timer;
 } tcp_info;

-状態変数の種類
 #define TCP_STATE_FREE      1
 #define TCP_STATE_RESERVED  2
 #define TCP_STATE_CLOSED    3
 #define TCP_STATE_LISTENING 4
 #define TCP_STATE_SYN_RECEIVED  5
 #define TCP_STATE_SYN_SENT  6
 #define TCP_STATE_FINW1     7
 #define TCP_STATE_FINW2     8
 #define TCP_STATE_CLOSING   9
 #define TCP_STATE_LAST_ACK  10
 #define TCP_STATE_TIMED_WAIT    11
 #define TCP_STATE_CONNECTED 12

-まず初期化(MES/tcp.c)
tcp_socket配列は、static tcp_infoで宣言されている。
 void tcp_init() {
     int32_t  i;
 
     for(i = 0;i <= TCP_NUM;i++) {
         tcp_socket[i].state = TCP_STATE_FREE;
         tcp_socket[i].type = TCP_TYPE_NONE;
         tcp_socket[i].flags = 0;
         tcp_socket[i].rem_ip = 0;
         tcp_socket[i].remport = 0;
         tcp_socket[i].locport = 0;
         tcp_socket[i].myflags = 0;
         tcp_socket[i].send_mtu = TCP_DEF_MTU;
         tcp_socket[i].event_listener = 0;
     }
 }

-tcpsocketからCALLされるtcp_getsocketでTCP_STATE_RESERVEDになる
-tcpconnectでtcp_newstate(sock, TCP_STATE_SYN_SENT)される
-tcpのcase TCP_STATE_SYN_SENT:内でSYN+ACKを検出したらTCP_STATE_CONNECTEDになる
         case TCP_STATE_SYN_SENT:
             if(tcphdr->hlen_flags & TCP_FLAG_RESET) {
                 soc->event_listener(sock, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                    tcp_newstate(sock, TCP_STATE_CLOSED);
                 return -1;
             }
             /* Is it SYN+ACK? */
             if((tcphdr->hlen_flags & TCP_FLAG_SYN) &&
                (tcphdr->hlen_flags & TCP_FLAG_ACK)) {
                 /* Right ACK?   */
                 if( tcphdr->ackno != soc->send_next ) return -1;
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;    /* ACK SYN */
                 soc->send_unacked = soc->send_next;
                 tcp_newstate(sock, TCP_STATE_CONNECTED);
                 soc->myflags = TCP_FLAG_ACK;
                 tcp_sendcontrol(sock);             プライベート内では通るけど、ルータ越しでは通らない
                 soc->event_listener(sock, TCP_EVENT_CONNECTED, soc->rem_ip, soc->remport);
                 return 0;
--結局、ルータ越しIPではtcp()に飛んで来ないのか?~
tcp()の呼び先であるip.c内のtcpip()を見ると・・・
 int32_t tcpip(uint32_t fd, IP_HDR *iphdr, Byte *destmac) {
     int32_t  index, ret;
     uint32_t ip, mask;
     Byte     mac[6];
  
     if(iphdr->version != 4)  return -1;
     index = fd2index(fd);
     if(index == -1) return -1;
     ret = set_ip_addr(index, iphdr->destip, destmac);
     if(ret == -1) return -1;
     ret = get_ipinfo(index, &ip, &mask, mac);
     if(ret == -1) return -1;
     if((ip & mask) != (iphdr->srcip & mask)) return -1;   ここで同一ネットワーク内でないとreturnしている?
     if(ip != iphdr->destip && (iphdr->destip | mask) != 0xffffffff) return -1;
     switch(iphdr->proto) {
     case ICMP:
         icmp(fd, iphdr);
         break;
     case UDP:
         udp(fd, iphdr);
         break;
     case TCP:
         tcp(fd, iphdr);
         break;
     }
     return 0;
--コメントアウトしたら、相手先のSYNが来なくなった。。。で、元に戻してもSYNが来ない。。。困った
--(この辺にルータ越しのバグが潜んでいるかも)

-つぎにディスコネクトの推移
-まずはtcpfreeでtcp_closeとtcp_releasesocketとが呼ばれる
-tcp_closeの処理はNAKデータ有り無しで変わる
--NAKなし・・・FINパケットを送出してtcp_newstate(sock, TCP_STATE_FINW1)する
--NAKあり・・・soc->flags|=TCP_INTFLAGS_CLOSEPENDINGする
-tcp_releasesocketでは、以下のように-1でreturn
 if((soc->id != id) &&
    (soc->state != TCP_STATE_FREE) &&
    (soc->state != TCP_STATE_RESERVED) &&
    (soc->state != TCP_STATE_CLOSED)) {
    return -1;
 }
-そうすると、tcpfreeでは、task->state |= NET_STATEしてreturn
     ret = tcp_releasesocket(id, sock);
     if(ret == -1) {
         task = get_taskptr(id);
         task->state |= NET_STATE;
         soc->fin_timer = 2;
     }
     return ret;
-で、task.cのinitial()では、下記のようにあるので、tcp_interval()が定期的に呼ばれている。
         if(sys_count != sys_count_ms / 1000) {
             check_flagroot_index();
             tcp_interval();
         }
-tcp_interval()では、下記のように処理している。
         if((soc->fin_timer) > 0) {
             if(--(soc->fin_timer) == 0) {
                 task->state &= ~NET_STATE;
                 task->retval = -1;
                 tcp_abort(i);
                 tcp_releasesocket(soc->id, i);
             }
         }
-tcp_abort()を見ると下記のように処理している。
         case TCP_STATE_SYN_SENT:
         case TCP_STATE_SYN_RECEIVED:
         case TCP_STATE_CONNECTED:
         case TCP_STATE_FINW1:
         case TCP_STATE_FINW2:
         case TCP_STATE_CLOSING:
         case TCP_STATE_LAST_ACK:
             soc->myflags = TCP_FLAG_RESET;
             tcp_sendcontrol(sock);
             tcp_newstate(sock, TCP_STATE_CLOSED);
             return sock;
-この辺にACKが返らないバグがありそう。
-TCP_STATE_FINW1からの処理はtcp()に記述がある。
         case TCP_STATE_FINW1:                          //sockの状態変数はTCP_STATE_FINW1になっている
             if(tcphdr->hlen_flags & TCP_FLAG_RESET) {  //結局、ここを通っていない。ただし、tcpip()からtcp()は呼ばれている
                 soc->event_listener(sock, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                     tcp_newstate(sock, TCP_STATE_CLOSED);
                 return -1;
             }
             /* Is it FIN+ACK? */
             if((tcphdr->hlen_flags & TCP_FLAG_FIN) &&
                (tcphdr->hlen_flags & TCP_FLAG_ACK)) {
                 if(tcphdr->ackno != soc->send_next) return -1;
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;
                 soc->receive_next += dlen;
                 soc->send_unacked = soc->send_next;
                 tcp_newstate(sock, TCP_STATE_TIMED_WAIT);
                 soc->myflags = TCP_FLAG_ACK;
                 tcp_sendcontrol(sock);
                 return 0;
             }
             /* Is it just FIN */
             if(tcphdr->hlen_flags & TCP_FLAG_FIN) {
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;
                 soc->receive_next += dlen;
                 tcp_newstate(sock, TCP_STATE_CLOSING);
                 soc->myflags = TCP_FLAG_ACK;
                 tcp_sendcontrol(sock);
                 return 0;
             }
             /* Is it just ACK? */                         //tcpdumpの結果では、ここを通るはず
             if(tcphdr->hlen_flags & TCP_FLAG_ACK) {
                 /* Right ACK?   */                        //このif文の中は通っていない。このcase文を通るか?
                 if( tcphdr->ackno != soc->send_next ) return -1;
                 soc->send_unacked = soc->send_next;
                 tcp_newstate(sock, TCP_STATE_FINW2);      //TCP_STATE_FINW2に状態遷移
                 return 0;
             }
             break;
         case TCP_STATE_FINW2:                             //で、TCP_STATE_FINW2の処理を見ると
             if(tcphdr->hlen_flags & TCP_FLAG_RESET) {
                 soc->event_listener(sock, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                     tcp_newstate(sock, TCP_STATE_CLOSED);
                 return -1;
             }
             if(tcphdr->hlen_flags & TCP_FLAG_FIN) {       //tcpdumpの結果では、ここを通るはず
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;
                 soc->receive_next += dlen;
                 tcp_newstate(sock, TCP_STATE_TIMED_WAIT); //TCP_STATE_TIMED_WAITに状態遷移
                 soc->myflags = TCP_FLAG_ACK;              //ここでACK処理している?
                 tcp_sendcontrol(sock);
                 return 0;
             }
             break;
         case TCP_STATE_CLOSING:
             if(tcphdr->hlen_flags & TCP_FLAG_RESET) {
                 soc->event_listener(sock, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                     tcp_newstate(sock, TCP_STATE_CLOSED);
                 return -1;
             }
             /* Is it ACK? */
             if( tcphdr->hlen_flags & TCP_FLAG_ACK   ) {
                 /* Right ACK? */
                 if( tcphdr->ackno != soc->send_next ) return -1;
                 soc->send_unacked = soc->send_next;
                 tcp_newstate(sock, TCP_STATE_TIMED_WAIT);
                 return 0;
             }
             if(tcphdr->hlen_flags & TCP_FLAG_FIN) {
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;
                 soc->receive_next += dlen;
                 soc->myflags = TCP_FLAG_ACK;
                 tcp_sendcontrol(sock);
                 return 0;
             }
             break;
         case TCP_STATE_LAST_ACK:
             if(tcphdr->hlen_flags & TCP_FLAG_RESET) {
                 soc->event_listener(sock, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                     tcp_newstate(sock, TCP_STATE_CLOSED);
                 return -1;
             }
             /* Is it ACK?   */
             if( tcphdr->hlen_flags & TCP_FLAG_ACK   ) {
                 /* Right ACK? */
                 if(tcphdr->ackno != soc->send_next) return -1;
                 soc->send_unacked = soc->send_next;
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                     tcp_newstate(sock, TCP_STATE_CLOSED);
                 return 0;
             }
             /* Is it repeated FIN?  */
             if(tcphdr->hlen_flags & TCP_FLAG_FIN) {
                 /* ACK FIN and all data */
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;
                 soc->receive_next += dlen;
                 soc->myflags = TCP_FLAG_FIN | TCP_FLAG_ACK;
                 tcp_sendcontrol(sock);
                 return 0;
             }
             break;
         case TCP_STATE_TIMED_WAIT:
             if(tcphdr->hlen_flags & TCP_FLAG_RESET) {
                 soc->event_listener(sock, TCP_EVENT_ABORT, soc->rem_ip, soc->remport);
                 if(soc->type & TCP_TYPE_SERVER)
                     tcp_newstate(sock, TCP_STATE_LISTENING);
                 else
                     tcp_newstate(sock, TCP_STATE_CLOSED);
                 return -1;
             }
             /* Is it repeated FIN?  */
             if(tcphdr->hlen_flags & TCP_FLAG_FIN) {
                 soc->receive_next = tcphdr->seqno;
                 soc->receive_next++;
                 soc->receive_next += dlen;
                 soc->myflags = TCP_FLAG_ACK;
                 tcp_sendcontrol(sock);
                 return 0;
             }
             break;

-TCPクローズ時、FINを送出してTCP_STATE_FINW1になるが、~
次のバケット(相手先からのACK)に対して、下記のどこかでreturnしている~
(すなわち、TCP_STATE_FINW1の処理が行われていない)~
下記はtcp()の冒頭部分
     ptr = (STRING)iphdr;
     ptr = &(ptr[iphdr->header_len * 4]);
     tcphdr = (TCP_HDR*)ptr;
     len = iphdr->datasize;
     len -= (int32_t)iphdr->header_len * 4;
     hlen = tcphdr->hlen_flags & 0xF000;
     hlen >>= 10;
     if(hlen < MIN_TCP_HLEN) return -1;
     olen = hlen - MIN_TCP_HLEN;
     if(olen > MAX_TCP_OPTLEN) return -1;
     if(hlen > len) return -1;
     dlen = len - hlen;
     tcpdata = &ptr[hlen];
     sock = tcp_mapsocket(iphdr);    //ここで-1が返される
     if(sock == -1) return 0;        //TCP_STATE_FINW1が処理されない
     soc = &tcp_socket[sock];

-tcp_mapsocketを見ると、下記の通り。
 static int32_t tcp_mapsocket(IP_HDR *iphdr) {
     TCP_HDR  *tcphdr;
     STRING   ptr;
     int32_t  i;

     ptr = (STRING)iphdr;
     ptr = &(ptr[iphdr->header_len * 4]);
     tcphdr = (TCP_HDR*)ptr;
     for(i = 0;i < TCP_NUM;i++) {                             //既存ソケットの検索
         if(tcp_socket[i].state == TCP_STATE_LISTENING) continue;
         if(tcp_socket[i].remport != tcphdr->sport) continue; //このif文がFALSEにならない=remportとsportとが違う
         if(tcp_socket[i].locport != tcphdr->dport) continue;
         if(tcp_socket[i].rem_ip != iphdr->srcip) continue;
         return i;
     }
     if((tcphdr->hlen_flags & TCP_FLAG_SYN) == 0) return -1;  //SYN受信〜新規ソケットの作成
     if(tcphdr->hlen_flags & TCP_FLAG_ACK) return -1;
     if(tcphdr->hlen_flags & TCP_FLAG_RESET) return -1;
     if(tcphdr->hlen_flags & TCP_FLAG_FIN) return -1;
     for(i = 0;i < TCP_NUM;i++){
         if(tcp_socket[i].state != TCP_STATE_LISTENING) continue;
         if(tcp_socket[i].locport != tcphdr->dport) continue;
         tcp_socket[i].rem_ip = iphdr->srcip;
         tcp_socket[i].remport = tcphdr->sport;
         return i;
     }
     return -1;
 }
--TCP_STATE_FINW1のとき、既存ソケットの検索に失敗している?
--if(tcp_socket[i].remport != tcphdr->sport) continue; //このif文がFALSEにならない=remportとsportとが違う
--どうして?
--調べると、remportもlocportもrem_ipも一致していない。~
すなわち、受信パケットのポインタが壊れていると考えられる
--SYN受信時にtcp_socket[i].rem_ipとremportが更新されていない可能性もある。


**initial()の解析 [#p50c1481]
-MES/task.cにあるinitial()が肝心。
ひとまずソース全体を張っておく。
 void initial() {
     static STRING   ptrs[2];
     static Byte name[16];
     static int64_t  sys_count_ms;
     volatile char   w;
     Task        *taskptr;
     int32_t     c, *sp_ptr;
 
     strcpy(name, "/rom0/shell");
     ptrs[0] = name;
     ptrs[1] = 0;
     curtask->req = EXEC_REQ;
     curtask->arg[0] = 1;
     curtask->arg[1] = (int32_t)ptrs;
     request(curtask);
     if(curtask->retval == -1) {
         strcpy(name, "/rom0/netsh");
         ptrs[0] = name;
         ptrs[1] = 0;
         curtask->req = EXEC_REQ;
         curtask->arg[0] = 1;
         curtask->arg[1] = (int32_t)ptrs;
         request(curtask);
         if(curtask->retval == -1) {
             write_device(stdio, "Shell not found, system halt.\n", 31);
             while(1);
         }
     }
     sys_count_ms = 0;
     while(1) {                                   //無限ループ
         int_disable();
         for(taskptr = curtask->next;taskptr != curtask;taskptr = taskptr->next) { //タスクのスキャン
             if(taskptr->state & EXIT_STATE) {    //タスクの終了処理
                 dettach_task(taskptr);
                 taskptr = curtask->next;
                 continue;
             }
             if(taskptr->state & REQ_STATE) request(taskptr);  //要求待ちタスクの実行
             if(taskptr->net_count > 0) {
                 (taskptr->net_count)--;
                 net_request(taskptr);                         //SEND_ARP_REQのみを処理してる
             }
             if(taskptr->count > 0) {
                 taskptr->count -= time_count / counter;
                 if(taskptr->count <= 0) taskptr->count = 0;
             }
             if(taskptr->interval > 0) {
                 taskptr->interval -= time_count / counter;
                 if(taskptr->interval <= 0) {
 #ifdef H8_300H
                     sp_ptr = taskptr->sp;
                     sp_ptr = &(sp_ptr[-1]);
                     taskptr->sp = sp_ptr;
                     for(c = 0;c < PC_REG;c++) sp_ptr[c] = sp_ptr[c + 1];
 #endif
 #ifdef SH
                     sp_ptr[PR_REG] = sp_ptr[PC_REG];
 #endif
                     sp_ptr[PC_REG] = (int32_t)(taskptr->sigfunc);
                     taskptr->interval = 0;
                 }
             }
             sys_count_ms += time_count / counter;
         }
         ip_request();                                     //rcv_fifoからパケットを取出して
         time_count -= (time_count / counter) * counter;   //case ARP_TYPE, case IP_TYPEする
         if(sys_count != sys_count_ms / 1000) {
             check_flagroot_index();
             tcp_interval();                               //相手のFINに対するACK不送出に関連がある?
         }
         sys_count = sys_count_ms / 1000;
         int_enable();
         TRAP0;
     }
 }


**TCPクライアントのサンプル [#d60cef52]
-shell.cのコマンドでdiscardを加筆してます。
--TCPポート7(ECHO)を開こうとします。
--"q"を押すとクローズします。
-daytimeもあるけど、socketのopen, closeのみの検証ではdiscardがgood
--doscardコマンドは実はechoコマンドが正しいけど、echoコマンドは既出。

**timer周りの変更点 [#c0bfa57f]
FDAUのクロックは20MHzなので、task.cの以下を変更する。
でも、ちょっと変なソースなので再考したい。
 static void init_timer() {
     time_count = 0;
     counter = ((25 * 1000) >> 8) & 0xff;       ここの25を20に変更
     counter = (256 - counter) & 0xff;          WDTはアップカウンタなので256から引算
     start_timer();
 }
-どうしてmagic numberなんだろう?
-counterを分母として減算している場所があるけど、変ではないか?


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS