|
| 1 | +#include "net_bus.hpp" |
| 2 | +#include "net_driver.hpp" |
| 3 | +#include "virtio_net_pci/virtio_net_pci.hpp" |
| 4 | +#include "pci.h" |
| 5 | +#include "std/std.h" |
| 6 | +#include "console/kio.h" |
| 7 | +#include "types.h" |
| 8 | +#include "networking/interface_manager.h" |
| 9 | +#include "networking/network.h" |
| 10 | + |
| 11 | +#define kprintfv(fmt, ...) ({ if (verbose){ kprintf(fmt, ##__VA_ARGS__); } }) |
| 12 | + |
| 13 | +typedef struct { |
| 14 | + NetDriver* drv; |
| 15 | + char ifname[16]; |
| 16 | + char hw_ifname[32]; |
| 17 | + uint8_t mac[6]; |
| 18 | + uint16_t mtu; |
| 19 | + uint16_t header_size; |
| 20 | + uint8_t kind; |
| 21 | + uint32_t speed_mbps; |
| 22 | + uint8_t duplex; |
| 23 | +} net_nic_desc_t; |
| 24 | + |
| 25 | +static net_nic_desc_t g_nics[MAX_L2_INTERFACES]; |
| 26 | +static size_t g_count = 0; |
| 27 | +static int g_eth_next = 0; |
| 28 | +static int g_wif_next = 0; |
| 29 | +static int g_net_next = 0; |
| 30 | +static bool g_lo_added = false; |
| 31 | +static bool verbose = true; |
| 32 | + |
| 33 | +static void memzero(void* p, size_t n){ |
| 34 | + memset(p,0,n); |
| 35 | +} |
| 36 | + |
| 37 | +static size_t u32_to_dec(char* dst, size_t cap, unsigned v){ |
| 38 | + char tmp[16]; |
| 39 | + int n=0; |
| 40 | + if (cap==0) return 0; |
| 41 | + if (v==0){ if (cap>1){ dst[0]='0'; dst[1]=0; return 1; } dst[0]=0; return 0; } |
| 42 | + while (v>0 && n<16){ tmp[n++] = (char)('0' + (v%10)); v/=10; } |
| 43 | + size_t i=0; |
| 44 | + while (i<cap-1 && n>0){ dst[i++] = tmp[--n]; } |
| 45 | + dst[i]=0; |
| 46 | + return i; |
| 47 | +} |
| 48 | + |
| 49 | +static void make_ifname(char* dst, size_t cap, const char* prefix){ |
| 50 | + if (!dst || cap==0) return; |
| 51 | + int idx=0; |
| 52 | + if (prefix && prefix[0]=='e'){ idx = g_eth_next++; } |
| 53 | + else if (prefix && prefix[0]=='w'){ idx = g_wif_next++; } |
| 54 | + else { idx = g_net_next++; } |
| 55 | + size_t j=0; |
| 56 | + if (prefix){ j = strncpy(dst, cap, prefix); } else { dst[0]='n'; dst[1]='i'; dst[2]='c'; dst[3]=0; j=3; } |
| 57 | + if (j<cap-1) u32_to_dec(dst+j, cap-j, (unsigned)idx); |
| 58 | +} |
| 59 | + |
| 60 | +static void add_loopback(){ |
| 61 | + if (g_lo_added) return; |
| 62 | + if (g_count >= MAX_L2_INTERFACES) return; |
| 63 | + net_nic_desc_t* d = &g_nics[g_count++]; |
| 64 | + d->drv = nullptr; |
| 65 | + memzero(d->ifname,sizeof(d->ifname)); |
| 66 | + memzero(d->hw_ifname,sizeof(d->hw_ifname)); |
| 67 | + d->ifname[0]='l'; d->ifname[1]='o'; d->ifname[2]='0'; d->ifname[3]=0; |
| 68 | + d->hw_ifname[0]='l'; d->hw_ifname[1]='o'; d->hw_ifname[2]='o'; d->hw_ifname[3]='p'; d->hw_ifname[4]='b'; d->hw_ifname[5]='a'; d->hw_ifname[6]='c'; d->hw_ifname[7]='k'; d->hw_ifname[8]=0; |
| 69 | + memzero(d->mac,6); |
| 70 | + d->mtu = 65535; |
| 71 | + d->header_size = 0; |
| 72 | + d->kind = NET_IFK_LOCALHOST; |
| 73 | + d->speed_mbps = 0xFFFFFFFFu; |
| 74 | + d->duplex = NET_IFK_LOCALHOST; |
| 75 | + g_lo_added = true; |
| 76 | + kprintfv("[net-bus] added loopback ifname=%s",d->ifname); |
| 77 | +} |
| 78 | + |
| 79 | +static bool is_virtio_net(uint16_t vendor, uint16_t device, uint8_t class_code, uint8_t subclass){ |
| 80 | + if (vendor != 0x1AF4) return false; |
| 81 | + if (class_code == 0x02) return true; |
| 82 | + if (device == 0x1000) return true; |
| 83 | + return false; |
| 84 | +} |
| 85 | + |
| 86 | +int net_bus_init(){ |
| 87 | + g_count = 0; |
| 88 | + g_eth_next = 0; |
| 89 | + g_wif_next = 0; |
| 90 | + g_net_next = 0; |
| 91 | + g_lo_added = false; |
| 92 | + |
| 93 | + kprintfv("[net-bus] init"); |
| 94 | + |
| 95 | + pci_device_info infos[64]; |
| 96 | + size_t n = pci_enumerate(infos, 64); |
| 97 | + kprintfv("[net-bus] pci_enumerate=%u",(unsigned)n); |
| 98 | + |
| 99 | + int nic_ord = 0; |
| 100 | + |
| 101 | + for (size_t i=0;i<n;i++){ |
| 102 | + if (g_count >= MAX_L2_INTERFACES){ kprintfv("[net-bus] cap reached"); break; } |
| 103 | + |
| 104 | + const uint16_t ven = infos[i].vendor; |
| 105 | + const uint16_t dev = infos[i].device; |
| 106 | + const uint8_t cls = infos[i].class_code; |
| 107 | + const uint8_t sub = infos[i].subclass; |
| 108 | + |
| 109 | + if (cls != 0x02) continue; |
| 110 | + |
| 111 | + kprintfv("[net-bus] net dev %u ven=%x dev=%x class=%x sub=%x prog=%x addr=%x", |
| 112 | + (unsigned)i, ven, dev, cls, sub, infos[i].prog_if, (uintptr_t)infos[i].addr); |
| 113 | + |
| 114 | + const char* if_prefix = "net"; |
| 115 | + uint8_t kind = NET_IFK_OTHER; |
| 116 | + if (sub == 0x00){ if_prefix = "eth"; kind = NET_IFK_ETH; } |
| 117 | + |
| 118 | + bool matched = false; |
| 119 | + |
| 120 | + if (is_virtio_net(ven, dev, cls, sub)){ |
| 121 | + VirtioNetDriver* d = new VirtioNetDriver(); |
| 122 | + if (!d){ kprintf("[net-bus][warn] virtio alloc failed"); continue; } |
| 123 | + |
| 124 | + uint32_t irq_base = NET_IRQ_BASE + (uint32_t)(2*nic_ord); |
| 125 | + if (!d->init_at(infos[i].addr, irq_base)){ |
| 126 | + kprintf("[net-bus][warn] virtio init_at failed"); |
| 127 | + delete d; |
| 128 | + continue; |
| 129 | + } |
| 130 | + |
| 131 | + net_nic_desc_t* e = &g_nics[g_count++]; |
| 132 | + e->drv = d; |
| 133 | + |
| 134 | + d->get_mac(e->mac); |
| 135 | + e->mtu = d->get_mtu(); |
| 136 | + e->header_size = d->get_header_size(); |
| 137 | + e->kind = kind; |
| 138 | + e->speed_mbps = d->get_speed_mbps(); |
| 139 | + e->duplex = d->get_duplex(); |
| 140 | + |
| 141 | + make_ifname(e->ifname, sizeof(e->ifname), if_prefix); |
| 142 | + |
| 143 | + const char* hw = d->hw_ifname(); |
| 144 | + strncpy(e->hw_ifname, sizeof(e->hw_ifname), (hw && hw[0]) ? hw : "vnet"); |
| 145 | + |
| 146 | + kprintfv("[net-bus] added if=%s mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u hw=%s irq_base=%u spd=%u dup=%u", |
| 147 | + e->ifname, e->mac[0],e->mac[1],e->mac[2],e->mac[3],e->mac[4],e->mac[5], |
| 148 | + e->mtu, e->header_size, e->hw_ifname, (unsigned)irq_base, |
| 149 | + (unsigned)e->speed_mbps, (unsigned)e->duplex); |
| 150 | + |
| 151 | + nic_ord += 1; |
| 152 | + matched = true; |
| 153 | + } |
| 154 | + //else if future drivers |
| 155 | + |
| 156 | + if (!matched){ |
| 157 | + kprintf("[net-bus][warn] no driver for ven=%x dev=%x class=%x sub=%x", ven, dev, cls, sub); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + if (!g_lo_added && g_count < MAX_L2_INTERFACES) add_loopback(); |
| 162 | + |
| 163 | + kprintfv("[net-bus] total_if=%u",(unsigned)g_count); |
| 164 | + return (int)g_count; |
| 165 | +} |
| 166 | + |
| 167 | + |
| 168 | +void net_bus_enable_verbose(){ |
| 169 | + verbose = true; |
| 170 | +} |
| 171 | + |
| 172 | +int net_bus_count(){ |
| 173 | + return (int)g_count; |
| 174 | +} |
| 175 | + |
| 176 | +NetDriver* net_bus_driver(int idx){ |
| 177 | + if (idx < 0 || (size_t)idx >= g_count) return nullptr; |
| 178 | + return g_nics[idx].drv; |
| 179 | +} |
| 180 | + |
| 181 | +const char* net_bus_ifname(int idx){ |
| 182 | + if (idx < 0 || (size_t)idx >= g_count) return nullptr; |
| 183 | + return g_nics[idx].ifname; |
| 184 | +} |
| 185 | + |
| 186 | +const char* net_bus_hw_ifname(int idx){ |
| 187 | + if (idx < 0 || (size_t)idx >= g_count) return nullptr; |
| 188 | + return g_nics[idx].hw_ifname; |
| 189 | +} |
| 190 | + |
| 191 | +void net_bus_get_mac(int idx, uint8_t out_mac[6]){ |
| 192 | + if (idx < 0 || (size_t)idx >= g_count) { memzero(out_mac,6); return; } |
| 193 | + memcpy(out_mac, g_nics[idx].mac, 6); |
| 194 | +} |
| 195 | + |
| 196 | +uint16_t net_bus_get_mtu(int idx){ |
| 197 | + if (idx < 0 || (size_t)idx >= g_count) return 0; |
| 198 | + return g_nics[idx].mtu; |
| 199 | +} |
| 200 | + |
| 201 | +uint16_t net_bus_get_header_size(int idx){ |
| 202 | + if (idx < 0 || (size_t)idx >= g_count) return 0; |
| 203 | + return g_nics[idx].header_size; |
| 204 | +} |
| 205 | + |
| 206 | +uint8_t net_bus_get_kind(int idx){ |
| 207 | + if (idx < 0 || (size_t)idx >= g_count) return NET_IFK_UNKNOWN; |
| 208 | + return g_nics[idx].kind; |
| 209 | +} |
| 210 | + |
| 211 | +uint32_t net_bus_get_speed_mbps(int idx){ |
| 212 | + if (idx < 0 || (size_t)idx >= g_count) return 0xFFFFFFFFu; |
| 213 | + return g_nics[idx].speed_mbps; |
| 214 | +} |
| 215 | + |
| 216 | +uint8_t net_bus_get_duplex(int idx){ |
| 217 | + if (idx < 0 || (size_t)idx >= g_count) return 0xFFu; |
| 218 | + return g_nics[idx].duplex; |
| 219 | +} |
0 commit comments