Annotation of nono/vm/ethernet.cpp, revision 1.1.1.12

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.6   root        7: //
                      8: // Ethernet 基本クラス
                      9: //
                     10: 
1.1.1.10  root       11: #if !defined(SELFTEST)
1.1       root       12: #include "ethernet.h"
1.1.1.7   root       13: #include "config.h"
1.1.1.6   root       14: #include "hostnet.h"
                     15: #include "scheduler.h"
1.1       root       16: 
                     17: // コンストラクタ
1.1.1.9   root       18: EthernetDevice::EthernetDevice(uint objid_)
1.1.1.8   root       19:        : inherited(objid_)
1.1       root       20: {
                     21: }
                     22: 
                     23: // デストラクタ
                     24: EthernetDevice::~EthernetDevice()
                     25: {
1.1.1.6   root       26:        if ((bool)hostnet) {
1.1.1.12! root       27:                hostnet->ResetRxCallback();
1.1.1.6   root       28:        }
1.1       root       29: }
                     30: 
                     31: // 動的なコンストラクション
                     32: bool
                     33: EthernetDevice::Create()
                     34: {
1.1.1.12! root       35:        // ホストドライバを作成してこのデバイスと紐付ける。
        !            36:        // ポート名は継承先ごとに Init() で設定している。
1.1.1.8   root       37:        int n = GetId() - OBJ_ETHERNET0;
1.1.1.11  root       38:        try {
1.1.1.12! root       39:                hostnet.reset(new HostNetDevice(this, n, ""));
1.1.1.11  root       40:        } catch (...) { }
                     41:        if ((bool)hostnet == false) {
                     42:                warnx("Failed to initialize HostNetDevice(%u) at %s", n, __method__);
                     43:                return false;
                     44:        }
1.1       root       45: 
1.1.1.12! root       46:        auto func = ToDeviceCallback(&EthernetDevice::HostRxCallback);
        !            47:        hostnet->SetRxCallback(func, 0);
1.1       root       48: 
                     49:        return true;
                     50: }
                     51: 
1.1.1.6   root       52: // これは Host スレッドから呼ばれる
                     53: void
1.1.1.12! root       54: EthernetDevice::HostRxCallback(uint32 dummy)
1.1.1.5   root       55: {
1.1.1.6   root       56:        // スレッドを超えるためにメッセージを投げる
1.1.1.8   root       57:        int n = GetId() - OBJ_ETHERNET0;
                     58:        scheduler->SendMessage(MessageID::HOSTNET_RX(n));
1.1.1.7   root       59: }
                     60: 
                     61: // 設定ファイルから MAC アドレスを読み込む。
                     62: // MAC アドレスを保持するデバイスが呼び出すこと。MAC アドレスを保持する
                     63: // デバイスがイーサネットデバイスとは限らず、例えば LANCE を採用している
                     64: // 機種ではたいてい ROM か誰かが MAC アドレスを持っている。
                     65: //
                     66: // 引数 accept_rom が true なら、設定 ethernet-macaddr=rom を許可する。
                     67: // これは (お手持ちの実機) ROM イメージが MAC アドレスを保持しているため、
                     68: // 指定(や生成)不要なケースで指定できる (prom.cpp 参照)。
                     69: // 引数 accept_rom が false で、設定値に "rom" が指定されるとエラーにする。
                     70: //
                     71: // "rom" が指定されて許可されている場合 mac は触らず true を返す。
                     72: // MAC アドレスが指定されているか自動生成したかで取得できれば mac に格納して
                     73: // true を返す。それ以外の場合は、エラーメッセージを表示して false を返す。
                     74: /*static*/ bool
