luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

RTL8139.lua (7847B)


      1 #!/usr/bin/env luajit
      2 -- RTL8139 Network Driver Library
      3 -- Provides high-level network interface for RTL8139 network card
      4 
      5 local RTL8139 = {}
      6 
      7 -- Driver state
      8 RTL8139.initialized = false
      9 RTL8139.mac_address = nil
     10 RTL8139.rx_callbacks = {}  -- Packet receive callbacks
     11 
     12 ---Initialize the RTL8139 network card
     13 ---@return boolean success True if initialization succeeded
     14 function RTL8139.init()
     15     if osprint then
     16         osprint("RTL8139.lua: Initializing network driver...\n")
     17     end
     18 
     19     -- Call C function to initialize hardware
     20     if not RTL8139Init then
     21         if osprint then
     22             osprint("RTL8139.lua: ERROR - RTL8139Init function not available\n")
     23         end
     24         return false
     25     end
     26 
     27     local success = RTL8139Init()
     28 
     29     if success then
     30         RTL8139.initialized = true
     31 
     32         -- Get MAC address
     33         RTL8139.mac_address = RTL8139GetMAC()
     34 
     35         if osprint then
     36             osprint("RTL8139.lua: Initialized successfully\n")
     37             if RTL8139.mac_address then
     38                 osprint("RTL8139.lua: MAC Address: ")
     39                 for i = 1, 6 do
     40                     osprint(string.format("%02X", RTL8139.mac_address[i]))
     41                     if i < 6 then osprint(":") end
     42                 end
     43                 osprint("\n")
     44             end
     45         end
     46     else
     47         if osprint then
     48             osprint("RTL8139.lua: Initialization failed\n")
     49         end
     50     end
     51 
     52     return success
     53 end
     54 
     55 ---Get the MAC address of the network card
     56 ---@return table|nil mac Array of 6 bytes, or nil if not initialized
     57 function RTL8139.getMACAddress()
     58     if not RTL8139.initialized then
     59         return nil
     60     end
     61 
     62     return RTL8139.mac_address
     63 end
     64 
     65 ---Get MAC address as a formatted string
     66 ---@return string|nil macString "XX:XX:XX:XX:XX:XX" format
     67 function RTL8139.getMACString()
     68     if not RTL8139.mac_address then
     69         return nil
     70     end
     71 
     72     local parts = {}
     73     for i = 1, 6 do
     74         parts[i] = string.format("%02X", RTL8139.mac_address[i])
     75     end
     76     return table.concat(parts, ":")
     77 end
     78 
     79 ---Send a raw Ethernet packet
     80 ---@param data string Raw packet data (including Ethernet header)
     81 ---@return number bytesent Number of bytes sent, or -1 on error
     82 function RTL8139.send(data)
     83     if not RTL8139.initialized then
     84         return -1
     85     end
     86 
     87     if type(data) ~= "string" then
     88         return -1
     89     end
     90 
     91     return RTL8139Send(data)
     92 end
     93 
     94 ---Receive a raw Ethernet packet (non-blocking)
     95 ---@return string|nil packet Raw packet data, or nil if no packet available
     96 function RTL8139.receive()
     97     if not RTL8139.initialized then
     98         return nil
     99     end
    100 
    101     return RTL8139Receive()
    102 end
    103 
    104 ---Register a callback for received packets
    105 ---@param callback function Function to call when packet is received
    106 ---@param filter table|nil Optional filter {ethertype = 0x0800} to filter packets
    107 ---@return number id Callback ID for later removal
    108 function RTL8139.onReceive(callback, filter)
    109     local id = #RTL8139.rx_callbacks + 1
    110     RTL8139.rx_callbacks[id] = {
    111         callback = callback,
    112         filter = filter
    113     }
    114     return id
    115 end
    116 
    117 ---Remove a receive callback
    118 ---@param id number Callback ID returned by onReceive
    119 function RTL8139.removeReceiveCallback(id)
    120     RTL8139.rx_callbacks[id] = nil
    121 end
    122 
    123 ---Poll for received packets and call callbacks
    124 ---Should be called regularly from main loop
    125 ---@return number count Number of packets processed
    126 function RTL8139.poll()
    127     if not RTL8139.initialized then
    128         return 0
    129     end
    130 
    131     local count = 0
    132 
    133     -- Process all available packets
    134     while true do
    135         local packet = RTL8139.receive()
    136         if not packet then
    137             break
    138         end
    139 
    140         count = count + 1
    141 
    142         -- Parse Ethernet header
    143         local eth = RTL8139.parseEthernetHeader(packet)
    144 
    145         -- Call registered callbacks
    146         for id, cb in pairs(RTL8139.rx_callbacks) do
    147             local should_call = true
    148 
    149             -- Apply filter if present
    150             if cb.filter then
    151                 if cb.filter.ethertype and eth.ethertype ~= cb.filter.ethertype then
    152                     should_call = false
    153                 end
    154             end
    155 
    156             if should_call then
    157                 local success, err = pcall(cb.callback, packet, eth)
    158                 if not success and osprint then
    159                     osprint("RTL8139.lua: Callback error: " .. tostring(err) .. "\n")
    160                 end
    161             end
    162         end
    163     end
    164 
    165     return count
    166 end
    167 
    168 ---Parse Ethernet header from packet
    169 ---@param packet string Raw packet data
    170 ---@return table header Ethernet header fields
    171 function RTL8139.parseEthernetHeader(packet)
    172     if #packet < 14 then
    173         return nil
    174     end
    175 
    176     local header = {}
    177 
    178     -- Destination MAC (6 bytes)
    179     header.dst_mac = {}
    180     for i = 1, 6 do
    181         header.dst_mac[i] = string.byte(packet, i)
    182     end
    183 
    184     -- Source MAC (6 bytes)
    185     header.src_mac = {}
    186     for i = 1, 6 do
    187         header.src_mac[i] = string.byte(packet, 6 + i)
    188     end
    189 
    190     -- EtherType (2 bytes, big endian)
    191     local b1, b2 = string.byte(packet, 13, 14)
    192     header.ethertype = (b1 * 256) + b2
    193 
    194     -- Payload starts at byte 15
    195     header.payload = string.sub(packet, 15)
    196 
    197     return header
    198 end
    199 
    200 ---Build an Ethernet frame
    201 ---@param dst_mac table Destination MAC address (6 bytes)
    202 ---@param src_mac table Source MAC address (6 bytes)
    203 ---@param ethertype number EtherType (0x0800 for IPv4, 0x0806 for ARP, etc.)
    204 ---@param payload string Payload data
    205 ---@return string frame Complete Ethernet frame
    206 function RTL8139.buildEthernetFrame(dst_mac, src_mac, ethertype, payload)
    207     local frame = {}
    208 
    209     -- Destination MAC (6 bytes)
    210     for i = 1, 6 do
    211         frame[#frame + 1] = string.char(dst_mac[i])
    212     end
    213 
    214     -- Source MAC (6 bytes)
    215     for i = 1, 6 do
    216         frame[#frame + 1] = string.char(src_mac[i])
    217     end
    218 
    219     -- EtherType (2 bytes, big endian)
    220     frame[#frame + 1] = string.char(math.floor(ethertype / 256))
    221     frame[#frame + 1] = string.char(ethertype % 256)
    222 
    223     -- Payload
    224     frame[#frame + 1] = payload
    225 
    226     return table.concat(frame)
    227 end
    228 
    229 ---Send an Ethernet frame with automatic source MAC
    230 ---@param dst_mac table Destination MAC address
    231 ---@param ethertype number EtherType
    232 ---@param payload string Payload data
    233 ---@return number bytessent Number of bytes sent
    234 function RTL8139.sendFrame(dst_mac, ethertype, payload)
    235     if not RTL8139.initialized or not RTL8139.mac_address then
    236         return -1
    237     end
    238 
    239     local frame = RTL8139.buildEthernetFrame(dst_mac, RTL8139.mac_address, ethertype, payload)
    240     return RTL8139.send(frame)
    241 end
    242 
    243 ---Send a broadcast packet
    244 ---@param ethertype number EtherType
    245 ---@param payload string Payload data
    246 ---@return number bytessent Number of bytes sent
    247 function RTL8139.sendBroadcast(ethertype, payload)
    248     local broadcast_mac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
    249     return RTL8139.sendFrame(broadcast_mac, ethertype, payload)
    250 end
    251 
    252 ---Common EtherType constants
    253 RTL8139.ETHERTYPE = {
    254     IPV4 = 0x0800,
    255     ARP = 0x0806,
    256     IPV6 = 0x86DD,
    257     VLAN = 0x8100,
    258 }
    259 
    260 ---Format MAC address for display
    261 ---@param mac table MAC address (6 bytes)
    262 ---@return string formatted "XX:XX:XX:XX:XX:XX"
    263 function RTL8139.formatMAC(mac)
    264     if not mac or #mac ~= 6 then
    265         return "00:00:00:00:00:00"
    266     end
    267 
    268     local parts = {}
    269     for i = 1, 6 do
    270         parts[i] = string.format("%02X", mac[i])
    271     end
    272     return table.concat(parts, ":")
    273 end
    274 
    275 ---Parse MAC address from string
    276 ---@param str string "XX:XX:XX:XX:XX:XX" format
    277 ---@return table|nil mac Array of 6 bytes
    278 function RTL8139.parseMAC(str)
    279     local mac = {}
    280     for byte_str in string.gmatch(str, "[^:]+") do
    281         local byte_val = tonumber(byte_str, 16)
    282         if not byte_val then
    283             return nil
    284         end
    285         mac[#mac + 1] = byte_val
    286     end
    287 
    288     if #mac ~= 6 then
    289         return nil
    290     end
    291 
    292     return mac
    293 end
    294 
    295 -- Export module
    296 return RTL8139