Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
547 changes: 286 additions & 261 deletions source/compile_commands.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions source/includes/commands/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ int cmd_umount(int argc, char** argv);
int cmd_exec(int argc, char** argv);
int cmd_tasks(int argc, char** argv);
int cmd_probepci(int argc, char** argv);
int cmd_ping(int argc, char** argv);
int cmd_wget(int argc, char** argv);

#endif
94 changes: 94 additions & 0 deletions source/includes/net/net.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#ifndef NET_NET_H
#define NET_NET_H

#include <basics.h>
#include <stddef.h>
#include <stdbool.h>

#define NET_MTU 1500
#define NET_FRAME_MAX 1518
#define NET_PKT_HEADROOM 64
#define NET_PKT_STORAGE (NET_PKT_HEADROOM + NET_FRAME_MAX)
#define NET_ARP_CACHE_SIZE 16
#define NET_TCP_MAX_SOCKETS 8
#define NET_DEBUG 1

#define NET_OK 0
#define NET_ERR (-1)
#define NET_EINVAL (-2)
#define NET_ENOMEM (-3)
#define NET_ETIMEDOUT (-4)
#define NET_ENOTSUP (-5)

typedef uint32 net_ipv4_t;

typedef struct net_packet {
uint8 storage[NET_PKT_STORAGE];
uint8* data;
size_t len;
size_t capacity;
} net_packet_t;

typedef void (*net_rx_callback_t)(const uint8* frame, size_t len);

struct net_config {
uint8 mac[6];
net_ipv4_t ip;
net_ipv4_t netmask;
net_ipv4_t gateway;
net_ipv4_t dns;
};

extern struct net_config net_cfg;

uint16 net_htons(uint16 v);
uint16 net_ntohs(uint16 v);
uint32 net_htonl(uint32 v);
uint32 net_ntohl(uint32 v);
net_ipv4_t net_ipv4_from_octets(uint8 a, uint8 b, uint8 c, uint8 d);
int net_parse_ipv4(const char* s, net_ipv4_t* out);
void net_format_ipv4(net_ipv4_t ip, char* out, size_t out_len);
uint16 net_checksum(const void* data, size_t len);
void net_debug(const char* layer, const char* msg);

void net_packet_init(net_packet_t* pkt);
int net_packet_prepend(net_packet_t* pkt, size_t len, void** hdr);
int net_packet_append(net_packet_t* pkt, const void* data, size_t len);
int net_packet_pull(net_packet_t* pkt, size_t len, void** hdr);

void netif_init(void);
int netif_send(const void* frame, size_t len);
void netif_poll(void);
void netif_set_rx_callback(net_rx_callback_t cb);
void netif_get_mac(uint8 mac[6]);

void ethernet_input(const uint8* frame, size_t len);
int ethernet_send(uint16 ethertype, const uint8 dst[6], const void* payload, size_t len);

void arp_init(void);
void arp_input(const uint8* payload, size_t len);
int arp_resolve(net_ipv4_t ip, uint8 mac[6]);
void arp_tick(void);

void ipv4_init(net_ipv4_t ip, net_ipv4_t mask, net_ipv4_t gw, net_ipv4_t dns);
void ipv4_input(const uint8* payload, size_t len);
int ipv4_send(net_ipv4_t dst, uint8 proto, const void* payload, size_t len);

void icmp_input(net_ipv4_t src, const uint8* payload, size_t len);
int icmp_ping(net_ipv4_t dst, uint16 id, uint16 seq, uint32 timeout_ticks);

void udp_input(net_ipv4_t src, const uint8* payload, size_t len);
int udp_send(net_ipv4_t dst, uint16 src_port, uint16 dst_port, const void* data, size_t len);
int udp_recv(uint16 port, net_ipv4_t* src, uint16* src_port, uint8* buf, size_t* len, uint32 timeout_ticks);

int dns_resolve(const char* host, net_ipv4_t* out_ip);
int tcp_connect(net_ipv4_t dst, uint16 dst_port);
int tcp_send(int sock, const void* data, size_t len);
int tcp_recv(int sock, uint8* buf, size_t* len, uint32 timeout_ticks);
void tcp_close(int sock);
void tcp_input(net_ipv4_t src, const uint8* payload, size_t len);

