void if_loop_input_task (intptr_t exinf) { T_NET_BUF *input; ID tskid; get_tid(&tskid); syslog(LOG_NOTICE, "[LOOP INPUT:%d] started.", tskid); while (true) { if (rcv_dtq(DTQ_LOOP_INPUT, (intptr_t)&input) == E_OK) { NET_COUNT_LOOP(net_count_loop.in_octets, input->len); NET_COUNT_LOOP(net_count_loop.in_packets, 1); #if defined(SUPPORT_INET4) /* IPv4 入力関数を呼び出す */ if (IP4_VHL_V(GET_IP4_HDR(input)->vhl) == IPV4_VERSION) ip_input(input); #endif /* of #if defined(SUPPORT_INET4) */ #if defined(SUPPORT_INET6) /* IPv6 入力関数を呼び出す */ if (IP6_VCF_V(ntohl(GET_IP6_HDR(input)->vcf)) == IPV6_VERSION) ip6_input(input); #endif /* of #if defined(SUPPORT_INET6) */ } } }
void ip6_input (T_NET_BUF *input) { T_IP6_HDR *ip6h; T_IN6_IFADDR *ia6; T_IFNET *ifp; ER_UINT noff; uint_t next, nest, plen, offp, nextp; uint_t (*func)(T_NET_BUF **, uint_t *, uint_t *); NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_OCTETS], input->len - IF_HDR_SIZE); NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_PACKETS], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInReceives, 1); /* IP ヘッダの長さをチェックする。*/ if (input->len < IF_IP6_HDR_SIZE) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_SHORT], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1); goto buf_rel; } ip6h = GET_IP6_HDR(input); /* バージョンをチェックする。*/ if (IP6_VCF_V(ntohl(ip6h->vcf)) != IPV6_VERSION) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_VER], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1); goto buf_rel; } /* * 次のデータグラムは破棄する。 * * ・始点アドレスがマルチキャスト * ・終点アドレスが未定義 * * ネットワークインタフェースがループバックでないとき、 * 次のデータグラムも破棄する。 * * ・始点アドレスがループバック * ・終点アドレスがループバック * * 悪意のあるユーザが TCP/UDP スタックの混乱や * セキュリティチェックをバイパスするため、IPv4 * マップアドレスを悪用することを防ぐため * 以下のデータグラムは破棄する。 * * ・始点アドレスが ::ffff:127.0.0.1 * ・終点アドレスが ::ffff:127.0.0.1 */ if (IN6_IS_ADDR_MULTICAST(&ip6h->src) || IN6_IS_ADDR_UNSPECIFIED(&ip6h->dst)) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1); goto buf_rel; } if (IN6_IS_ADDR_V4MAPPED(&ip6h->src) || IN6_IS_ADDR_V4MAPPED(&ip6h->dst)) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1); goto buf_rel; } #ifdef SUPPORT_LOOP #else /* of #ifdef SUPPORT_LOOP */ if (IN6_IS_ADDR_LOOPBACK(&ip6h->src) || IN6_IS_ADDR_LOOPBACK(&ip6h->dst)) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1); goto buf_rel; } #endif /* of #ifdef SUPPORT_LOOP */ ifp = IF_GET_IFNET(); if (IN6_IS_ADDR_MULTICAST(&ip6h->dst)) { /* 宛先がマルチキャストの場合の処理 */ NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInMcastPkts, 1); if (!in6_lookup_multi(ifp, &ip6h->dst)) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1); goto buf_rel; } } else { if ((ia6 = in6_lookup_ifaddr(ifp, &ip6h->dst)) == NULL) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1); goto buf_rel; } /* アドレスが未解決の場合はデータグラムを破棄する。*/ if (IFA6_IS_NOTREADY(ia6)) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1); goto buf_rel; } } /* オフセットを設定する。*/ offp = GET_IP6_NEXT_HDR(input) - input->buf; /* ペイロード長を取り出す。*/ plen = ntohs(ip6h->plen); /* 次ヘッダの位置を初期化する。*/ nextp = offsetof(T_IP6_HDR, next); /* * 中継点 (Hop-by-Hop) オプションヘッダのチェック */ if (ip6h->next == IPPROTO_HOPOPTS) { /* 中継点ヘッダの長さをチェックする。*/ if (plen < sizeof(T_IP6_HBH_HDR)) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_SHORT], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1); goto buf_rel; } if ((noff = ip6_hopopts_input(input, &offp, &nextp)) < 0) { if (noff == IP6_OPT_RET_ERR) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1); goto buf_rel; } else if (noff == IP6_OPT_RET_REL) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1); return; } } /* * ペイロード長が 0 で、中継点オプションがあるときは、 * 巨大ペイロード・オプションが含まれなければならない。 * このとき、巨大ペイロード・オプションにある * ペイロード長をチェックする必要があるが、本実装では、 * 巨大ペイロード・オプションを未知のオプションとして * 扱うので、何もしない。 */ next = ((T_IP6_HBH_HDR *)(ip6h + 1))->next; } else next = ip6h->next; /* IPv6 データグラム長をチェックする。*/ if (input->len - IF_IP6_HDR_SIZE < plen) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_SHORT], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInTruncatedPkts, 1); goto buf_rel; } else if (input->len > IF_IP6_HDR_SIZE + plen) input->len = IF_IP6_HDR_SIZE + plen; /* 上位プロトコル処理関数を呼び出す。*/ nest = 0; while (next != IPPROTO_DONE) { if (++ nest > IP6_HDR_NEST_LIMIT) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PROTO], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInUnknownProtos, 1); goto buf_rel; } else if ((func = get_upper_proto(next)) == NULL) { NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PROTO], 1); NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1); NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInUnknownProtos, 1); /* icmp6_error でネットワークバッファを開放する。*/ icmp6_error(input, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXT_HEADER, nextp); return; } else { next = (*func)(&input, &offp, &nextp); } } return; buf_rel: NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1); syscall(rel_net_buf(input)); }
void tcp_respond (T_NET_BUF *output, T_TCP_CEP *cep, T_TCP_SEQ ack, T_TCP_SEQ seq, uint_t rbfree, uint8_t flags) { T_IP_HDR *iph; T_TCP_HDR *tcph; uint_t win = 0; if ((flags & TCP_FLG_RST) == 0) win = rbfree; /* * output が NULL でなければ、これは入力したセグメントの * net_buf で、そのまま再利用する。 */ if (output != NULL) { T_IN_ADDR ipaddr; uint16_t portno; /* * IPv4 では、IP ヘッダのオプションを削除する。 * IPv6 では、拡張ヘッダを削除する。 */ if (IP_REMOVE_OPTIONS(output) != E_OK) { syscall(rel_net_buf(output)); return; } iph = GET_IP_HDR(output); /* IP アドレスを交換する。*/ ipaddr = iph->src; iph->src = iph->dst; iph->dst = ipaddr; #if defined(SUPPORT_INET6) /* トラヒッククラスとフローラベルをクリアする。*/ iph->vcf = htonl(IP6_MAKE_VCF(IP6_VCF_V(ntohl(iph->vcf)), 0)); #endif /* of #if defined(SUPPORT_INET6) */ /* TCP SDU 長を 0 にする。*/ SET_IP_SDU_SIZE(iph, TCP_HDR_SIZE); tcph = GET_TCP_HDR(output, IF_IP_TCP_HDR_OFFSET); /* ポート番号を交換する。*/ portno = tcph->sport; tcph->sport = tcph->dport; tcph->dport = portno; /* TCP ヘッダに情報を設定する。*/ tcph->doff = TCP_MAKE_DATA_OFF(TCP_HDR_SIZE); } /* cep が NULL であれば、何もしないで終了する。*/ else if (cep == NULL) return; else { if (tcp_get_segment(&output, cep, 0, 0, (uint_t)(net_buf_max_siz() - IF_IP_TCP_HDR_SIZE), NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF) != E_OK) return; tcph = GET_TCP_HDR(output, IF_IP_TCP_HDR_OFFSET); flags |= TCP_FLG_ACK; } tcph->seq = htonl(seq); tcph->ack = htonl(ack); tcph->win = htons(win); tcph->flags = flags; tcph->urp = tcph->sum = 0; /* * チェックサムを設定する。 */ tcph->sum = IN_CKSUM(output, IPPROTO_TCP, IF_IP_TCP_HDR_OFFSET, (uint_t)GET_TCP_HDR_SIZE2(output, IF_IP_TCP_HDR_OFFSET)); /* ネットワークバッファ長を調整する。*/ output->len = (uint16_t)GET_IF_IP_TCP_HDR_SIZE2(output, IF_IP_TCP_HDR_OFFSET); #ifdef TCP_CFG_TRACE tcp_output_trace(output, cep); #endif /* of #ifdef TCP_CFG_TRACE */ /* ネットワーク層 (IP) の出力関数を呼び出す。*/ IP_OUTPUT(output, TMO_TCP_OUTPUT); }