int udp_port_unreach(in_addr_t __faddr, uint16_t __fport, in_addr_t __laddr, uint16_t __lport) { struct udp_pcb * up; up = (struct udp_pcb *)pcb_wildlookup(__faddr, __fport, __laddr, __lport, &__udp__.active); if (up == NULL) { DCC_LOG4(LOG_TRACE, "not found: %I:%d > %I:%d", __laddr, ntohs(__lport), __faddr, ntohs(__lport)); return -1; } /* set the error flag */ up->u_icmp_err = 1; /* unconnect the PCB */ up->u_faddr = INADDR_ANY; up->u_fport = 0; /* notify the application */ __os_cond_signal(up->u_rcv_cond); return 0; }
int mbuf_alloc_check(void) { struct mbuf * m; int ret = 0; int n; __os_mutex_lock(__mbufs__.mutex); n = 0; m = __mbufs__.free.first; /* count the free blocks */ while (m != NULL) { n++; m = m->next; } if ((n + __mbufs__.used) != __mbufs__.max) { DCC_LOG4(LOG_ERROR, "used=%d max=%d free=%d avail=%d", __mbufs__.used, __mbufs__.max, __mbufs__.max - __mbufs__.used, n); ret = -1; } __os_mutex_unlock(__mbufs__.mutex); return ret; }
void __attribute__((noreturn)) serial_recv_task(struct vcom * vcom) { struct serial_dev * serial = vcom->serial; struct usb_cdc_class * cdc = vcom->cdc; uint8_t buf[VCOM_BUF_SIZE]; int len; DCC_LOG1(LOG_TRACE, "[%d] started.", thinkos_thread_self()); /* wait for line configuration */ usb_cdc_acm_lc_wait(cdc); /* enable serial */ serial_enable(serial); for (;;) { len = serial_read(serial, buf, VCOM_BUF_SIZE, 1000); if (len > 0) { // dbg_write(buf, len); if (vcom->mode == VCOM_MODE_CONVERTER) { led_flash(LED_AMBER, 50); usb_cdc_write(cdc, buf, len); } if (vcom->mode == VCOM_MODE_SDU_TRACE) { led_flash(LED_AMBER, 50); sdu_decode(buf, len); } #if RAW_TRACE if (len == 1) DCC_LOG1(LOG_TRACE, "RX: %02x", buf[0]); else if (len == 2) DCC_LOG2(LOG_TRACE, "RX: %02x %02x", buf[0], buf[1]); else if (len == 3) DCC_LOG3(LOG_TRACE, "RX: %02x %02x %02x", buf[0], buf[1], buf[2]); else if (len == 4) DCC_LOG4(LOG_TRACE, "RX: %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3]); else if (len == 5) DCC_LOG5(LOG_TRACE, "RX: %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4]); else if (len == 6) DCC_LOG6(LOG_TRACE, "RX: %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); else if (len == 7) DCC_LOG7(LOG_TRACE, "RX: %02x %02x %02x %02x %02x %02x %02x ", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); else DCC_LOG8(LOG_TRACE, "RX: %02x %02x %02x %02x %02x %02x " "%02x %02x ...", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); #endif #if SDU_TRACE RX(buf, len); #endif } } }
int raw_input(struct ifnet * __if, struct iphdr * __ip, int __len) { struct pcb_link * q; struct raw_pcb * raw; int n; q = (struct pcb_link *)&__raw__.active.first; DCC_LOG4(LOG_TRACE, "%I > %I prot=%d (%d) ", __ip->saddr, __ip->daddr, __ip->proto, __len); while ((q = q->next)) { raw = (struct raw_pcb *)&q->pcb; if (raw->r_protocol != __ip->proto) continue; raw->r_faddr = __ip->saddr; raw->r_laddr = __ip->daddr; n = MIN(NET_RAW_RCV_BUF_LEN, __len); memcpy(raw->r_buf, __ip, n); raw->r_len = n; DCC_LOG2(LOG_TRACE, "<%0x> signal ---> %d", raw, raw->r_cond); thinkos_cond_signal(raw->r_cond); return 0; } return -1; }
void __attribute__((noreturn)) usb_recv_task(struct vcom * vcom) { struct serial_dev * serial = vcom->serial; usb_cdc_class_t * cdc = vcom->cdc; uint8_t buf[VCOM_BUF_SIZE]; int len; DCC_LOG1(LOG_TRACE, "[%d] started.", thinkos_thread_self()); DCC_LOG2(LOG_TRACE, "vcom->%p, cdc->%p", vcom, cdc); for (;;) { len = usb_cdc_read(cdc, buf, VCOM_BUF_SIZE, 1000); if (vcom->mode == VCOM_MODE_CONVERTER) { if (len > 0) { led_flash(LED_RED, 50); serial_write(serial, buf, len); #if RAW_TRACE if (len == 1) DCC_LOG1(LOG_TRACE, "TX: %02x", buf[0]); else if (len == 2) DCC_LOG2(LOG_TRACE, "TX: %02x %02x", buf[0], buf[1]); else if (len == 3) DCC_LOG3(LOG_TRACE, "TX: %02x %02x %02x", buf[0], buf[1], buf[2]); else if (len == 4) DCC_LOG4(LOG_TRACE, "TX: %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3]); else if (len == 5) DCC_LOG5(LOG_TRACE, "TX: %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4]); else if (len == 6) DCC_LOG6(LOG_TRACE, "TX: %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); else if (len == 7) DCC_LOG7(LOG_TRACE, "TX: %02x %02x %02x %02x %02x %02x %02x ", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); else DCC_LOG8(LOG_TRACE, "TX: %02x %02x %02x %02x %02x %02x " "%02x %02x ...", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); #endif #if SDU_TRACE TX(buf, len); #endif // dbg_write(buf, len); } } else { // forward to service input vcom_service_input(vcom, buf, len); } } }
void __thinkos_thread_init(unsigned int thread_id, uint32_t sp, void * task, void * arg) { struct thinkos_context * ctx; uint32_t pc; pc = (uint32_t)task; sp &= 0xfffffff8; /* 64bits alignemnt */ sp -= sizeof(struct thinkos_context); ctx = (struct thinkos_context *)sp; __thinkos_memset32(ctx, 0, sizeof(struct thinkos_context)); ctx->r0 = (uint32_t)arg; #if THINKOS_ENABLE_EXIT ctx->lr = (uint32_t)__exit_stub; #else ctx->lr = (uint32_t)__thinkos_thread_exit; #endif ctx->pc = pc; ctx->xpsr = CM_EPSR_T; /* set the thumb bit */ thinkos_rt.ctx[thread_id] = ctx; #if THINKOS_ENABLE_PAUSE /* insert into the paused list */ __bit_mem_wr(&thinkos_rt.wq_paused, thread_id, 1); #endif DCC_LOG4(LOG_TRACE, "thread_id=%d sp=%08x lr=%08x pc=%08x", thread_id, sp, ctx->lr, ctx->pc); DCC_LOG4(LOG_MSG, "r0=%08x r1=%08x r2=%08x r3=%08x", ctx->r0, ctx->r1, ctx->r2, ctx->r3); DCC_LOG3(LOG_MSG, "msp=%08x psp=%08x ctrl=%02x", cm3_msp_get(), cm3_psp_get(), cm3_control_get()); }
struct tcp_pcb * tcp_accept(const struct tcp_pcb * __mux) { struct tcp_listen_pcb * mux = (struct tcp_listen_pcb *)__mux; struct tcp_pcb * tp; if (__mux == NULL) DCC_LOG(LOG_WARNING, "NULL pointer"); DCC_LOG1(LOG_INFO, "<%04x> waiting...", (int)mux); if (thinkos_sem_wait(mux->t_sem) < 0) { DCC_LOG2(LOG_ERROR, "<%04x> thinkos_sem_wait(%d) failed!", (int)mux, mux->t_sem); return NULL; } tcpip_net_lock(); if (mux->t_state != TCPS_LISTEN) { DCC_LOG1(LOG_WARNING, "<%04x> invalid state!", (int)mux); tp = NULL; } else { unsigned int tail; tail = mux->t_tail; tp = (struct tcp_pcb *)mux->t_backlog[tail++]; /* wrap */ if (tail == mux->t_max) tail = 0; mux->t_tail = tail; #ifdef ENABLE_SANITY if (tp == NULL) DCC_LOG(LOG_PANIC, "NULL pointer"); #endif DCC_LOG4(LOG_INFO, "<%04x> --> <%04x> %I:%d", (int)mux, (int)tp, tp->t_faddr, ntohs(tp->t_fport)); // thinkos_sleep(100); } tcpip_net_unlock(); return tp; }
uint32_t calc32(int op, uint32_t x, uint32_t y) { uint32_t z = 0; switch (op) { case ADD: z = x + y; break; case SUB: z = x - y; break; case AND: z = x & y; break; case OR: z = x | y; break; case XOR: z = x ^ y; break; case SHL: z = x << y; break; case SHR: z = x >> y; break; case MUL: z = x * y; break; case DIV: z = x / y; break; case MOD: z = x % y; break; } DCC_LOG4(LOG_TRACE, "%d %s %d = %d", x, op_sym[op], y, z); return z; }
int var_global_add(int mod_id, const char * name, int type, int var_id) { struct var_def * var; if (var_cnt == VAR_GLOBAL_MAX) { DCC_LOG(LOG_WARNING, "no more room for global variables!"); return -1; } var = &var_tab[var_cnt++]; var->name = (char *)name; var->type = type; var->mod_id = mod_id; var->id = var_id; DCC_LOG4(LOG_TRACE, "name:'%s.%s' type:%s id:%d", module_name(mod_id), name, type_name(type), var_id); return 0; }
usb_cdc_class_t * usb_cdc_init(const usb_dev_t * usb, const uint8_t * const str[], unsigned int strcnt) { struct usb_cdc_acm_dev * dev = &usb_cdc_rt; usb_class_t * cl = (usb_class_t *)dev; /* initialize USB device */ dev->usb = (usb_dev_t *)usb; #ifndef CDC_RX_SEM_NO dev->rx_sem = thinkos_sem_alloc(0); #endif #ifndef CDC_TX_DONE_NO dev->tx_done = thinkos_flag_alloc(); #endif #ifndef CDC_TX_LOCK_NO dev->tx_lock = thinkos_flag_alloc(); #endif #ifndef CDC_CTL_FLAG_NO dev->ctl_flag = thinkos_flag_alloc(); #endif dev->rx_cnt = 0; dev->rx_pos = 0; dev->str = str; dev->strcnt = strcnt; DCC_LOG4(LOG_INFO, "tx_done=%d tx_lock=%d rx_sem=%d ctl_flag=%d", TX_DONE, TX_LOCK, RX_SEM, CTL_FLAG); thinkos_flag_clr(TX_DONE); thinkos_flag_clr(TX_LOCK); thinkos_flag_clr(CTL_FLAG); usb_dev_init(dev->usb, cl, &usb_cdc_ev); return (usb_cdc_class_t *)dev; }
unsigned int jtag3ctrl_set_speed(unsigned int freq) { uint32_t brg_freq; uint32_t brg_fmax; uint32_t brg_fmin; uint32_t tap_freq; uint32_t cfg; uint32_t clk; int32_t div; int sel; int err; int min = INT_MAX; int best_sel; brg_fmax = jtag_clk_tab[15] / 2; brg_freq = freq * 2; if (brg_freq > brg_fmax) { brg_freq = brg_fmax; } brg_fmin = jtag_clk_tab[0] / 0x10000; if (brg_freq < brg_fmin) { brg_freq = brg_fmin; } DCC_LOG1(LOG_INFO, "brg freq=%d", brg_freq); /* find the best matching frequency, but never bigger than the desired frequency */ best_sel = -1; for (sel = 0; sel <= 15; sel++) { clk = jtag_clk_tab[sel]; div = ((clk + (brg_freq / 2)) / brg_freq) - 2; /* range checking */ if (div < 0) div = 0; if (div >= 0xffff) div = 0xfffe; err = brg_freq - (clk / (div + 2)); DCC_LOG3(LOG_INFO, "clk=%d div=%d err=%d", clk, (div + 2), brg_freq - (clk / (div + 2))); if ((err >= 0) && (err < min)) { min = err; best_sel = sel; if (err == 0) break; } } if (best_sel < 0) best_sel = 0; clk = jtag_clk_tab[best_sel]; div = ((clk + (brg_freq / 2)) / brg_freq) - 2; /* range checking */ if (div < 0) div = 0; if (div >= 0xffff) div = 0xfffe; /* select the clock source */ cfg = reg_rd(REG_CFG) & ~CFG_CLK_SEL(0xf); reg_wr(REG_CFG, cfg | CFG_CLK_SEL(best_sel)); /* configure the brg divisor */ reg_wr(REG_BRG_DIV, div); brg_freq = clk / (div + 2); tap_freq = brg_freq / 2; DCC_LOG2(LOG_INFO, "sel: %d div: %d", best_sel, div + 2); DCC_LOG4(LOG_TRACE, "clk=%d.%06d MHz, TAP freq: %d.%06d MHz", clk / 1000000, clk % 1000000, tap_freq / 1000000, tap_freq % 1000000); return tap_freq; }
int tcp_input(struct ifnet * __if, struct iphdr * iph, struct tcphdr * th, int len) { struct tcp_listen_pcb * mux; struct tcp_pcb * tp; #if (ENABLE_NET_TCP_CHECKSUM) unsigned int sum; #endif int ti_len; int acked = 0; int ourfinisacked = 0; int needoutput = 0; unsigned int optlen; int tiflags; int todrop; uint32_t snd_una; uint32_t snd_nxt; uint32_t snd_max; uint32_t ti_seq; uint32_t ti_ack; int rcv_wnd; int tiwin; int hdrlen; uint8_t * data; int ret; #if (ENABLE_TCPDUMP) tcp_dump(iph, th, TCPDUMP_RX); #endif /* get TCP options, if any */ optlen = ((th->th_off << 2) - sizeof(struct tcphdr)); hdrlen = sizeof(struct tcphdr) + optlen; data = (uint8_t *)&th->th_opt[optlen]; ti_len = len - hdrlen; #if (ENABLE_NET_TCP_CHECKSUM) /* initialize checksum */ sum = htons(len) + (IPPROTO_TCP << 8); sum = in_chksum(sum, &iph->saddr, 8); sum = in_chksum(sum, th, hdrlen); if (ti_len) { sum = in_chksum(sum, data, ti_len); } if (sum != 0x0000ffff) { DCC_LOG3(LOG_WARNING, "checksum error: 0x%04x hdrlen=%d, len=%d", sum, hdrlen, len); TCP_PROTO_STAT_ADD(rx_err, 1); goto drop; } #endif tiflags = th->th_flags; /* convert TCP protocol specific fields to host format */ tiwin = ntohs(th->th_win); ti_seq = ntohl(th->th_seq); ti_ack = ntohl(th->th_ack); TCP_PROTO_STAT_ADD(rx_ok, 1); /* Serch in active list first */ if ((tp = tcp_active_lookup(iph->saddr, th->th_sport, iph->daddr, th->th_dport)) == NULL) { /* lookup into listening pcb list */ if ((mux = tcp_listen_lookup(iph->saddr, th->th_sport, iph->daddr, th->th_dport)) == NULL) { DCC_LOG(LOG_WARNING, "invalid peer ???"); goto dropwithreset; } if ((tiflags & TH_ACK)) { DCC_LOG(LOG_WARNING, "listen ACK ?"); goto dropwithreset; } if (ti_len != 0) { DCC_LOG(LOG_WARNING, "ti_len != 0"); goto dropwithreset; } /* Completion of Passive Open Ref.: TCP/IP Illustrated Volume 2, pg. 942 */ if (!(tiflags & TH_SYN)) { DCC_LOG(LOG_WARNING, "listen !SYN ?"); goto drop; } /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if ((tiflags & TH_RST)) { DCC_LOG(LOG_WARNING, "listen RST?"); goto drop; } if ((tp = tcp_passive_open(mux, iph, th, optlen)) == NULL) { DCC_LOG(LOG_WARNING, "tcp_passive_open()"); goto dropwithreset; } /* schedule output */ tcp_output_sched(tp); /* packet handled */ return 0; } DCC_LOG1(LOG_MSG, "<%05x> active", (int)tp); snd_una = tp->snd_seq; snd_nxt = tp->snd_seq + tp->snd_off; snd_max = tp->snd_seq + tp->snd_max; /* Remove acknowledged bytes from the send buffer */ /* Wakeup processes waiting on send buffer */ /* Segment received on a connection. Reset the idle detection timer Ref.: TCP/IP Illustrated Volume 2, pg. 932 */ tp->t_conn_tmr = tcp_idle_det_tmo; if (tp->t_flags & TF_IDLE) { /* exits from the idle state */ tp->t_flags &= ~TF_IDLE; DCC_LOG1(LOG_INFO, "<%05x> IDLE exit", (int)tp); } #if 0 /* Process options, we don't need to check if the socket is in the LISTEN state, because only active (non LISTENING) sockets will actually fall into this code. XXX: options after connection stablished ??? */ if (optlen) tcp_parse_options(tp, th, th->th_opt, optlen); #endif /* Ref.: TCP/IP Illustrated Volume 2, pg. 934 */ #if (TCP_ENABLE_HEADER_PREDICTION) if ((tp->t_state == TCPS_ESTABLISHED) && (tiflags & (TH_SYN | TH_FIN | TH_RST | TH_URG | TH_ACK)) == TH_ACK && (ti_seq == tp->rcv_nxt) && (tiwin) && (tiwin == tp->snd_wnd) && (snd_nxt == snd_max)) { if (ti_len == 0) { if (SEQ_GT(ti_ack, snd_una) && SEQ_LEQ(ti_ack, snd_max)) { acked = ti_ack - snd_una; DCC_LOG(LOG_INFO, "header prediction, ACK ..."); mbuf_queue_trim(&tp->snd_q, acked); snd_una = ti_ack; tp->snd_seq = snd_una; tp->snd_off = snd_nxt - tp->snd_seq; tp->snd_max = snd_max - tp->snd_seq; if (snd_una == snd_max) { tp->t_rxmt_tmr = 0; tp->t_rxmt_cnt = 0; DCC_LOG(LOG_INFO, "acked all data, rxmt tmr stopped"); } else { if (tp->t_rxmt_tmr == 0) { DCC_LOG(LOG_INFO, "not all data acked restart rxmt tmr"); tp->t_rxmt_tmr = tcp_rxmtintvl[tp->t_rxmt_cnt / 2]; } } thinkos_cond_broadcast(tp->t_cond); if (tp->snd_q.len) { /* schedule output */ tcp_output_sched(tp); } return 0; } } else { if ((ti_ack == snd_una) && ti_len <= (tcp_maxrcv - tp->rcv_q.len)) { int len; DCC_LOG1(LOG_INFO, "header prediction, data (%d)", ti_len); /* append data */ len = mbuf_queue_add(&tp->rcv_q, data, ti_len); tp->rcv_nxt += len; thinkos_cond_broadcast(tp->t_cond); if (len != ti_len) { DCC_LOG1(LOG_WARNING, "<%05x> no more mbufs", (int)tp); tp->t_flags |= TF_ACKNOW; /* schedule output */ tcp_output_sched(tp); } else { tp->t_flags |= TF_DELACK; } return 0; } } } #endif /* TCP_ENABLE_HEADER_PREDICTION */ /* Slow path input processing Ref.: TCP/IP Illustrated Volume 2, pg. 941 */ /* TODO: Drop TCP, IP headers and TCP options. Well, only if these structures were dynamic allocated... */ if (ti_len == 0) { DCC_LOG(LOG_INFO, "slow path ACK"); } else { DCC_LOG1(LOG_INFO, "slow path (%d)", ti_len); } /* Calculate the amount of space in receive window, and then do TCP input processing. Receive window is amount of space in rcv queue, but not less than advertise window. Ref.: TCP/IP Illustrated Volume 2, pg. 941 */ { int win; /* space left in the input queue */ win = tcp_maxrcv - tp->rcv_q.len; if (win <= 0) { win = 0; DCC_LOG(LOG_INFO, "receive buffer full!"); } // rcv_wnd = MAX(win, tp->rcv_adv_wnd); rcv_wnd = win; DCC_LOG3(LOG_INFO, "adv_wnd=%d rcv_wnd=%d win=%d", tp->rcv_adv_wnd, rcv_wnd, win); } if (tp->t_state == TCPS_SYN_SENT) { /* response to an active open. Ref.: TCP/IP Illustrated Volume 2, pg. 947 */ /* Common proccessing for receipt of SYN. Ref.: TCP/IP Illustrated Volume 2, pg. 950 */ if ((tiflags & TH_RST)) { goto close; } if (!(tiflags & TH_SYN)) { DCC_LOG(LOG_WARNING, "SYN_SENT SYN ?"); /* TODO: reset */ goto close_and_reset; } if (!(tiflags & TH_ACK)) { DCC_LOG(LOG_WARNING, "SYN_SENT ACK ?"); /* TODO: reset */ goto close_and_reset; } if (ti_len != 0) { DCC_LOG(LOG_WARNING, "ti_len != 0"); /* TODO: reset */ goto close_and_reset; } /* update the send sequence */ tp->snd_seq++; if (tp->snd_seq != ti_ack) { DCC_LOG3(LOG_WARNING, "<%05x> tp->snd_seq(%d) != ti_ack(%d)", (int)tp, tp->snd_seq, ti_ack); /* TODO: reset */ goto close_and_reset; } tp->snd_off--; tp->snd_max--; // tp->snd_off = 0; // tp->snd_max = 0; if (optlen) tcp_parse_options(tp, th, th->th_opt, optlen); /* Advance tp->ti_seq to correspond to first data byte. */ ti_seq++; if (ti_len > rcv_wnd) { DCC_LOG3(LOG_WARNING, "<%05x> ti_len(%d) > rcv_wnd(%d)", (int)tp, ti_len, rcv_wnd); /* TODO: if data, trim to stay within window. */ ti_len = rcv_wnd; } /* update the sequence number */ tp->rcv_nxt = ti_seq; /* update the window size */ tp->snd_wnd = ntohs(th->th_win); tp->t_state = TCPS_ESTABLISHED; DCC_LOG1(LOG_INFO, "<%05x> [ESTABLISHED]", (int)tp); /* TODO: initialization of receive urgent pointer tcp->rcv_up = ti_seq; */ /* XXX: */ tp->t_flags |= TF_ACKNOW; thinkos_cond_broadcast(tp->t_cond); goto step6; close_and_reset: tp->t_state = TCPS_CLOSED; pcb_move((struct pcb *)tp, &__tcp__.active, &__tcp__.closed); DCC_LOG1(LOG_INFO, "<%05x> [CLOSED]", (int)tp); /* XXX: discard the data */ mbuf_queue_free(&tp->snd_q); mbuf_queue_free(&tp->rcv_q); /* notify the upper layer */ thinkos_cond_broadcast(tp->t_cond); goto dropwithreset; } /* States other than LISTEN or SYN_SENT First check timestamp, if present. Then check that at least some bytes of segment are within receive window. If segment begins before rcv_nxt, drop leading data (and SYN); if nothing left, just ti_ack. */ /* Trim Segment so Data is Within Window Ref.: TCP/IP Illustrated Volume 2, pg. 954 */ todrop = tp->rcv_nxt - ti_seq; if (todrop > 0) { if (tiflags & TH_SYN) { DCC_LOG(LOG_INFO, "SYN"); tiflags &= ~TH_SYN; ti_seq++; todrop--; } if ((todrop > ti_len) || ((todrop == ti_len) && ((tiflags & TH_FIN) == 0))) { tiflags &= ~TH_FIN; tp->t_flags |= TF_ACKNOW; todrop = ti_len; } DCC_LOG4(LOG_WARNING, "<%05x> drop: len=%d drop=%d rem=%d!", (int)tp, ti_len, todrop, ti_len - todrop); /* adjust the data pointer */ data += todrop; ti_seq += todrop; ti_len -= todrop; /* TODO: adjust the urgent pointer */ } /* FIXME: only reset the connection if there are no more application to handle the incomming data, half-close */ if ((tp->t_state > TCPS_FIN_WAIT_1) && (ti_len)) { DCC_LOG1(LOG_INFO, "<%05x> segment received after FIN", (int)tp); /* TODO: stat */ goto dropwithreset; } /* If segment ends after window, drop trailing data and (PUSH and FIN); if nothing left, just ACK. Ref.: TCP/IP Illustrated Volume 2, pg. 958 */ todrop = (ti_seq + ti_len) - (tp->rcv_nxt + rcv_wnd); DCC_LOG4(LOG_INFO, "ti_seq=%u ti_len=%d rcv_nxt=%u rcv_wnd=%d", ti_seq, ti_len, tp->rcv_nxt, rcv_wnd); /* */ if (todrop > 0) { // TCP_LOG(tp, "tcp_input: trailing data drop"); if (todrop >= ti_len) { /* * If a new connection request is received * while in TIME_WAIT, drop the old connection ... * Ref.: TCP/IP Illustrated Volume 2, pg. 958 if ((tiflags & TH_SYN) && (tp->t_state == TCPS_TIMEWAIT) && (SEQ_GT(ti_seq, tp->rcv_nxt))) { __tcp__.iss += tcp_issincr; tcp_rst(tp); goto findpcb; } */ if ((rcv_wnd == 0) && (ti_seq == tp->rcv_nxt)) { tp->t_flags |= TF_ACKNOW; } else goto dropafterack; } DCC_LOG2(LOG_WARNING, "<%05x> data drop: %d!", (int)tp, todrop); ti_len -= todrop; tiflags &= ~(TH_PSH | TH_FIN); } /* If the RST bit is set eximine the state: ... Ref.: TCP/IP Illustrated Volume 2, pg. 964 */ if ((tiflags & TH_RST)) { DCC_LOG1(LOG_WARNING, "<%05x> RST received", (int)tp); switch(tp->t_state) { case TCPS_SYN_RCVD: // tp->errno = ECONNREFUSED; goto close; case TCPS_ESTABLISHED: case TCPS_CLOSE_WAIT: // tp->errno = ECONNRESET; close: /* discard the data */ mbuf_queue_free(&tp->snd_q); mbuf_queue_free(&tp->rcv_q); tp->t_state = TCPS_CLOSED; pcb_move((struct pcb *)tp, &__tcp__.active, &__tcp__.closed); DCC_LOG1(LOG_INFO, "<%05x> [CLOSED]", (int)tp); /* notify the upper layer */ thinkos_cond_broadcast(tp->t_cond); /* PCBs in the close state should be cleared by the application */ goto drop; case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: /* Our side was already closed */ tcp_pcb_free(tp); goto drop; } } /* If a SYN is in the window, then this is an error and we send an RST and drop the connection. Ref.: TCP/IP Illustrated Volume 2, pg. 965 */ if ((tiflags & TH_SYN)) { DCC_LOG1(LOG_WARNING, "<%05x> the SYN bit is set inside the window", (int)tp); goto dropwithreset; } /* If the ACK bit is off we drop the segment and return. */ if ((!(tiflags & TH_ACK))) { DCC_LOG1(LOG_WARNING, "<%05x> the ACK bit is off", (int)tp); goto drop; } /* * ACK processing. * Ref.: TCP/IP Illustrated Volume 2, pg. 969 * */ DCC_LOG4(LOG_INFO, "ack=%u una=%u nxt=%u max=%u", ti_ack, snd_una, snd_nxt, snd_max); switch(tp->t_state) { case TCPS_SYN_RCVD: if (SEQ_GT(snd_una, ti_ack) || SEQ_GT(ti_ack, snd_max)) { DCC_LOG1(LOG_WARNING, "<%05x> ti_ack < snd_una || snd_max < ti_ack", (int)tp); goto dropwithreset; } tp->t_state = TCPS_ESTABLISHED; tp->snd_off--; tp->snd_max--; DCC_LOG1(LOG_INFO, "<%05x> SYN ackd [ESTABLISHED]", (int)tp); /* notify the upper layer*/ // thinkos_cond_signal(tp->t_cond); /* TODO: tcp reassembly tcp_reass(tp); */ case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: /* TODO: tcp reassembly tcp_reass(tp); */ if (SEQ_LEQ(ti_ack, snd_una)) { /* TODO: check for completly duplicated ACKs. Ref.: TCP/IP Illustrated Volume 2, pg. 971 */ if ((ti_len == 0) && (tiwin == tp->snd_wnd)) { if ((tp->t_rxmt_tmr == 0) || ti_ack != snd_una) { // dupacks = 0; } else { DCC_LOG2(LOG_INFO, "duplicated ACK. ti_ack=%u snd_una=%u", ti_ack, snd_una); } } else { // dupacks = 0; } break; } /* Check out of range ACK */ /* Ref.: TCP/IP Illustrated Volume 2, pg. 974 */ if (SEQ_GT(ti_ack, snd_max)) { /* TODO: tcpstat.tcps_rcvacktoomuch++; */ DCC_LOG3(LOG_WARNING, "(%04x) out of range ACK. " "th_ack=%u > snd_max=%u !", (int)tp, ti_ack, snd_max); goto dropafterack; } acked = ti_ack - snd_una; /* TODO: tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; */ DCC_LOG1(LOG_INFO, "acked=%d", acked); /* If all outstanding data is acked, stop retransmit timer else restarts it .... Ref.: TCP/IP Illustrated Volume 2, pg. 976 */ if (ti_ack == snd_max) { tp->t_rxmt_tmr = 0; tp->t_rxmt_cnt = 0; needoutput = 1; DCC_LOG(LOG_INFO, "acked all data, rxmt tmr stopped"); } else { /* TODO: peristent timer */ // if (tp->t_persist_tmr == 0) { DCC_LOG(LOG_INFO, "not all data acked restart rxmt tmr"); tp->t_rxmt_tmr = tcp_rxmtintvl[tp->t_rxmt_cnt / 2]; // } } /* TODO: tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; */ /* TODO: remove acknowledged data from send buffer Ref.: TCP/IP Illustrated Volume 2, pg. 978 */ /* FIXME: send buffer bytes count */ if (acked > tp->snd_q.len) { mbuf_queue_trim(&tp->snd_q, tp->snd_q.len); ourfinisacked = 1; } else { /* TODO: estimate the send window */ mbuf_queue_trim(&tp->snd_q, acked); ourfinisacked = 0; } /* awaken a thread waiting on the send buffer ... */ thinkos_cond_broadcast(tp->t_cond); snd_una = ti_ack; if (SEQ_LT(snd_nxt, snd_una)) { snd_nxt = snd_una; } tp->snd_seq = snd_una; tp->snd_off = snd_nxt - tp->snd_seq; tp->snd_max = snd_max - tp->snd_seq; DCC_LOG4(LOG_INFO, "<%05x> snd_seq=%u snd_max=%u snd_q.len=%d", (int)tp, tp->snd_seq, snd_max, tp->snd_q.len); switch(tp->t_state) { case TCPS_FIN_WAIT_1: if (ourfinisacked) { /* FIXME: If we can't receive any more data.. Ref.: TCP/IP Illustrated Volume 2, pg. 979 */ tp->t_conn_tmr = 4 * tcp_msl; tp->t_state = TCPS_FIN_WAIT_2; DCC_LOG1(LOG_INFO, "<%05x> [FIN_WAIT_2]", (int)tp); } break; case TCPS_CLOSING: if (ourfinisacked) { mbuf_queue_free(&tp->snd_q); mbuf_queue_free(&tp->rcv_q); tp->t_state = TCPS_TIME_WAIT; DCC_LOG1(LOG_INFO, "<%05x> [TIME_WAIT]", (int)tp); tp->t_rxmt_tmr = 0; tp->t_conn_tmr = 2 * tcp_msl; DCC_LOG1(LOG_INFO, "stop rxmt tmr, start 2MSL tmr: %d", tp->t_conn_tmr); } break; case TCPS_LAST_ACK: if (ourfinisacked) { tcp_pcb_free(tp); goto drop; } break; case TCPS_TIME_WAIT: /* restart the finack timer Ref.: TCP/IP Illustrated Volume 2, pg. 981 */ tp->t_conn_tmr = 2 * tcp_msl; goto dropafterack; } break; } DCC_LOG4(LOG_INFO, "<%05x> recvd=%d acked=%d rcv_q.len=%d", (int)tp, ti_len, acked, tp->rcv_q.len); step6: /* Update window information Ref.: TCP/IP Illustrated Volume 2, pg. 982 */ DCC_LOG(LOG_MSG, "setp6"); // if ((tiflags & TH_ACK) && (tiwin > tp->snd_wnd)) { if ((tiflags & TH_ACK) && (tiwin != tp->snd_wnd)) { /* Keep track of pure window updates */ /* TODO: TCP Statistics */ /* TODO: Update window information */ DCC_LOG1(LOG_INFO, "window update, win=%d", tiwin); tp->snd_wnd = tiwin; needoutput = 1; } /* TODO: Urgent mode processing */ /* Process the segment text, merging it into the TCP sequencing queue, dodata: ... Ref.: TCP/IP Illustrated Volume 2, pg. 988 */ if ((ti_len || (tiflags & TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { if ((ti_seq == tp->rcv_nxt) && (tp->t_state == TCPS_ESTABLISHED)) { /* append data */ int n; tp->t_flags |= TF_DELACK; n = mbuf_queue_add(&tp->rcv_q, data, ti_len); if (n != ti_len) { DCC_LOG2(LOG_WARNING, "no more mbufs, %d != %d", n, ti_len); } ti_len = n; tp->rcv_nxt += ti_len; /* TODO: statistics */ tiflags &= TH_FIN; // if (tp->rcv_q.len == ti_len) { // DCC_LOG3(LOG_INFO, "<%05x> rcvd %d, signaling %d ...", // (int)tp, ti_len, tp->t_cond); /* * notify the upper layer of the data arrival... */ thinkos_cond_signal(tp->t_cond); // } else { // DCC_LOG2(LOG_INFO, "<%05x> rcvd %d", (int)tp, ti_len); // } } else { /* TODO: half-close */ /* TODO: reassembly */ // m = mlink_free(m); if (tp->t_state == TCPS_ESTABLISHED) { // DCC_LOG(LOG_WARNING, "out of order, drop!"); DCC_LOG(LOG_WARNING, "out of order, drop"); TCP_PROTO_STAT_ADD(rx_drop, 1); } tp->t_flags |= TF_ACKNOW; } } else { DCC_LOG(LOG_INFO, "!!!!!!!!!"); tiflags &= ~TH_FIN; } /* FIN Processing */ if (tiflags & TH_FIN) { if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } switch(tp->t_state) { case TCPS_SYN_RCVD: case TCPS_ESTABLISHED: tp->t_state = TCPS_CLOSE_WAIT; DCC_LOG1(LOG_INFO, "<%05x> [CLOSE_WAIT]", (int)tp); /* notify the application that our peer has closed its side. Sockets: marks the socket as write-only */ if (tp->rcv_q.len == 0) { thinkos_cond_broadcast(tp->t_cond); } break; case TCPS_FIN_WAIT_1: tp->t_state = TCPS_CLOSING; DCC_LOG1(LOG_INFO, "<%05x> [CLOSING]", (int)tp); break; case TCPS_FIN_WAIT_2: mbuf_queue_free(&tp->rcv_q); mbuf_queue_free(&tp->snd_q); tp->t_state = TCPS_TIME_WAIT; DCC_LOG1(LOG_INFO, "<%05x> [TIME_WAIT]", (int)tp); tp->t_rxmt_tmr = 0; tp->t_conn_tmr = 2 * tcp_msl; DCC_LOG1(LOG_INFO, "stop rxmt tmr, start 2MSL tmr: %d", tp->t_conn_tmr); break; case TCPS_TIME_WAIT: /* restart the counter */ tp->t_conn_tmr = 2 * tcp_msl; break; } } /* Final Processing */ if (needoutput || (tp->t_flags & TF_ACKNOW)) { if (needoutput) { DCC_LOG(LOG_INFO, "needoutput, call tcp_out."); } if (tp->t_flags & TF_ACKNOW) { DCC_LOG(LOG_INFO, "ACKNOW set, call tcp_out."); } /* schedule output */ tcp_output_sched(tp); } return 0; dropafterack: DCC_LOG1(LOG_INFO, "<%05x> drop and ACK", (int)tp); if (tiflags & TH_RST) goto drop; tp->t_flags |= TF_ACKNOW; /* schedule output */ tcp_output_sched(tp); return 0; dropwithreset: DCC_LOG1(LOG_TRACE, "<%05x> drop and RST", (int)tp); ret = 0; /* TODO: check for a broadcast/multicast */ if (!(tiflags & TH_RST)) { if (tiflags & TH_ACK) { ret = tcp_respond(iph, th, 0, ti_ack, TH_RST); } else if (tiflags & TH_SYN) { ti_len++; ret = tcp_respond(iph, th, ti_seq + ti_len, 0, TH_ACK | TH_RST); } } TCP_PROTO_STAT_ADD(rx_drop, 1); return ret; drop: DCC_LOG(LOG_TRACE, "drop"); TCP_PROTO_STAT_ADD(rx_drop, 1); return 0; }
int usb_cdc_read(usb_cdc_class_t * cl, void * buf, unsigned int len, unsigned int msec) { struct usb_cdc_acm_dev * dev = (struct usb_cdc_acm_dev *)cl; int ret; int n; DCC_LOG2(LOG_INFO, "len=%d msec=%d", len, msec); if ((n = dev->rx_cnt - dev->rx_pos) > 0) { DCC_LOG(LOG_INFO, "read from intern buffer"); goto read_from_buffer; }; usb_dev_ep_nak(dev->usb, dev->out_ep, false); if ((ret = thinkos_sem_timedwait(RX_SEM, msec)) < 0) { if (ret == THINKOS_ETIMEDOUT) { DCC_LOG(LOG_INFO, "timeout!!"); } return ret; } if (len >= CDC_EP_IN_MAX_PKT_SIZE) { n = usb_dev_ep_pkt_recv(dev->usb, dev->out_ep, buf, len); DCC_LOG1(LOG_INFO, "wakeup, pkt rcv extern buffer: %d bytes", n); return n; } n = usb_dev_ep_pkt_recv(dev->usb, dev->out_ep, dev->rx_buf, CDC_EP_IN_MAX_PKT_SIZE); DCC_LOG1(LOG_INFO, "wakeup, pkt rcv intern buffer: %d bytes", n); { char * s = (char *)dev->rx_buf; (void)s; if (n == 1) DCC_LOG1(LOG_INFO, "%02x", s[0]); else if (n == 2) DCC_LOG2(LOG_INFO, "%02x %02x", s[0], s[1]); else if (n == 3) DCC_LOG3(LOG_INFO, "%02x %02x %02x", s[0], s[1], s[2]); else if (n == 4) DCC_LOG4(LOG_INFO, "%02x %02x %02x %02x", s[0], s[1], s[2], s[3]); else if (n == 5) DCC_LOG5(LOG_INFO, "%02x %02x %02x %02x %02x", s[0], s[1], s[2], s[3], s[4]); else if (n == 6) DCC_LOG6(LOG_INFO, "%02x %02x %02x %02x %02x %02x", s[0], s[1], s[2], s[3], s[4], s[5]); else if (n == 7) DCC_LOG7(LOG_INFO, "%02x %02x %02x %02x %02x %02x %02x", s[0], s[1], s[2], s[3], s[4], s[5], s[6]); else if (n == 8) DCC_LOG8(LOG_INFO, "%02x %02x %02x %02x %02x %02x %02x %02x", s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]); else DCC_LOG8(LOG_INFO, "%02x %02x %02x %02x %02x %02x %02x %02x ...", s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]); } dev->rx_pos = 0; dev->rx_cnt = n; read_from_buffer: DCC_LOG(LOG_INFO, "reading from buffer"); /* get data from the rx buffer if not empty */ n = MIN(n, len); memcpy(buf, &dev->rx_buf[dev->rx_pos], n); dev->rx_pos += n; return n; #if 0 { int rem; uint8_t * cp = (uint8_t *)buf; rem = n; while (rem > 4) { DCC_LOG4(LOG_INFO, "%02x %02x %02x %02x", cp[0], cp[1], cp[2], cp[3]); rem -= 4; cp += 4; } switch (rem) { case 3: DCC_LOG3(LOG_INFO, "%02x %02x %02x", cp[0], cp[1], cp[2]); break; case 2: DCC_LOG2(LOG_INFO, "%02x %02x", cp[0], cp[1]); break; case 1: if ((*cp) >= ' ') { DCC_LOG1(LOG_INFO, "'%c'", cp[0]); } else { DCC_LOG1(LOG_INFO, "%02x", cp[0]); } break; } } #endif }
/*********************************************************************** ICE Driver Methods ***********************************************************************/ static int cm3ice_comm_sync(cm3ice_ctrl_t * ctrl, ice_comm_t * comm) { jtag_tap_t * tap = ctrl->tap; /* Reload the COMM address */ if (jtag_mem_ap_rd32(tap, 8 * 4, &ctrl->comm_addr) != JTAG_ADI_ACK_OK_FAULT) { DCC_LOG(LOG_WARNING, "jtag_mem_ap_rd32() failed!"); return ICE_ST_FAULT; } if ((ctrl->comm_addr == 0x00000000) || (ctrl->comm_addr == 0xffffffff)) { DCC_LOG1(LOG_INFO, "comm block not found! comm_addr=0x%08x", ctrl->comm_addr); return 0; } DCC_LOG1(LOG_TRACE, "COMM=0x%08x", ctrl->comm_addr); /* get the state of the device's COMM buffer */ jtag_mem_ap_read(tap, ctrl->comm_addr, &ctrl->cc, 8); DCC_LOG4(LOG_TRACE, "COMM: dbg=%d dev=%d tx_tail=%d tx_head=%d", ctrl->cc.rw.dbg, ctrl->cc.ro.dev, ctrl->cc.rw.tx_tail, ctrl->cc.ro.tx_head); if (ctrl->cc.ro.dev == DEV_CONNECTED) { if (ctrl->cc.rw.dbg == DBG_CONNECTED) { DCC_LOG(LOG_TRACE, "COMM already connected..."); return 0; } if (ctrl->cc.rw.dbg != DBG_SYNC) { DCC_LOG1(LOG_WARNING, "DEV=CONNECTED, DBG!=(SYNC|CONNECTED) %02x??", ctrl->cc.rw.dbg); return 0; } DCC_LOG(LOG_TRACE, "COMM: [CONNECTED]"); ctrl->cc.rw.dbg = DBG_CONNECTED; /* update the state of the buffer */ if (jtag_mem_ap_wr32(tap, ctrl->comm_addr + 4, ctrl->cc.rw.u32) != JTAG_ADI_ACK_OK_FAULT) { DCC_LOG(LOG_WARNING, "jtag_mem_ap_wr32() failed!"); return ICE_ST_FAULT; } return 0; } if (ctrl->cc.ro.dev == DEV_SYNC) { if (ctrl->cc.rw.dbg == DBG_SYNC) { DCC_LOG(LOG_TRACE, "DEV=SYNC, DBG=SYNC, wating ...."); return 0; } if (ctrl->cc.rw.dbg == DBG_CONNECTED) { DCC_LOG(LOG_WARNING, "DEV=SYNC, DBG=CONNECTED ???"); } DCC_LOG(LOG_TRACE, "COMM: [SYNC]"); ctrl->cc.rw.dbg = DBG_SYNC; /* ensure the buffer is flushed */ ctrl->cc.rw.tx_tail = 0; ctrl->cc.rw.rx_head = 0; /* update the state of the buffer */ if (jtag_mem_ap_wr32(tap, ctrl->comm_addr + 4, ctrl->cc.rw.u32) != JTAG_ADI_ACK_OK_FAULT) { DCC_LOG(LOG_WARNING, "jtag_mem_ap_wr32() failed!"); return ICE_ST_FAULT; } return 0; } DCC_LOG(LOG_INFO, "COMM: [IDLE]"); return 0; }
void module_contorl_seq(struct ss_device * dev, uint32_t ctl) { device_led_default(dev, ctl); switch (ctl & 0x7) { case 0:/* 0 0 0 */ /* Outputs: 1 2 3 5 */ dev->out1 = 1; /* Pulse */ dev->out2 = 1; dev->out3 = 1; dev->out5 = 1; DCC_LOG(LOG_MSG, "Pu 1 1 1"); break; case 4: /* 0 0 1 */ dev->out1 = 1; /* Pulse */ dev->out3 = 1; dev->out5 = 1; DCC_LOG(LOG_MSG, "Pu NC 1 1"); break; case 2: /* 0 1 0 */ dev->out1 = 0; dev->out2 = 1; dev->out3 = 1; dev->out5 = 1; DCC_LOG(LOG_MSG, "0 1 1 1"); break; case 6: /* 0 1 1 */ dev->out1 = 0; dev->out3 = 1; dev->out5 = 1; DCC_LOG(LOG_MSG, "0 NC 1 1"); break; case 1: /* 1 0 0 */ dev->out1 = 1; /* Pulse */ dev->out3 = 0; dev->out5 = 0; DCC_LOG(LOG_MSG, "Pu NC 0 0"); break; case 5: /* 1 0 1 */ dev->out1 = 0; /* Pulse */ dev->out2 = 0; dev->out3 = 1; /* Pulse */ dev->out5 = 1; /* Pulse */ DCC_LOG(LOG_MSG, "Pu 0 Pu Pu"); break; case 3: /* 1 1 0 */ dev->out1 = 0; dev->out2 = 0; dev->out5 = 0; DCC_LOG(LOG_MSG, "0 NC 0 0"); break; case 7: /* 1 1 1 */ dev->out1 = 0; dev->out2 = 0; dev->out3 = 1; /* Pulse */ dev->out5 = 1; /* Pulse */ DCC_LOG(LOG_MSG, "0 0 Pu Pu"); break; } DCC_LOG4(LOG_INFO, "%d %d %d %d", dev->out1, dev->out2, dev->out3, dev->out5); }