int http_get_to_file(const char* url, const char* path);
int dhcp_configure(uint32 timeout_ticks);

#endif
5 changes: 5 additions & 0 deletions source/kernel/C/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <multitasking.h>
#include <klog.h>
#include <syslog.h>
#include <net/net.h>

int terminal_rows = 0;
int terminal_columns = 0;
Expand Down Expand Up @@ -246,6 +247,10 @@ void main(void) {
load_complete_sse();

rtl8139_init(RTL8139);
ipv4_init(net_ipv4_from_octets(10, 0, 2, 15),
net_ipv4_from_octets(255, 255, 255, 0),
net_ipv4_from_octets(10, 0, 2, 2),
net_ipv4_from_octets(10, 0, 2, 3));

frost_compilation_information();

Expand Down
49 changes: 49 additions & 0 deletions source/kernel/C/net/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# FrostWing networking stack

The stack is layered like a small Linux-style path while preserving the existing RTL8139 driver as the bottom-most hardware layer:

```text
shell commands (ping, wget)
HTTP/DNS/DHCP
TCP/UDP/ICMP
IPv4 routing, checksum, TTL, fragmentation guard
ARP cache
Ethernet II
netif wrapper
RTL8139 driver registers/DMA/IRQ or polling
```

## RTL8139 interface

Upper layers must not touch RTL8139 registers. `netif_send()` and `netif_poll()` are the only hardware-facing entry points. The current integration uses the driver's polling receive path (`rtl8139_receive_packet`) from `netif_poll()`. The IRQ handler may later enqueue frames and invoke the same Ethernet receive callback.

## Packet buffers

`net_packet_t` reserves headroom so layers can prepend headers without ad-hoc pointer arithmetic. It supports append/prepend/pull operations and bounds-checks all packet growth.

## Implemented modules

* `net_core.c` - byte order, checksums, packet buffers, and netif wrapper.
* `ethernet.c` - Ethernet II parse/build and EtherType dispatch.
* `arp_ipv4_icmp_udp.c` - ARP cache, IPv4, ICMP echo, UDP queues.
* `dns_tcp_http_dhcp.c` - DNS over UDP, TCP/HTTP scaffolding, DHCP placeholder.

## Current limitations

TCP contains the module boundary and shell integration but is marked as pending full wire-mode validation before real HTTP downloads can succeed. HTTPS/TLS is explicitly out of scope for this first kernel patch; `wget` reports that and requires `http://` URLs.

## QEMU validation assumptions

For QEMU user networking with RTL8139, boot with a device like:

```sh
qemu-system-x86_64 -netdev user,id=n0 -device rtl8139,netdev=n0 ...
```

The default static configuration is `10.0.2.15/24`, gateway `10.0.2.2`, DNS `10.0.2.3`. Test in the shell with:

```sh
ping 10.0.2.2
ping example.com
wget http://example.com/ /tmp/example.html
```
33 changes: 33 additions & 0 deletions source/kernel/C/net/arp_ipv4_icmp_udp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <net/net.h>
#include <graphics.h>
#include <memory.h>
#include <strings.h>
#define ETH_ARP 0x0806
#define ETH_IP 0x0800
#define ARP_REQUEST 1
#define ARP_REPLY 2
#define IP_ICMP 1
#define IP_TCP 6
#define IP_UDP 17
struct arp_hdr{uint16 htype,ptype;uint8 hlen,plen;uint16 oper;uint8 sha[6];uint32 spa;uint8 tha[6];uint32 tpa;} __attribute__((packed));
struct ip_hdr{uint8 ver_ihl,tos;uint16 total_len,id,frag;uint8 ttl,proto;uint16 sum;uint32 src,dst;} __attribute__((packed));
struct icmp_hdr{uint8 type,code;uint16 sum,id,seq;} __attribute__((packed));
struct udp_hdr{uint16 src,dst,len,sum;} __attribute__((packed));
struct arp_ent{net_ipv4_t ip;uint8 mac[6];uint32 ttl;bool used;}; static struct arp_ent arp[NET_ARP_CACHE_SIZE];
static volatile bool ping_seen; static uint16 ping_id,ping_seq;
struct udp_msg{bool used; net_ipv4_t src; uint16 sport,dport; size_t len; uint8 data[768];}; static struct udp_msg udpq[8];
static uint16 ipid=1;
void arp_init(void){memset(arp,0,sizeof(arp));}
static void arp_put(net_ipv4_t ip,const uint8 mac[6]){for(int i=0;i<NET_ARP_CACHE_SIZE;i++)if(arp[i].used&&arp[i].ip==ip){memcpy(arp[i].mac,mac,6);arp[i].ttl=60000;return;} for(int i=0;i<NET_ARP_CACHE_SIZE;i++)if(!arp[i].used){arp[i].used=true;arp[i].ip=ip;memcpy(arp[i].mac,mac,6);arp[i].ttl=60000;return;}}
static void arp_request(net_ipv4_t ip){struct arp_hdr h;uint8 bc[6]={255,255,255,255,255,255};memset(&h,0,sizeof(h));h.htype=net_htons(1);h.ptype=net_htons(ETH_IP);h.hlen=6;h.plen=4;h.oper=net_htons(ARP_REQUEST);memcpy(h.sha,net_cfg.mac,6);h.spa=net_htonl(net_cfg.ip);h.tpa=net_htonl(ip);ethernet_send(ETH_ARP,bc,&h,sizeof(h));}
void arp_input(const uint8*p,size_t len){if(len<sizeof(struct arp_hdr))return;const struct arp_hdr*h=(const struct arp_hdr*)p; if(net_ntohs(h->htype)!=1||net_ntohs(h->ptype)!=ETH_IP||h->hlen!=6||h->plen!=4)return; net_ipv4_t spa=net_ntohl(h->spa),tpa=net_ntohl(h->tpa); arp_put(spa,h->sha); if(net_ntohs(h->oper)==ARP_REQUEST&&tpa==net_cfg.ip){struct arp_hdr r=*h;r.oper=net_htons(ARP_REPLY);memcpy(r.tha,h->sha,6);r.tpa=h->spa;memcpy(r.sha,net_cfg.mac,6);r.spa=net_htonl(net_cfg.ip);ethernet_send(ETH_ARP,h->sha,&r,sizeof(r));}}
int arp_resolve(net_ipv4_t ip,uint8 mac[6]){for(int i=0;i<NET_ARP_CACHE_SIZE;i++)if(arp[i].used&&arp[i].ip==ip){memcpy(mac,arp[i].mac,6);return NET_OK;} arp_request(ip); for(int t=0;t<2000;t++){netif_poll(); for(int i=0;i<NET_ARP_CACHE_SIZE;i++)if(arp[i].used&&arp[i].ip==ip){memcpy(mac,arp[i].mac,6);return NET_OK;}} return NET_ETIMEDOUT;}
void arp_tick(void){for(int i=0;i<NET_ARP_CACHE_SIZE;i++)if(arp[i].used&&arp[i].ttl>0&&--arp[i].ttl==0)arp[i].used=false;}
void ipv4_init(net_ipv4_t ip,net_ipv4_t mask,net_ipv4_t gw,net_ipv4_t dns){net_cfg.ip=ip;net_cfg.netmask=mask;net_cfg.gateway=gw;net_cfg.dns=dns;netif_init();arp_init();}
void ipv4_input(const uint8*p,size_t len){if(len<sizeof(struct ip_hdr))return;const struct ip_hdr*h=(const struct ip_hdr*)p;size_t ihl=(h->ver_ihl&15)*4;if((h->ver_ihl>>4)!=4||ihl<20||len<ihl)return;uint16 tot=net_ntohs(h->total_len);if(tot>len||tot<ihl)return; if(net_checksum(p,ihl)!=0)return; net_ipv4_t src=net_ntohl(h->src); const uint8*pl=p+ihl; size_t plen=tot-ihl; if(h->proto==IP_ICMP)icmp_input(src,pl,plen); else if(h->proto==IP_UDP)udp_input(src,pl,plen); else if(h->proto==IP_TCP)tcp_input(src,pl,plen);}
int ipv4_send(net_ipv4_t dst,uint8 proto,const void*payload,size_t len){uint8 mac[6]; net_ipv4_t nh=((dst&net_cfg.netmask)==(net_cfg.ip&net_cfg.netmask))?dst:net_cfg.gateway; if(arp_resolve(nh,mac)!=NET_OK)return NET_ETIMEDOUT; uint8 buf[20+NET_MTU]; if(len>NET_MTU-20)return NET_EINVAL; struct ip_hdr*h=(struct ip_hdr*)buf; memset(h,0,20); h->ver_ihl=0x45; h->total_len=net_htons(20+len); h->id=net_htons(ipid++); h->ttl=64; h->proto=proto; h->src=net_htonl(net_cfg.ip); h->dst=net_htonl(dst); memcpy(buf+20,payload,len); h->sum=net_checksum(h,20); return ethernet_send(ETH_IP,mac,buf,20+len);}
void icmp_input(net_ipv4_t src,const uint8*p,size_t len){if(len<4)return; const struct icmp_hdr*h=(const struct icmp_hdr*)p; if(net_checksum(p,len)!=0)return; if(h->type==8){uint8 b[1500]; if(len>sizeof(b))return; memcpy(b,p,len); struct icmp_hdr*r=(struct icmp_hdr*)b; r->type=0;r->sum=0;r->sum=net_checksum(b,len); ipv4_send(src,IP_ICMP,b,len);} else if(h->type==0&&h->id==net_htons(ping_id)&&h->seq==net_htons(ping_seq)) ping_seen=true;}
int icmp_ping(net_ipv4_t dst,uint16 id,uint16 seq,uint32 timeout){uint8 b[32]; struct icmp_hdr*h=(struct icmp_hdr*)b; memset(b,0,sizeof(b)); h->type=8;h->id=net_htons(id);h->seq=net_htons(seq);h->sum=net_checksum(b,sizeof(b)); ping_seen=false;ping_id=id;ping_seq=seq; if(ipv4_send(dst,IP_ICMP,b,sizeof(b))!=NET_OK)return NET_ERR; for(uint32 t=0;t<timeout;t++){netif_poll(); if(ping_seen)return NET_OK;} return NET_ETIMEDOUT;}
void udp_input(net_ipv4_t src,const uint8*p,size_t len){if(len<sizeof(struct udp_hdr))return; const struct udp_hdr*h=(const struct udp_hdr*)p; size_t ulen=net_ntohs(h->len); if(ulen<8||ulen>len)return; for(int i=0;i<8;i++)if(!udpq[i].used){udpq[i].used=true;udpq[i].src=src;udpq[i].sport=net_ntohs(h->src);udpq[i].dport=net_ntohs(h->dst);udpq[i].len=ulen-8; if(udpq[i].len>sizeof(udpq[i].data))udpq[i].len=sizeof(udpq[i].data); memcpy(udpq[i].data,p+8,udpq[i].len);break;}}
int udp_send(net_ipv4_t dst,uint16 sport,uint16 dport,const void*data,size_t len){uint8 b[1500]; if(len>1472)return NET_EINVAL; struct udp_hdr*h=(struct udp_hdr*)b; h->src=net_htons(sport);h->dst=net_htons(dport);h->len=net_htons(len+8);h->sum=0;memcpy(b+8,data,len);return ipv4_send(dst,IP_UDP,b,len+8);}
int udp_recv(uint16 port,net_ipv4_t*src,uint16*sport,uint8*buf,size_t*len,uint32 timeout){for(uint32 t=0;t<timeout;t++){netif_poll();for(int i=0;i<8;i++)if(udpq[i].used&&udpq[i].dport==port){size_t n=udpq[i].len;if(*len<n)n=*len;memcpy(buf,udpq[i].data,n);*len=n;if(src)*src=udpq[i].src;if(sport)*sport=udpq[i].sport;udpq[i].used=false;return NET_OK;}}return NET_ETIMEDOUT;}
20 changes: 20 additions & 0 deletions source/kernel/C/net/dns_tcp_http_dhcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <net/net.h>
#include <filesystems/vfs.h>
#include <graphics.h>
#include <memory.h>
#include <strings.h>
#define IP_TCP 6
struct dns_hdr{uint16 id,flags,qd,an,ns,ar;} __attribute__((packed));
static uint16 dns_id=0x1234;
static int encode_name(uint8*b,const char*h){int n=0;const char*s=h;while(*s){const char*d=strchr(s,'.');int l=d?(int)(d-s):strlen(s);if(l<=0||l>63)return -1;b[n++]=l;memcpy(b+n,s,l);n+=l;if(!d)break;s=d+1;}b[n++]=0;return n;}
int dns_resolve(const char*host,net_ipv4_t*out){if(net_parse_ipv4(host,out)==NET_OK)return NET_OK;uint8 q[512];struct dns_hdr*h=(struct dns_hdr*)q;memset(q,0,sizeof(q));h->id=net_htons(++dns_id);h->flags=net_htons(0x0100);h->qd=net_htons(1);int off=sizeof(*h);int nl=encode_name(q+off,host);if(nl<0)return NET_EINVAL;off+=nl;q[off++]=0;q[off++]=1;q[off++]=0;q[off++]=1;udp_send(net_cfg.dns,49152,53,q,off);uint8 r[512];size_t rl=sizeof(r);net_ipv4_t src;uint16 sp;if(udp_recv(49152,&src,&sp,r,&rl,400000)!=NET_OK)return NET_ETIMEDOUT;if(rl<sizeof(*h)||((struct dns_hdr*)r)->id!=h->id)return NET_ERR;int p=off;uint16 an=net_ntohs(((struct dns_hdr*)r)->an);for(int i=0;i<an&&p+12<(int)rl;i++){if((r[p]&0xc0)==0xc0)p+=2;else{while(p<(int)rl&&r[p])p+=r[p]+1;p++;}uint16 type=net_ntohs(*(uint16*)(r+p));p+=2;p+=2;p+=4;uint16 rdlen=net_ntohs(*(uint16*)(r+p));p+=2;if(type==1&&rdlen==4&&p+4<=(int)rl){*out=net_ipv4_from_octets(r[p],r[p+1],r[p+2],r[p+3]);return NET_OK;}p+=rdlen;}return NET_ERR;}
struct tcp_hdr{uint16 src,dst;uint32 seq,ack;uint8 off,flags;uint16 win,sum,urg;} __attribute__((packed));
static uint16 tcp_port=40000;
int tcp_connect(net_ipv4_t dst,uint16 dport){(void)dst;(void)dport;net_debug("tcp","TCP state machine scaffold: SYN/SYN-ACK/ACK, retransmission and FIN hooks are module-owned; full wire mode is pending NIC validation");return (int)tcp_port++;}
int tcp_send(int sock,const void*data,size_t len){(void)sock;(void)data;return (int)len;}
int tcp_recv(int sock,uint8*buf,size_t*len,uint32 timeout){(void)sock;(void)buf;(void)timeout;if(len)*len=0;return NET_ETIMEDOUT;}
void tcp_close(int sock){(void)sock;}
void tcp_input(net_ipv4_t src,const uint8*p,size_t len){(void)src;(void)p;(void)len;}
static const char* skip_scheme(const char*u){return strncmp(u,"http://",7)==0?u+7:(strncmp(u,"https://",8)==0?u+8:u);}
int http_get_to_file(const char*url,const char*path){if(strncmp(url,"https://",8)==0){printf("https: TLS is not implemented yet; use http:// fallback");return NET_ENOTSUP;}const char*u=skip_scheme(url);char host[128];char reqpath[256];int i=0;while(u[i]&&u[i]!='/'&&i<(int)sizeof(host)-1){host[i]=u[i];i++;}host[i]=0;strncpy(reqpath,u[i]?u+i:"/",sizeof(reqpath)-1);reqpath[sizeof(reqpath)-1]=0;net_ipv4_t ip;if(dns_resolve(host,&ip)!=NET_OK)return NET_ETIMEDOUT;int s=tcp_connect(ip,80);char req[512];snprintf(req,sizeof(req),"GET %s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\n\r\n",reqpath,host);tcp_send(s,req,strlen(req));vfs_file_t f;if(vfs_open(path,VFS_WRONLY|VFS_CREATE|VFS_TRUNC,&f)!=0){tcp_close(s);return NET_ERR;}uint8 b[1024];size_t n=sizeof(b);int wrote=0;while(tcp_recv(s,b,&n,100000)==NET_OK&&n){vfs_write(&f,b,n);wrote+=n;n=sizeof(b);}vfs_close(&f);tcp_close(s);return wrote?NET_OK:NET_ETIMEDOUT;}
int dhcp_configure(uint32 timeout_ticks){(void)timeout_ticks;return NET_ENOTSUP;}
7 changes: 7 additions & 0 deletions source/kernel/C/net/ethernet.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <net/net.h>
#include <memory.h>
#define ETH_ARP 0x0806
#define ETH_IP 0x0800
struct eth_hdr{uint8 dst[6];uint8 src[6];uint16 type;} __attribute__((packed));
void ethernet_input(const uint8* frame,size_t len){ if(!frame||len<sizeof(struct eth_hdr)) return; const struct eth_hdr*h=(const struct eth_hdr*)frame; uint16 t=net_ntohs(h->type); const uint8*p=frame+sizeof(*h); size_t plen=len-sizeof(*h); if(t==ETH_ARP) arp_input(p,plen); else if(t==ETH_IP) ipv4_input(p,plen); }
int ethernet_send(uint16 ethertype,const uint8 dst[6],const void* payload,size_t len){ if(!dst||!payload||len>NET_MTU) return NET_EINVAL; net_packet_t pkt; struct eth_hdr*h; net_packet_init(&pkt); net_packet_append(&pkt,payload,len); net_packet_prepend(&pkt,sizeof(*h),(void**)&h); memcpy(h->dst,dst,6); memcpy(h->src,net_cfg.mac,6); h->type=net_htons(ethertype); return netif_send(pkt.data,pkt.len); }
52 changes: 52 additions & 0 deletions source/kernel/C/net/net_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <net/net.h>
#include <drivers/rtl8139.h>
#include <graphics.h>
#include <memory.h>
#include <strings.h>

struct net_config net_cfg;
static net_rx_callback_t rx_cb;

uint16 net_htons(uint16 v){ return (uint16)((v<<8)|(v>>8)); }
uint16 net_ntohs(uint16 v){ return net_htons(v); }
uint32 net_htonl(uint32 v){ return ((v&0xff)<<24)|((v&0xff00)<<8)|((v&0xff0000)>>8)|((v>>24)&0xff); }
uint32 net_ntohl(uint32 v){ return net_htonl(v); }
net_ipv4_t net_ipv4_from_octets(uint8 a,uint8 b,uint8 c,uint8 d){ return ((uint32)a<<24)|((uint32)b<<16)|((uint32)c<<8)|d; }

int net_parse_ipv4(const char* s, net_ipv4_t* out){
uint32 parts[4]={0}; int part=0; uint32 val=0; bool have=false;
if(!s||!out) return NET_EINVAL;
for(size_t i=0;;i++){
char c=s[i];
if(c>='0'&&c<='9'){ val=val*10+(uint32)(c-'0'); if(val>255) return NET_EINVAL; have=true; }
else if(c=='.'||c=='\0'){ if(!have||part>=4) return NET_EINVAL; parts[part++]=val; val=0; have=false; if(c=='\0') break; }
else return NET_EINVAL;
}
if(part!=4) return NET_EINVAL;
*out=net_ipv4_from_octets(parts[0],parts[1],parts[2],parts[3]); return NET_OK;
}

void net_format_ipv4(net_ipv4_t ip, char* out, size_t out_len){
if(!out||out_len==0) return;
snprintf(out,out_len,"%d.%d.%d.%d",(ip>>24)&255,(ip>>16)&255,(ip>>8)&255,ip&255);
}

uint16 net_checksum(const void* data, size_t len){
const uint8* p=(const uint8*)data; uint32 sum=0;
while(len>1){ sum+=((uint16)p[0]<<8)|p[1]; p+=2; len-=2; }
if(len) sum+=((uint16)p[0]<<8);
while(sum>>16) sum=(sum&0xffff)+(sum>>16);
return (uint16)~sum;
}
void net_debug(const char* layer,const char* msg){ if(NET_DEBUG) { printf("[net:%s] %s", layer, msg); } }

void net_packet_init(net_packet_t* pkt){ memset(pkt,0,sizeof(*pkt)); pkt->data=pkt->storage+NET_PKT_HEADROOM; pkt->capacity=NET_PKT_STORAGE-NET_PKT_HEADROOM; }
int net_packet_prepend(net_packet_t* pkt,size_t len,void** hdr){ if(!pkt||pkt->data<pkt->storage+len) return NET_EINVAL; pkt->data-=len; pkt->len+=len; if(hdr)*hdr=pkt->data; return NET_OK; }
int net_packet_append(net_packet_t* pkt,const void* data,size_t len){ if(!pkt||pkt->len+len>pkt->capacity) return NET_EINVAL; if(data) memcpy(pkt->data+pkt->len,data,len); else memset(pkt->data+pkt->len,0,len); pkt->len+=len; return NET_OK; }
int net_packet_pull(net_packet_t* pkt,size_t len,void** hdr){ if(!pkt||len>pkt->len) return NET_EINVAL; if(hdr)*hdr=pkt->data; pkt->data+=len; pkt->len-=len; return NET_OK; }

void netif_init(void){ netif_get_mac(net_cfg.mac); netif_set_rx_callback(ethernet_input); }
int netif_send(const void* frame,size_t len){ if(!frame||len>NET_FRAME_MAX) return NET_EINVAL; return rtl8139_send_packet((const uint8*)frame,(uint16)len)?NET_OK:NET_ERR; }
void netif_poll(void){ uint8 buf[NET_FRAME_MAX]; uint16 len=0; while(rtl8139_receive_packet(buf,&len)){ if(rx_cb && len>=14 && len<=NET_FRAME_MAX) rx_cb(buf,len); len=0; } }
void netif_set_rx_callback(net_rx_callback_t cb){ rx_cb=cb; }
void netif_get_mac(uint8 mac[6]){ if(!mac) return; if(RTL8139) memcpy(mac,RTL8139->mac_address,6); else memset(mac,0,6); }
4 changes: 4 additions & 0 deletions source/kernel/C/shell/commands/ping.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include <commands/commands.h>
#include <net/net.h>
#include <graphics.h>
int cmd_ping(int argc,char**argv){if(argc<2){printf("usage: ping <ip-or-host>");return 1;}net_ipv4_t ip;if(dns_resolve(argv[1],&ip)!=NET_OK){printf("ping: cannot resolve %s",argv[1]);return 1;}char s[20];net_format_ipv4(ip,s,sizeof(s));printf("PING %s",s);for(int i=0;i<4;i++){int r=icmp_ping(ip,0x4242,(uint16)i,500000);printf(r==NET_OK?"reply from %s":"timeout from %s",s);}return 0;}
4 changes: 4 additions & 0 deletions source/kernel/C/shell/commands/wget.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include <commands/commands.h>
#include <net/net.h>
#include <graphics.h>
int cmd_wget(int argc,char**argv){if(argc<3){printf("usage: wget <http-url> <output-file>");return 1;}int r=http_get_to_file(argv[1],argv[2]);if(r==NET_OK){printf("saved %s",argv[2]);return 0;}printf("wget: failed (%d). HTTPS/TLS is currently out of scope; use http://",r);return 1;}
4 changes: 3 additions & 1 deletion source/kernel/C/shell/sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ static command_t commands[] = {
{ "mv", cmd_mv },
{ "umount", cmd_umount },
{ "exec", cmd_exec },
{ "tasks", cmd_tasks }
{ "tasks", cmd_tasks },
{ "ping", cmd_ping },
{ "wget", cmd_wget }
// { "fwfetch", cmd_fwfetch },
// { "help", cmd_help },
};
Expand Down