void icmp_error (uint8_t code, T_NET_BUF *input) { T_IP4_HDR *ip4h; T_ICMP4_HDR *icmp4h; T_NET_BUF *output; T_IN4_ADDR saddr; uint_t len, ip4hl, align; ip4h = GET_IP4_HDR(input); ip4hl = GET_IP4_HDR_SIZE(ip4h); /* 送信用の IP データグラムを獲得する。*/ if (input->len - ip4hl < 8) len = input->len - ip4hl; else len = 8; saddr = ntohl(ip4h->src); if (in4_get_datagram(&output, (uint_t)(ICMP4_HDR_SIZE + ip4hl + len), 0, &saddr, NULL, IPPROTO_ICMP, IP4_DEFTTL, NBA_SEARCH_ASCENT, TMO_ICMP_OUTPUT) != E_OK) return; /* ICMP ヘッダを設定する。*/ icmp4h = GET_ICMP4_HDR(output, IF_IP4_ICMP4_HDR_OFFSET); icmp4h->type = ICMP4_UNREACH; icmp4h->code = code; icmp4h->data.addr= 0; /* エラーが発生した IP ヘッダと データ 8 オクテットをコピーする。*/ memcpy(GET_ICMP4_SDU(output, IF_IP4_ICMP4_HDR_OFFSET), GET_IP4_HDR(input), (size_t)(ip4hl + len)); /* 4 オクテット境界のデータ長 */ align = (len + 3) >> 2 << 2; /* 4 オクテット境界までパディングで埋める。*/ if (align > len) memset((uint8_t*)GET_ICMP4_SDU(output, IF_IP4_ICMP4_HDR_OFFSET) + ip4hl + len, 0, (size_t)(align - len)); /* チェックサムを計算する。*/ icmp4h->sum = 0; icmp4h->sum = in_cksum(icmp4h, (uint_t)(ICMP4_HDR_SIZE + ip4hl + align)); /* 送信する。*/ NET_COUNT_ICMP4(net_count_icmp4.out_octets, output->len - GET_IF_IP4_HDR_SIZE(output)); NET_COUNT_ICMP4(net_count_icmp4.out_packets, 1); NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1); NET_COUNT_MIB(icmp_stats.icmpOutDestUnreachs, 1); ip_output(output, TMO_ICMP_OUTPUT); }
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) */ } } }
static void icmp_redirect (T_NET_BUF *input, uint_t ihoff) { T_IP4_HDR *ip4h, *sip4h; T_ICMP4_HDR *icmp4h; ip4h = GET_IP4_HDR(input); icmp4h = GET_ICMP4_HDR(input, ihoff); sip4h = (T_IP4_HDR *)GET_ICMP4_SDU(input, ihoff); /* * 内容チェック、以下の場合はエラー * * ・ICMP コードが、ICMP4_REDIRECT_PORT_AND_HOST (3) 以上 * ・データグラム長が、ICMP の最小長より短い (IP ヘッダ + ICMP ヘッダ + IP ヘッダ + 8) * ・データグラム長が、ICMP の最大長より短い * ・ */ if (icmp4h->code > ICMP4_REDIRECT_PORT_AND_HOST || ip4h->len < GET_IP4_ICMP4_HDR_SIZE(input) + 8 + IP4_HDR_SIZE || ip4h->len < GET_IP4_ICMP4_HDR_SIZE(input) + 8 + (IP4_VHL_HL(sip4h->vhl) << 2)) { NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1); return; } in4_rtredirect(icmp4h->data.addr, sip4h->dst, IN_RTF_REDIRECT, TMO_IN_REDIRECT); }
static void icmp_unreach (T_NET_BUF *input, uint_t ihoff) { T_IP4_HDR *ip4h; uint8_t code; ER error; NET_COUNT_MIB(icmp_stats.icmpInDestUnreachs, 1); ip4h = (T_IP4_HDR*)GET_ICMP4_SDU(input, ihoff); code = GET_ICMP4_HDR(input, ihoff)->code; error = code2error[code]; if (ip4h->proto == IPPROTO_TCP) { #ifdef SUPPORT_TCP memcpy(GET_IP4_HDR(input), ip4h, input->len - (IP4_HDR_SIZE + ICMP4_HDR_SIZE)); input->len -= IP4_HDR_SIZE + ICMP4_HDR_SIZE; tcp_notify(input, error); #endif /* of #ifdef SUPPORT_TCP */ } else syslog(LOG_NOTICE, "[ICMP] error, code: %d.", code); }
static void icmp_echo (T_NET_BUF *input, uint_t ihoff) { T_IP4_HDR *ip4h; T_ICMP4_HDR *icmp4h; T_IN4_ADDR addr; NET_COUNT_MIB(icmp_stats.icmpInEchos, 1); /* メッセージの型をエコー要求 (8) から エコー応答 (0) に */ /* 変更して送り返す。 */ icmp4h = GET_ICMP4_HDR(input, ihoff); icmp4h->type = ICMP4_ECHO_REPLY; /* IP ヘッダの宛先と発信元を交換する。*/ ip4h = GET_IP4_HDR(input); addr = ip4h->src; ip4h->src = ip4h->dst; ip4h->dst = addr; /* チェックサムを計算する。*/ icmp4h->sum = 0; icmp4h->sum = in_cksum(icmp4h, (uint_t)(((input->len - GET_IF_IP4_HDR_SIZE(input)) + 3) >> 2 << 2)); /* 送信する。*/ NET_COUNT_ICMP4(net_count_icmp4.out_octets, input->len - GET_IF_IP4_HDR_SIZE(input)); NET_COUNT_ICMP4(net_count_icmp4.out_packets, 1); NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1); NET_COUNT_MIB(icmp_stats.icmpOutEchoReps, 1); ip_output(input, TMO_ICMP_OUTPUT); }
static T_NET_BUF * ip_reass (T_IP4_HDR *ip4h, T_NET_BUF *input) { T_NET_BUF *frag, *prev; T_IN4_ADDR dst, src; int_t ix; uint_t id, off, len; NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_FRAGS], 1); NET_COUNT_MIB(ip_stats.ipReasmReqds, 1); src = ntohl(ip4h->src); dst = ntohl(ip4h->dst); NTOHS(ip4h->id); NTOHS(ip4h->flg_off); id = ip4h->id; ix = id % NUM_IP4_FRAG_QUEUE; syscall(wai_sem(SEM_IP4_FRAG_QUEUE)); /* * ID、IPアドレス、上位プロトコルが異なるフラグメントがキューに有れば破棄する。 */ frag = ip_frag_queue[ix]; if (frag != NULL && (id != GET_IP4_HDR(frag)->id || dst != frag_dst[ix] || src != ntohl(GET_IP4_HDR(frag)->src) || ip4h->proto != GET_IP4_HDR(frag)->proto)) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1); NET_COUNT_MIB(ip_stats.ipReasmFails, 1); ip_freef(ix); } frag = ip_frag_queue[ix]; if (frag == NULL) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN], 1); /* 新規の ID なら、宛先アドレスを保存して、キューにつなぐ。*/ frag_dst [ix] = dst; ip_frag_queue[ix] = input; ((T_QIP4_HDR *)ip4h)->next = NULL; input = NULL; /* 再構成タイムアウトを設定する。*/ ip4h->ttl = IP4_FRAGTTL; } else { /* 正しい位置に挿入する。*/ prev = NULL; while (frag != NULL && IP4_FLGOFF_OFF(ip4h->flg_off) > IP4_FLGOFF_OFF(GET_QIP4_HDR(frag)->flg_off)) { prev = frag; frag = GET_QIP4_HDR(frag)->next; } ((T_QIP4_HDR *)ip4h)->next = frag; if (prev == NULL) { ip4h->ttl = GET_QIP4_HDR(frag)->ttl; ip_frag_queue[ix] = input; } else GET_QIP4_HDR(prev)->next = input; input = NULL; /* 全てのフラグメントが揃っているか調べる。*/ off = 0; for (frag = ip_frag_queue[ix]; frag != NULL; frag = GET_QIP4_HDR(frag)->next) { if ((IP4_FLGOFF_OFF(GET_QIP4_HDR(frag)->flg_off) << 3) != off) { /* 途中が抜けていたら終了する。*/ syscall(sig_sem(SEM_IP4_FRAG_QUEUE)); return NULL; } off += ntohs(GET_QIP4_HDR(frag)->len) - (IP4_VHL_HL(GET_QIP4_HDR(frag)->vhl) << 2); prev = frag; } /* 全てのフラグメントが揃ったら再構成する。*/ if ((GET_QIP4_HDR(prev)->flg_off & IP4_MF) == 0) { /* ネットワークバッファを獲得する。*/ if (tget_net_buf(&input, IF_IP4_HDR_SIZE + off, TMO_IP4_FRAG_GET_NET_BUF) == E_OK) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_OK], 1); NET_COUNT_MIB(ip_stats.ipReasmOKs, 1); /* IPv4 ヘッダを設定する。*/ frag = ip_frag_queue[ix]; ip4h = GET_IP4_HDR(input); *ip4h = *GET_IP4_HDR(frag); ip4h->dst = htonl(frag_dst[ix]); ip4h->len = htons(IP4_HDR_SIZE + off); ip4h->vhl = IP4_MAKE_VHL(IPV4_VERSION, IP4_HDR_SIZE >> 2); ip4h->ttl = GET_QIP4_HDR(prev)->ttl; ip4h->flg_off = ip4h->id = 0; /* データグラムを再構成する。*/ off = IP4_HDR_SIZE; while (frag != NULL) { len = ntohs(GET_QIP4_HDR(frag)->len) - (IP4_VHL_HL(GET_QIP4_HDR(frag)->vhl) << 2); memcpy((uint8_t *)ip4h + off, GET_QIP4_SDU(frag), len); off += len; frag = GET_QIP4_HDR(frag)->next; } } else { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_NO_BUF], 1); NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1); NET_COUNT_MIB(ip_stats.ipReasmFails, 1); } /* キューを空にする。*/ ip_freef(ix); }