1.1.1.10  root       75: EthernetDevice::GetConfigMacAddr(uint n, MacAddr *mac, bool accept_rom)
1.1.1.7   root       76: {
1.1.1.9   root       77:        std::string keyname = string_format("ethernet%u-macaddr", n);
1.1.1.8   root       78:        const ConfigItem& item = gConfig->Find(keyname);
1.1.1.7   root       79:        const std::string& val = item.AsString();
                     80: 
                     81:        if (val == "rom") {
                     82:                // ROM に書いてあるのを使う。
                     83:                if (accept_rom) {
                     84:                        return true;
                     85:                } else {
                     86:                        item.Err("\"rom\" cannot be specified in this vmtype");
                     87:                        return false;
                     88:                }
                     89:        } else {
                     90:                if (val == "auto") {
                     91:                        // 自動生成。
                     92:                        // 出来れば生成したのを覚えといて、次からそれを使いたい。
                     93:                        if (0) {
                     94:                        } else {
                     95:                                mac->Generate();
                     96:                        }
                     97:                } else {
                     98:                        // ユーザ指定
                     99:                        if (mac->FromString(val) == false) {
                    100:                                item.Err("Invalid MAC address");
                    101:                                return false;
                    102:                        }
                    103:                }
                    104:        }
                    105: 
                    106:        return true;
1.1.1.5   root      107: }
1.1.1.10  root      108: 
                    109: #endif // !SELFTEST
                    110: 
                    111: // CRC32 を計算する。
                    112: //
                    113: // CRC と言ってもおそらく5つのパラメータによって定まる亜種が多数あるが、
                    114: // Ethernet で使われる CRC32 はおそらく以下のもの。
                    115: //  初期値: 0xffffffff
                    116: //  多項式: 0x04c11db6
                    117: //  RefIn : false
                    118: //  RefOut: false (出力をビットリバースしない)
                    119: //  XorOut: false (出力を XOR しない)
                    120: //
                    121: // NetBSD の src/sys/net/if_ethersubr.c にある ether_crc32_be() がこれと同じ。
                    122: //
                    123: // その隣にある ether_crc32_le() は
                    124: //  初期値: 0xffffffff
                    125: //  多項式: 0xedb88320
                    126: //  RefIn : true
                    127: //  RefOut: false (出力をビットリバースしない)
                    128: //  XorOut: false (出力を XOR しない)
                    129: // というパラメータだが、RefIn と多項式のビットが反転しているだけなので
                    130: // 結果をビットリバースすれば同じものになる。
                    131: //
                    132: // ちなみに ether_crc32_* の_le, _be はエンディアンではなく、どっち向きに
                    133: // 処理するかを示しており、名前が紛らわしい。
                    134: /*static*/ uint32
                    135: EthernetDevice::CRC32(const uint8 *buf, size_t buflen)
                    136: {
                    137:        static const uint32 CRC_POLY = 0x04c11db6;
                    138:        uint32 crc;
                    139:        uint32 cy;
                    140: 
                    141:        crc = 0xffffffff;
                    142:        for (size_t i = 0; i < buflen; i++) {
1.1.1.11  root      143:                uint32 s = buf[i];
1.1.1.10  root      144:                for (size_t j = 0; j < 8; j++) {
                    145:                        cy = ((crc & 0x80000000U) ? 0x01 : 0x00) ^ (s & 0x01);
                    146:                        crc <<= 1;
                    147:                        s >>= 1;
                    148:                        if (cy) {
                    149:                                crc = (crc ^ CRC_POLY) | cy;
                    150:                        }
                    151:                }
                    152:        }
                    153: 
                    154:        return crc;
                    155: }
                    156: 
                    157: // MAC アドレスの CRC32 を計算する限定版。
                    158: // 6バイトが uint64 にリトルエンディアン的に格納されていると分かっている。
                    159: /*static*/ uint32
                    160: EthernetDevice::CRC32(const MacAddr& mac)
                    161: {
                    162:        static const uint32 CRC_POLY = 0x04c11db6;
                    163:        uint32 crc;
                    164:        uint64 s = mac.Get();
                    165: 
                    166:        crc = 0xffffffff;
                    167:        for (size_t i = 0; i < mac.size() * 8; i++) {
1.1.1.11  root      168:                uint32 cy = ((crc & 0x80000000U) ? 0x01 : 0x00) ^ (s & 0x01);
1.1.1.10  root      169:                crc <<= 1;
                    170:                s >>= 1;
                    171:                if (cy) {
                    172:                        crc = (crc ^ CRC_POLY) | cy;
                    173:                }
                    174:        }
                    175: 
                    176:        return crc;
                    177: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.