refactor(stdio): replace console/terminal command system with buffer-based stdio - Introduced stdio.pas as the unified command I/O layer. - All 31 command procedures across 15 files now receive stdin_buf, stdout_buf, and stderr_buf (POutBuf) instead of a single outbuf. - vterminal.pas creates all three buffers per command invocation and displays both stdout and stderr. - Deleted console.pas, terminal.pas, and 9 obsolete windowing programs (shell, splash, edit, memview, themer, netlog, vmlog, vmstate, udpcat). - Migrated all registerCommand calls to stdio, rewrote vterminal processCommand to use stdio.findCommand, and added proper error routing to stderr for invalid params, bad paths, and system errors. refactor(syslog): replace console logging with serial-backed syslog - Introduced syslog.pas for kernel-level logging over serial/dev. - Migrated all boot logging in kernel.pas from console.outputln/ writestringln to syslog.logln/writestringln. - Converted 19 fault handlers, hashmap, lists, scheduler, tracer, net, udp, and all driver init paths to use syslog. - Rewrote BSOD in util.pas (50+ calls) from console to syslog. - Removed CONSOLE_SLOW_REDRAW, TRGB565, TRGB565Pair, and HWND from system.pas. fix(keyboard): add ring buffer and proper press/release cycling for LVGL input - Replaced the single last_key/key_pressed slot in lvgl.pas with a 16-entry ring buffer (kb_buf, kb_head, kb_tail) to prevent ISR overwrites when typing fast. - Added a kb_pending_release flag so each keystroke gets a full PRESSED->RELEASED cycle before the next key is consumed — LVGL requires this pairing and was silently dropping intermediate keys when receiving consecutive PRESSED events without intervening releases. feat(vterminal): use Hack monospace font for terminal output - Added Hack Regular 14px (hack_14.c) as a custom LVGL font. - Removed the .static_bitmap field from the generated font file (not present in LVGL 9.2 lv_font_t struct). - Declared the hack_14 external symbol in lvgl.pas and switched vterminal's text label from lv_font_montserrat_14 to hack_14 for proper monospace terminal rendering.
255 lines
7.2 KiB
ObjectPascal
255 lines
7.2 KiB
ObjectPascal
// Copyright 2021 Kieron Morris
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
{
|
|
Driver->Net->L4->ICMP - Internet Control Message Protocol Driver,
|
|
|
|
@author(Kieron Morris <[email protected]>)
|
|
}
|
|
unit icmp;
|
|
|
|
interface
|
|
|
|
uses
|
|
bios_data_area,
|
|
lmemorymanager,
|
|
net, nettypes, netutils, ipv4, arp, util;
|
|
|
|
type
|
|
TARPErrorCode = (aecFailedToResolveHost, aecNoRouteToHost, aecTimeout, aecTTLExpired);
|
|
TARPReplyCallback = procedure(hdr : PICMPHeader);
|
|
TARPErrorCallback = procedure(hdr : PICMPHeader; Reason : TARPErrorCode);
|
|
TARPHandler = record
|
|
Active : Boolean;
|
|
OnReply : TARPReplyCallback;
|
|
OnError : TARPErrorCallback;
|
|
end;
|
|
|
|
procedure register;
|
|
procedure sendICMPRequest(ip : puint8; Sequence : uint16; TTL : uint8; OnRep : TARPReplyCallback; OnErr : TARPErrorCallback);
|
|
|
|
procedure ping_err(hdr : PICMPHeader; Reason : TARPErrorCode);
|
|
procedure ping_rep(hdr : PICMPHeader);
|
|
|
|
implementation
|
|
|
|
uses
|
|
stdio, strings;
|
|
|
|
var
|
|
Handlers : Array[0..255] of TARPHandler;
|
|
|
|
function nextInactiveHandler : uint8;
|
|
var
|
|
i : uint8;
|
|
|
|
begin
|
|
nextInactiveHandler:= 0;
|
|
for i:=1 to 255 do begin
|
|
if not Handlers[i].Active then begin
|
|
nextInactiveHandler:= i;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure sendResponse(p_context : PPacketContext);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure sendICMPRequest(ip : puint8; Sequence : uint16; TTL : uint8; OnRep : TARPReplyCallback; OnErr : TARPErrorCallback);
|
|
var
|
|
handle : uint8;
|
|
dest_mac : puint8;
|
|
context : PPacketContext;
|
|
Header : PICMPHeader;
|
|
Buffer : void;
|
|
CHK : uint16;
|
|
Size : uint32;
|
|
|
|
begin
|
|
handle:= nextInactiveHandler;
|
|
Handlers[handle].Active:= true;
|
|
Handlers[handle].OnReply:= OnRep;
|
|
Handlers[handle].OnError:= OnErr;
|
|
if SameSubnetIPv4(ip, @getIPv4Config^.Address[0], @getIPv4Config^.Netmask[0]) then begin
|
|
dest_mac:= arp.resolveIP(ip);
|
|
end else begin
|
|
dest_mac:= arp.resolveIP(@getIPv4Config^.Gateway[0]);
|
|
end;
|
|
if dest_mac = nil then begin
|
|
if Handlers[handle].OnError <> nil then Handlers[handle].OnError(nil, aecFailedToResolveHost);
|
|
Handlers[handle].Active:= false;
|
|
end else begin
|
|
context:= newPacketContext;
|
|
copyMAC(getMAC, @context^.MAC.Source[0]);
|
|
copyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
|
copyMAC(dest_mac, @context^.MAC.Destination[0]);
|
|
copyIPv4(ip, @context^.IP.Destination[0]);
|
|
context^.TTL:= TTL;
|
|
context^.Protocol.L4:= $01;
|
|
|
|
Size:= sizeof(TICMPHeader) + sizeof(ICMP_DATA_GENERIC);
|
|
Buffer:= kalloc(Size);
|
|
Header:= PICMPHeader(Buffer);
|
|
Header^.ICMP_Type:= $08;
|
|
Header^.ICMP_CHK_Hi:= 0;
|
|
Header^.ICMP_CHK_Lo:= 0;
|
|
Header^.Identifier:= handle;
|
|
Header^.Sequence:= Sequence;
|
|
|
|
memcpy(uint32(@ICMP_DATA_GENERIC[0]), uint32(Buffer) + sizeof(TICMPHeader), sizeof(ICMP_DATA_GENERIC));
|
|
|
|
CHK:= calculateChecksum(puint16(Buffer), Size);
|
|
|
|
Header^.ICMP_CHK_Hi:= CHK AND $FF;
|
|
Header^.ICMP_CHK_Lo:= CHK SHR 8;
|
|
|
|
ipv4.send(Buffer, size, context);
|
|
|
|
freePacketContext(context);
|
|
end;
|
|
end;
|
|
|
|
{procedure sendRequest(ip : puint8);
|
|
begin
|
|
|
|
end;}
|
|
|
|
procedure recv(p_data : void; p_len : uint16; p_context : PPacketContext);
|
|
var
|
|
Header : PICMPHeader;
|
|
CHK : uint16;
|
|
Handle : uint8;
|
|
|
|
begin
|
|
Header:= PICMPHeader(p_data);
|
|
//writehexlnWND(Header^.ICMP_Type, getTerminalHWND);
|
|
case Header^.ICMP_Type of
|
|
$08:Begin //Request
|
|
contextMACSwitch(p_context);
|
|
contextIPv4Switch(p_context);
|
|
Header^.ICMP_Type:= 0;
|
|
Header^.ICMP_CHK_Hi:= 0;
|
|
Header^.ICMP_CHK_Lo:= 0;
|
|
CHK:= calculateChecksum(puint16(p_data), p_len);
|
|
Header^.ICMP_CHK_Hi:= CHK AND $FF;
|
|
Header^.ICMP_CHK_Lo:= CHK SHR 8;
|
|
p_context^.Protocol.L4:= $01;
|
|
p_context^.TTL:= 128;
|
|
ipv4.send(p_data, p_len, p_context);
|
|
end;
|
|
$00:begin //Reply
|
|
Handle:= Header^.Identifier;
|
|
if (Handle > 0) and (Handle < 256) then begin
|
|
If Handlers[Handle].Active then begin
|
|
If Handlers[Handle].OnReply <> nil then Handlers[Handle].OnReply(Header);
|
|
Handlers[Handle].Active:= false;
|
|
Handlers[Handle].OnError:= nil;
|
|
Handlers[Handle].OnReply:= nil;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
PING_T1 : uint64;
|
|
PING_N : uint16;
|
|
PING_C : uint16;
|
|
PING_L : uint32;
|
|
PING_IP : puint8;
|
|
PING_STDOUT : POutBuf;
|
|
PING_STDERR : POutBuf;
|
|
|
|
procedure ping_err(hdr : PICMPHeader; Reason : TARPErrorCode);
|
|
begin
|
|
stdio.bufWriteStr(PING_STDERR, 'Ping Error: ');
|
|
case Reason of
|
|
aecFailedToResolveHost:stdio.bufWriteStrLn(PING_STDERR, 'Failed to resolve host.');
|
|
aecNoRouteToHost:stdio.bufWriteStrLn(PING_STDERR, 'No route to host.');
|
|
aecTimeout:stdio.bufWriteStrLn(PING_STDERR, 'Timeout expired.');
|
|
aecTTLExpired:stdio.bufWriteStrLn(PING_STDERR, 'TTL Expired.');
|
|
end;
|
|
PING_T1:= Counters.c64;
|
|
INC(PING_C);
|
|
if PING_C < PING_N then begin
|
|
sendICMPRequest(PING_IP, PING_C, 128, @ping_rep, @ping_err);
|
|
end else begin
|
|
stdio.done(PING_L);
|
|
end;
|
|
end;
|
|
|
|
procedure ping_rep(hdr : PICMPHeader);
|
|
var
|
|
PING_T2 : uint64;
|
|
|
|
begin
|
|
PING_T2:= Counters.c64;
|
|
stdio.bufWriteStr(PING_STDOUT, 'Ping Reply: ');
|
|
stdio.bufWriteInt(PING_STDOUT, PING_T2-PING_T1);
|
|
stdio.bufWriteStrLn(PING_STDOUT, 'ms.');
|
|
PING_T1:= PING_T2;
|
|
INC(PING_C);
|
|
if PING_C < PING_N then begin
|
|
sendICMPRequest(PING_IP, PING_C, 128, @ping_rep, @ping_err);
|
|
end else begin
|
|
stdio.done(PING_L);
|
|
end;
|
|
end;
|
|
|
|
procedure ping_terminate();
|
|
begin
|
|
PING_N:= 0;
|
|
end;
|
|
|
|
procedure terminal_command_ping(Params : PParamList; stdin_buf, stdout_buf, stderr_buf : POutBuf);
|
|
var
|
|
ip_str : pchar;
|
|
ip : puint8;
|
|
|
|
begin
|
|
if ParamCount(Params) > 0 then begin
|
|
ip_str:= getParam(0, Params);
|
|
ip:= stringToIPv4(ip_str);
|
|
if ip <> nil then begin
|
|
PING_STDOUT:= stdout_buf;
|
|
PING_STDERR:= stderr_buf;
|
|
stdio.halt(PING_L, @ping_terminate);
|
|
PING_L:= Counters.c32;
|
|
PING_N:= 10;
|
|
PING_C:= 0;
|
|
PING_T1:= Counters.c64;
|
|
PING_IP:= ip;
|
|
sendICMPRequest(PING_IP, PING_C, 128, @ping_rep, @ping_err);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure register;
|
|
var
|
|
i : uint32;
|
|
|
|
begin
|
|
for i:=0 to 255 do begin
|
|
Handlers[i].Active:= false;
|
|
Handlers[i].OnError:= nil;
|
|
Handlers[i].OnReply:= nil;
|
|
end;
|
|
ipv4.registerProtocol($01, @recv);
|
|
stdio.registerCommand('PING', @terminal_command_ping, 'Ping a host.');
|
|
end;
|
|
|
|
end. |