// 指定した MAC アドレスがリストに登録されているかどうかチェックする bool SeEthIsSenderMacAddressExistsInList(SE_ETH *e, UCHAR *mac_address) { bool ret = false; // 引数チェック if (e == NULL || mac_address == NULL) { return false; } SeLock(e->SenderMacListLock); { UINT i; bool exists = false; for (i = 0;i < SE_LIST_NUM(e->SenderMacList);i++) { SE_ETH_SENDER_MAC *m = SE_LIST_DATA(e->SenderMacList, i); if (SeCmp(m->MacAddress, mac_address, SE_ETHERNET_MAC_ADDR_SIZE) == 0) { m->Expires = SeTick64() + (UINT64)SE_ETH_SENDER_MAC_EXPIRES; ret = true; } } SeEthDeleteOldSenderMacList(e); } SeUnlock(e->SenderMacListLock); return ret; }
// タイマのセット void SeTimerSet(SE_TIMER *t, UINT interval) { SE_TIMER_ENTRY *e; // 引数チェック if (t == NULL) { return; } // タイマエントリの挿入 SeLock(t->TimerEntryLock); { SE_TIMER_ENTRY st; UINT64 target_tick = SeTick64() + (UINT64)interval; SeZero(&st, sizeof(st)); st.Tick = target_tick; // 同一の Tick を指すタイマエントリが存在するかどうかチェックする if (SeSearch(t->TimerEntryList, &st) == NULL) { // タイマエントリの新規作成 e = SeZeroMalloc(sizeof(SE_TIMER_ENTRY)); e->Tick = target_tick; // 挿入 SeInsert(t->TimerEntryList, e); // タイマを調整 SeTimerAdjust(t); } } SeUnlock(t->TimerEntryLock); }
// タイマの調整 void SeTimerAdjust(SE_TIMER *t) { // 引数チェック if (t == NULL) { return; } SeLock(t->TimerEntryLock); { UINT num = SE_LIST_NUM(t->TimerEntryList); if (num >= 1) { SE_TIMER_ENTRY *e = SE_LIST_DATA(t->TimerEntryList, 0); // タイマの状態が変化したかどうか調べる if (e->Tick != t->CurrentTimerTargetTick) { UINT64 now = SeTick64(); UINT64 interval64; UINT interval; // 先頭のタイマエントリまでの時間を求める if (e->Tick > now) { interval64 = e->Tick - now; } else { interval64 = 0; } interval = (UINT)interval64; if (interval == 0) { interval = 1; } t->CurrentTimerTargetTick = e->Tick; // タイマを設定する SeSysSetTimer(t->TimerHandle, interval); } } } SeUnlock(t->TimerEntryLock); }
// 古い MAC アドレスをリストから削除 void SeEthDeleteOldSenderMacList(SE_ETH *e) { UINT64 now; // 引数チェック if (e == NULL) { return; } now = SeTick64(); SeLock(e->SenderMacListLock); { UINT i; SE_LIST *o = NULL; for (i = 0;i < SE_LIST_NUM(e->SenderMacList);i++) { SE_ETH_SENDER_MAC *m = SE_LIST_DATA(e->SenderMacList, i); if (m->Expires <= now) { if (o == NULL) { o = SeNewList(NULL); } SeAdd(o, m); } } if (o != NULL) { for (i = 0;i < SE_LIST_NUM(o);i++) { SE_ETH_SENDER_MAC *m = SE_LIST_DATA(o, i); SeDelete(e->SenderMacList, m); SeFree(m); } SeFreeList(o); } } SeUnlock(e->SenderMacListLock); }
// 次の受信パケットの取得 void *SeEthGetNextRecvPacket(SE_ETH *e) { void *ret; // 引数チェック if (e == NULL) { return NULL; } SeLock(e->RecvQueueLock); { ret = SeGetNext(e->RecvQueue); } SeUnlock(e->RecvQueueLock); return ret; }
// MAC アドレスをリストへ追加 void SeEthAddSenderMacList(SE_ETH *e, UCHAR *mac_address) { // 引数チェック if (e == NULL || mac_address == NULL) { return; } SeLock(e->SenderMacListLock); { UINT i; bool exists = false; for (i = 0;i < SE_LIST_NUM(e->SenderMacList);i++) { SE_ETH_SENDER_MAC *m = SE_LIST_DATA(e->SenderMacList, i); if (SeCmp(m->MacAddress, mac_address, SE_ETHERNET_MAC_ADDR_SIZE) == 0) { m->Expires = SeTick64() + (UINT64)SE_ETH_SENDER_MAC_EXPIRES; exists = true; } } if (exists == false) { SE_ETH_SENDER_MAC *m = SeZeroMalloc(sizeof(SE_ETH_SENDER_MAC)); m->Expires = SeTick64() + (UINT64)SE_ETH_SENDER_MAC_EXPIRES; SeCopy(m->MacAddress, mac_address, SE_ETHERNET_MAC_ADDR_SIZE); SeAdd(e->SenderMacList, m); } SeEthDeleteOldSenderMacList(e); } SeUnlock(e->SenderMacListLock); }
// 64 bit Tick 値の取得 UINT64 SeTick64Internal() { UINT64 ret; SeLock(rt->TickLock); { UINT tick = SeTick(); if (rt->LastTick > tick) { // Tick の値が 1 周した rt->TickRoundCounter++; } rt->LastTick = tick; ret = (UINT64)tick + (UINT64)rt->TickRoundCounter * 4294967296ULL; } SeUnlock(rt->TickLock); return ret; }
// CSR レジスタ用 MMIO ハンドラ int pro100_mm_handler(void *data, phys_t gphys, bool wr, void *buf, uint len, u32 flags) { int ret = 0; PRO100_CTX *ctx = (PRO100_CTX *)data; SeLock(ctx->lock); // 範囲チェック if (((UINT64)gphys >= (UINT64)ctx->csr_mm_addr) && ((UINT64)gphys < ((UINT64)ctx->csr_mm_addr) + (UINT64)PRO100_CSR_SIZE)) { UINT offset = (UINT)((UINT64)gphys - (UINT64)ctx->csr_mm_addr); if (len == 1 || len == 2 || len == 4) { if (wr == 0) { UINT ret_data = 0; if (pro100_hook_read(ctx, offset, len, &ret_data) == false) { ret_data = pro100_read(ctx, offset, len); } if (len == 1) { *((UCHAR *)buf) = (UCHAR)ret_data; } else if (len == 2) { *((USHORT *)buf) = (USHORT)ret_data; } else if (len == 4) { *((UINT *)buf) = (UINT)ret_data; } } else { UINT data = 0; if (len == 1) { data = (UINT)(*((UCHAR *)buf)); } else if (len == 2) { data = (UINT)(*((USHORT *)buf)); } else if (len == 4) { data = (UINT)(*((UINT *)buf)); } if (pro100_hook_write(ctx, offset, data, len) == false) { pro100_write(ctx, offset, data, len); } } ret = 1; } } SeUnlock(ctx->lock); return ret; }
// NIC からの受信コールバック関数 void SeEthNicCallback(SE_HANDLE nic_handle, UINT num_packets, void **packets, UINT *packet_sizes, void *param) { SE_ETH *e; UINT i; UINT num_insert_packets; // 引数チェック if (nic_handle == NULL || param == NULL) { return; } e = (SE_ETH *)param; num_insert_packets = 0; SeLock(e->RecvQueueLock); { for (i = 0;i < num_packets;i++) { UINT size = packet_sizes[i]; UCHAR *packet = (UCHAR *)packets[i]; if (size >= SE_ETHERNET_HEADER_SIZE) { UCHAR *src_mac = packet + 6; UCHAR *dst_mac = packet; if (SeEthIsSenderMacAddressExistsInList(e, src_mac) == false) { bool b = false; UINT type = SeEthParseEthernetPacket(packet, size, e->MyMacAddress); if (type & SE_ETHER_PACKET_TYPE_VALID) { if (e->IsPromiscusMode) { b = true; } else { if (type & SE_ETHER_PACKET_TYPE_FOR_ME) { b = true; } } } if (b) { SeInsertQueue(e->RecvQueue, SeClone(packet, size)); num_insert_packets++; } } } } } SeUnlock(e->RecvQueueLock); if (num_insert_packets != 0) { e->RecvCallback(e, e->RecvCallbackParam); } }
// タイマのコールバック関数 void SeTimerCallback(SE_HANDLE timer_handle, void *param) { SE_TIMER *t; bool invoke_callback = false; UINT64 now = 0; // 引数チェック if (timer_handle == NULL || param == NULL) { return; } t = (SE_TIMER *)param; SeLock(t->TimerEntryLock); { UINT i; SE_LIST *o = NULL; now = SeTick64(); // 登録されているタイマエントリのうち現在時刻またはそれよりも前に // 発動すべきもののリストを取得する for (i = 0;i < SE_LIST_NUM(t->TimerEntryList);i++) { SE_TIMER_ENTRY *e = SE_LIST_DATA(t->TimerEntryList, i); if (now >= e->Tick) { if (o == NULL) { o = SeNewList(NULL); } SeAdd(o, e); } } if (o != NULL) { // 不要になったタイマエントリをリストから削除する for (i = 0;i < SE_LIST_NUM(o);i++) { SE_TIMER_ENTRY *e = SE_LIST_DATA(o, i); SeDelete(t->TimerEntryList, e); SeFree(e); } SeFreeList(o); t->CurrentTimerTargetTick = 0; invoke_callback = true; } // タイマ調整 SeTimerAdjust(t); } SeUnlock(t->TimerEntryLock); if (invoke_callback) { // コールバック関数を呼び出す t->TimerCallback(t, now, t->TimerCallbackParam); } }