/* * TINET (TCP/IP Protocol Stack) * * Copyright (C) 2001-2009 by Dep. of Computer Science and Engineering * Tomakomai National College of Technology, JAPAN * * 上記著作権者は,以下の (1)~(4) の条件か,Free Software Foundation * によって公表されている GNU General Public License の Version 2 に記 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, * 利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次の条件を満たすこと. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. * * @(#) $Id: ethernet.c 270 2017-02-09 04:03:47Z coas-nagasima $ */ /* * Ethernet 処理タスクの本体 */ #include #ifdef TARGET_KERNEL_ASP #include #include #include #include "kernel_cfg.h" #endif /* of #ifdef TARGET_KERNEL_ASP */ #ifdef TARGET_KERNEL_JSP #include #include #include "kernel_id.h" #endif /* of #ifdef TARGET_KERNEL_JSP */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SUPPORT_ETHER /* * 変数 */ #if defined(SUPPORT_INET4) const uint8_t ether_broad_cast_addr[ETHER_ADDR_LEN] = { UINT_C(0xff), UINT_C(0xff), UINT_C(0xff), UINT_C(0xff), UINT_C(0xff), UINT_C(0xff) }; #endif /* of #if defined(SUPPORT_INET4) */ /* * 変数 */ /* ネットワークインタフェース構造体 */ #if defined(SUPPORT_INET4) static T_IFNET ether_ifnet = { NULL, /* ネットワークインタフェースのソフトウェア情報 */ { IPV4_ADDR_LOCAL, /* IPv4 アドレス */ IPV4_ADDR_LOCAL_MASK, /* サブネットマスク */ }, }; #endif /* of #if defined(SUPPORT_INET4) */ #if defined(SUPPORT_INET6) static T_IFNET ether_ifnet = { NULL, /* ネットワークインタフェースのソフトウェア情報 */ {0}, /* IPv6 アドレス情報 */ {0}, /* マルチキャスト IPv6 アドレス */ 0, /* フラグ */ }; #endif /* of #if defined(SUPPORT_INET6) */ #ifdef SUPPORT_MIB /* * SNMP の 管理情報ベース (MIB) */ T_IF_STATS if_stats; #endif /* of #ifdef SUPPORT_MIB */ #ifdef ETHER_CFG_802_WARNING /* * 関数 */ static void ieee_802_input (T_NET_BUF *input); /* * ieee_802_input -- IEEE 802.3 入力処理 */ static void ieee_802_input (T_NET_BUF *input) { T_8023MAC_HDR *mhdr; T_8022SNAP_HDR *shdr; mhdr = GET_8023MAC_HDR(input); shdr = GET_8022SNAP_HDR(input); syslog(LOG_WARNING, "[ETHER] unexp 802.3 from: %s, proto: 0x%04x.", mac2str(NULL, mhdr->shost), ntohs(*(uint16_t*)&shdr->type)); } #endif /* of #ifdef ETHER_CFG_802_WARNING */ /* * ether_get_ifnet -- ネットワークインタフェース構造体を返す。 */ T_IFNET * ether_get_ifnet (void) { return ðer_ifnet; } #if defined(SUPPORT_INET6) /* * ether_in6_resolve_multicast -- イーサネットのマルチキャストアドレスへの変換 */ ER ether_in6_resolve_multicast (T_ETHER_ADDR *ifaddr, T_IN6_ADDR *maddr) { /* マルチキャストアドレスかチェックする。*/ if (!IN6_IS_ADDR_MULTICAST(maddr)) return E_PAR; /* イーサネットのマルチキャストアドレスへの変換 */ ether_map_ipv6_multicast(ifaddr, maddr); return E_OK; } #endif /* of #if defined(SUPPORT_INET6) */ /** * Called by a driver when its link goes up */ void ether_set_link_up(T_IFNET *ether) { if (!(ether->flags & IF_FLAG_LINK_UP)) { ether->flags |= IF_FLAG_LINK_UP; if (ether->flags & IF_FLAG_UP) { #if LWIP_ARP /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ if (ether->flags & IF_FLAG_ETHARP) { etharp_gratuitous(ether); } #endif /* LWIP_ARP */ } if (ether->link_callback) { (ether->link_callback)(ether); } } } /** * Called by a driver when its link goes down */ void ether_set_link_down(T_IFNET *ether) { if (ether->flags & IF_FLAG_LINK_UP) { ether->flags &= ~IF_FLAG_LINK_UP; if (ether->link_callback) { (ether->link_callback)(ether); } } } /** * Set callback to be called when link is brought up/down */ void ether_set_link_callback(ether_status_callback_fn link_callback) { ether_ifnet.link_callback = link_callback; } /* * ether_raw_output -- Ethernet インタフェースの出力関数、MAC アドレス解決無し */ ER ether_raw_output (T_NET_BUF *output, TMO tmout) { ER error = E_OK; /* Ethernet 出力キューに投入する。*/ if ((error = tsnd_dtq(DTQ_ETHER_OUTPUT, (intptr_t)output, tmout)) != E_OK) { NET_COUNT_ETHER(net_count_ether.out_err_packets, 1); NET_COUNT_MIB(if_stats.ifOutDiscards, 1); /* IF でネットワークバッファを開放しないフラグをチェックする。*/ if ((output->flags & NB_FLG_NOREL_IFOUT) == 0) { syscall(rel_net_buf(output)); } else { output->flags &= (uint8_t)~NB_FLG_NOREL_IFOUT; } IF_ETHER_NIC_RESET(IF_ETHER_NIC_GET_SOFTC()); } return error; } /* * ether_output -- Ethernet インタフェースの出力関数、MAC アドレス解決有り */ ER ether_output (T_NET_BUF *output, void *dst, T_IF_ADDR *gw, TMO tmout) { T_IF_SOFTC *ic; ER error = E_OK; T_ETHER_HDR *eth; /* 送信元 MAC アドレスを設定する。*/ ic = IF_ETHER_NIC_GET_SOFTC(); eth = GET_ETHER_HDR(output); memcpy(eth->shost, ic->ifaddr.lladdr, ETHER_ADDR_LEN); switch(ntohs(eth->type)) { #if defined(SUPPORT_INET4) case ETHER_TYPE_IP: /* IPv4 */ #ifdef ETHER_CFG_MULTICAST /* マルチキャストアドレスの場合 */ if(IN4_IS_ADDR_MULTICAST(*(uint32_t*)dst)){ /* イーサネットのマルチキャストアドレスへの変換 */ ether_map_ipv4_multicast((T_ETHER_ADDR *)ð->dhost, *(T_IN4_ADDR*)dst); error = ether_raw_output(output, tmout); break; } #endif if (arp_resolve(&ic->ifaddr, output, *(uint32_t*)dst)) { /* true ならアドレス解決済 */ error = ether_raw_output(output, tmout); } break; #endif /* of #if defined(SUPPORT_INET4) */ #if defined(SUPPORT_INET6) case ETHER_TYPE_IPV6: /* IPv6 */ error = nd6_storelladdr((T_ETHER_ADDR*)GET_ETHER_HDR(output)->dhost, (T_IN6_ADDR*)dst, gw); if (error == E_OK) error = ether_raw_output(output, tmout); /* IF でネットワークバッファを開放しないフラグをチェックする。*/ else if ((output->flags & NB_FLG_NOREL_IFOUT) == 0) { syscall(rel_net_buf(output)); } else { output->flags &= (uint8_t)~NB_FLG_NOREL_IFOUT; } break; #endif /* of #if defined(SUPPORT_INET6) */ default: NET_COUNT_MIB(if_stats.ifOutErrors, 1); /* IF でネットワークバッファを開放しないフラグをチェックする。*/ if ((output->flags & NB_FLG_NOREL_IFOUT) == 0) { syscall(rel_net_buf(output)); } else { output->flags &= (uint8_t)~NB_FLG_NOREL_IFOUT; } error = E_PAR; break; } if (error != E_OK) NET_COUNT_ETHER(net_count_ether.out_err_packets, 1); return error; } /* * Ethernet 出力タスク */ void ether_output_task(intptr_t exinf) { T_IF_SOFTC *ic; T_NET_BUF *output; ID tskid; get_tid(&tskid); syslog(LOG_NOTICE, "[ETHER OUTPUT:%d] started.", tskid); ic = IF_ETHER_NIC_GET_SOFTC(); while (true) { while (rcv_dtq(DTQ_ETHER_OUTPUT, (intptr_t*)&output) == E_OK) { NET_COUNT_ETHER(net_count_ether.out_octets, output->len); NET_COUNT_MIB(if_stats.ifOutOctets, output->len + 8); NET_COUNT_ETHER(net_count_ether.out_packets, 1); #ifdef SUPPORT_MIB if ((*(GET_ETHER_HDR(output)->dhost) & ETHER_MCAST_ADDR) == 0) { NET_COUNT_MIB(if_stats.ifOutUcastPkts, 1); } else { NET_COUNT_MIB(if_stats.ifOutNUcastPkts, 1); } #endif /* of #ifdef SUPPORT_MIB */ syscall(wai_sem(ic->semid_txb_ready)); IF_ETHER_NIC_START(ic, output); #ifndef ETHER_NIC_CFG_RELEASE_NET_BUF if ((output->flags & NB_FLG_NOREL_IFOUT) == 0) { syscall(rel_net_buf(output)); } else { output->flags &= (uint8_t)~NB_FLG_NOREL_IFOUT; #ifdef SUPPORT_TCP sig_sem(SEM_TCP_POST_OUTPUT); #endif /* of #ifdef SUPPORT_TCP */ } #endif /* of #ifndef ETHER_NIC_CFG_RELEASE_NET_BUF */ } } } /* * Ethernet 入力タスク */ void ether_input_task(intptr_t exinf) { T_IF_SOFTC *ic; T_NET_BUF *input; T_ETHER_HDR *eth; ID tskid; uint16_t proto; /* ネットワークインタフェース管理を初期化する。*/ ifinit(); /* NIC を初期化する。*/ ic = IF_ETHER_NIC_GET_SOFTC(); IF_ETHER_NIC_PROBE(ic); IF_ETHER_NIC_INIT(ic); /* Ethernet 出力タスクを起動する */ syscall(act_tsk(ETHER_OUTPUT_TASK)); /* ネットワークタイマタスクを起動する */ syscall(act_tsk(NET_TIMER_TASK)); get_tid(&tskid); syslog(LOG_NOTICE, "[ETHER INPUT:%2d] started on MAC Addr: %s.", tskid, mac2str(NULL, ic->ifaddr.lladdr)); #if defined(SUPPORT_INET4) /* ARP を初期化する。*/ arp_init(); #endif /* of #if defined(SUPPORT_INET4) */ ether_ifnet.ic = ic; while (true) { syscall(wai_sem(ic->semid_rxb_ready)); if ((input = IF_ETHER_NIC_READ(ic)) != NULL) { NET_COUNT_ETHER(net_count_ether.in_octets, input->len); NET_COUNT_MIB(if_stats.ifInOctets, input->len + 8); NET_COUNT_ETHER(net_count_ether.in_packets, 1); eth = GET_ETHER_HDR(input); proto = ntohs(eth->type); #ifdef SUPPORT_MIB if ((*eth->dhost & ETHER_MCAST_ADDR) == 0) { NET_COUNT_MIB(if_stats.ifInUcastPkts, 1); } else { NET_COUNT_MIB(if_stats.ifInNUcastPkts, 1); } #endif /* of #ifdef SUPPORT_MIB */ #if defined(SUPPORT_INET4) && defined(ETHER_CFG_ACCEPT_ALL) if ((*eth->dhost & ETHER_MCAST_ADDR) && *eth->dhost != 0xff) { #ifdef ETHER_CFG_MCAST_WARNING if (proto <= 1500) proto = ntohs(*(uint16_t*)&(GET_8022SNAP_HDR(input)->type)); syslog(LOG_WARNING, "[ETHER] mcast addr from: %s, to: %s, proto: 0x%04x.", mac2str(NULL, eth->shost), mac2str(NULL, eth->dhost), proto); #endif /* of #ifdef ETHER_CFG_MCAST_WARNING */ NET_COUNT_ETHER(net_count_ether.in_err_packets, 1); NET_COUNT_MIB(if_stats.ifInErrors, 1); syscall(rel_net_buf(input)); continue; } #endif /* of #if defined(SUPPORT_INET4) && defined(ETHER_CFG_ACCEPT_ALL) */ switch(proto) { #if defined(SUPPORT_INET4) case ETHER_TYPE_IP: /* IP */ ip_input(input); break; case ETHER_TYPE_ARP: /* ARP */ arp_input(&ic->ifaddr, input); break; #endif /* of #if defined(SUPPORT_INET4) */ #if defined(SUPPORT_INET6) case ETHER_TYPE_IPV6: /* IPv6 */ ip6_input(input); break; #endif /* of #if defined(SUPPORT_INET6) */ default: #ifdef ETHER_CFG_UNEXP_WARNING #ifdef ETHER_CFG_802_WARNING if (proto <= 1500) ieee_802_input(input); else syslog(LOG_NOTICE, "[ETHER] unexp proto from: %s, proto: 0x%04x.", mac2str(NULL, GET_ETHER_HDR(input)->shost), proto); #else /* of #ifdef ETHER_CFG_802_WARNING */ syslog(LOG_INFO, "[ETHER] unexp proto from: %s, proto: 0x%04x.", mac2str(NULL, GET_ETHER_HDR(input)->shost), proto); #endif /* of #ifdef ETHER_CFG_802_WARNING */ #endif /* of #ifdef ETHER_CFG_UNEXP_WARNING */ NET_COUNT_ETHER(net_count_ether.in_err_packets, 1); NET_COUNT_MIB(if_stats.ifUnknownProtos, 1); syscall(rel_net_buf(input)); break; } } } } #endif /* of #ifdef SUPPORT_ETHER */