Skip to content

Instantly share code, notes, and snippets.

@gucchan22
Last active June 16, 2016 19:18
Show Gist options
  • Save gucchan22/7bf7d7b02fa063c0eee41ea7fb25a0e7 to your computer and use it in GitHub Desktop.
Save gucchan22/7bf7d7b02fa063c0eee41ea7fb25a0e7 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG 1
#define ETHER_MTU 1500
#define LOOPBACK_MTU 1536
#define ETHER_ADDR_LEN 6
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
uchar hw_addr[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc };
struct gbuf {};
struct ifnet {
struct ifnet *if_next;
struct ifaddr *if_addrlist;
uchar ifname[16]; // eth, wlan, le, lo
short if_unit; // sub-unit for lower level driver.
ushort if_index; // uniquely identifies the interface within the kernel and is used by the sysctl.
short if_flags;
#define IFF_UP (1 << 0)
#define IFF_PROMISC (1 << 1)
#define IFF_RUNNING (1 << 2)
#define IFF_OACTIVE (1 << 3)
#define IFF_LOOPBACK (1 << 4)
//short if_timer; watchdog timer.
int if_pcount; // number of promiscuous listeners.
// caddr_t if_bpf; // packet filter structure.
struct ifdata {
uchar ifi_type;
uchar ifi_addrlen; // MAC = 6byte (48bit.)
uchar ifi_hdrlen;
ulong ifi_mtu;
ulong ifi_metric;
ulong ifi_ipackets; // packets received on interface.
ulong ifi_ierrors; // input errors on interface.
ulong ifi_opackets; // packets sent on interface.
ulong ifi_oerrors; // output errors on interface.
ulong ifi_collisions; // CSMA collisions.
ulong ifi_ibytes; // bytes received.
ulong ifi_obytes; // bytes sent.
ulong ifi_iqdrops;
ulong ifi_noproto; // packets destined for unsupported protocol.
// ifi_imcasts, ifi_omcasts is not implemented.
} if_data;
#define if_mtu if_data.ifi_mtu
#define if_type if_data.ifi_type
#define if_addrlen if_data.ifi_addrlen
#define if_hdrlen if_data.ifi_hdrlen
// handles.
int (*if_init)(int);
// int (*if_output)(struct ifnet *, struct gbuf *, struct sockaddr *, struct rtentry *)
int (*if_output)(struct ifnet *, struct gbuf *, struct sockaddr *);
int (*if_start)(struct ifnet *); // initiate transmission of packets.
int (*if_done)(struct ifnet *); // NOT USED.
int (*if_ioctl)(struct ifnet *, int, caddr_t);
int (*if_reset)(int);
int (*if_watchdog)(int); // timctl_add_task().
/*
struct ifqueue {
struct gbuf *ifq_head;
struct gbuf *ifq_tail;
int ifq_len;
int ifq_maxlen;
int ifq_drops;
} if_snd;
*/
};
// ifnet.ifdata.ifi_type
#define IFT_OTHER (1 << 0)
#define IFI_ETHER (1 << 1)
#define IFT_LOOP (1 << 2)
struct xv6_sockaddr { uchar sa_len, sa_family; char sa_data[14]; };
struct xv6_osockaddr { ushort sa_family; char sa_data[14]; };
struct xv6_sockaddr_dl {
uchar sdl_len; // total length of sockaddr.
uchar sdl_family; // AF_LINK
uchar sdl_index;
uchar sdl_type;
uchar sdl_nlen;
uchar sdl_alen;
uchar sdl_slen;
char sdl_data[12];
};
struct xv6_in_addr { uchar addr[4]; };
// sockaddr.sa_family
#define AF_INET (1 << 0)
#define AF_LINK (1 << 1)
#define LLADDR(s) ((uint)((s)->sdl_data + (s)->sdl_nlen))
// ifnet.if_flags
struct ifaddr {
struct ifnet *ifa_ifp;
uint ifa_next;
struct xv6_sockaddr ifa_addr;
struct xv6_sockaddr ifa_netmask;
};
struct arpcom {
struct ifnet ac_if;
struct ifaddr ac_ifaddr;
uchar ac_enaddr[6]; // MAC 48bit.
struct xv6_in_addr ac_ipaddr; // copy of ipaddress.
};
#define NLE 3
struct ne2k_softc {
struct arpcom sc_ac;
#define sc_if sc_ac.ac_if
#define sc_ifaddr sc_ac.ac_ifaddr
#define sc_addr sc_ac.ac_enaddr
} ne2k_softc[NLE];
struct loif {
struct ifnet lo_ifnet;
} loif;
#define print_mac(hw) printf("%x:%x:%x:%x:%x:%x", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]);
// network structures.
struct ether_header {
uchar ether_dhost[6];
uchar ether_shost[6];
ushort ether_type;
};
void ne2k_init();
void ne2k_reset();
void ne2k_ioctl();
// GLOBAL VARIABLES.
int if_index = 0;
struct ifnet *ifnet = NULL;
int int_count(int n) {
int count = 0;
if(n > 0) {
while(n != 0) {
++count;
n /= 10;
}
} else {
count = 1;
}
return count;
}
struct ifnet *get_ifnet() { return ifnet; }
void if_ether_create(const char *if_pname, struct ifnet *ifn, struct ifaddr *ifn_ifaddr) {
int i;
ifn->if_next = NULL;
memset(ifn->ifname, 0, 16);
for(i = 0; i < strlen(if_pname) + int_count(if_index); i++) {
if(i < strlen(if_pname)) {
memcpy(ifn->ifname, if_pname, strlen(if_pname));
} else {
ifn->ifname[i] = '0' + if_index;
}
}
ifn->if_index = if_index;
ifn->if_unit = if_index;
ifn->if_addrlist = ifn_ifaddr;
ifn_ifaddr->ifa_ifp = ifn;
ifn_ifaddr->ifa_next = NULL;
struct xv6_sockaddr_dl *ifa_addr_dl = (struct xv6_sockaddr_dl *)&ifn_ifaddr->ifa_addr;
struct xv6_sockaddr_dl *ifa_netmask_dl = (struct xv6_sockaddr_dl *)&ifn_ifaddr->ifa_netmask;
ifa_addr_dl->sdl_len = 20;
ifa_addr_dl->sdl_type = AF_LINK;
ifa_addr_dl->sdl_index = 1;
ifa_addr_dl->sdl_nlen = strlen(if_pname) + int_count(if_index); // ifa_addr_dl->sdl_nlen = 4 ("eth0").
ifa_addr_dl->sdl_alen = ETHER_ADDR_LEN;
memcpy(ifa_addr_dl->sdl_data, ifn->ifname, strlen(if_pname)+int_count(if_index));
memcpy(ifa_addr_dl->sdl_data + strlen(if_pname) + int_count(if_index), hw_addr, ifa_addr_dl->sdl_alen);
ifa_netmask_dl->sdl_len = 11;
memcpy(ifa_netmask_dl->sdl_data, "\xff\xff\xff", 3);
}
#ifdef DEBUG
static void if_debug(const struct ifnet *ifn) {
char nlen_buff[20];
uchar alen_buff[6];
memset(nlen_buff, 0, 20);
memset(alen_buff, 0, 6);
printf("<ifnet{} @ %p <ifname:\"%s\", if_index:%d, if_unit:%d, if_mtu:%d%s, if_next:%p>>\n",
ifn, ifn->ifname, ifn->if_index, ifn->if_unit, ifn->if_mtu, (ifn->if_mtu == 1500 ? "(Ethernet)" : ""), ifn->if_next);
if(ifn->if_addrlist != NULL) {
printf("\t<ifaddr{} @ %p <ifa_ifp:<ifnet{} @ %p ifname:\"%s\">, ifa_next:%p>>\n",
ifn->if_addrlist, ifn->if_addrlist->ifa_ifp, ifn->if_addrlist->ifa_ifp->ifname, ifn->if_addrlist->ifa_next);
struct xv6_sockaddr_dl *ifa_addr_dl = (struct sockaddr_dl *)&ifn->if_addrlist->ifa_addr;
struct xv6_sockaddr_dl *ifa_netmask_dl = (struct sockaddr_dl *)&ifn->if_addrlist->ifa_netmask;
printf("\t\t<sockaddr_dl{} @ %p <sdl_len:%d, sdl_nlen:%d, sdl_alen:%d, ",
ifa_addr_dl, ifa_addr_dl->sdl_len, ifa_addr_dl->sdl_nlen, ifa_addr_dl->sdl_alen);
memcpy(nlen_buff, ifa_addr_dl->sdl_data, ifa_addr_dl->sdl_nlen);
printf("nlen: \"%s\", ", nlen_buff);
memcpy(alen_buff, ifa_addr_dl->sdl_data + strlen(ifn->ifname), ifa_addr_dl->sdl_alen);
printf("alen:");
print_mac(alen_buff);
printf(">>\n");
printf("\t\t<sockaddr_dl{} @ %p <sdl_len:%d>>\n\n", ifa_netmask_dl, ifa_netmask_dl->sdl_len);
}
}
#endif
void if_attach(struct ifnet *ifn) {
struct ifnet **if_ptr = &ifnet;
struct ifnet *prev_ifnet = NULL;
while(*if_ptr != NULL) {
prev_ifnet = *if_ptr;
if_ptr = &((*if_ptr)->if_next);
}
*if_ptr = ifn;
if(if_index > 0) {
prev_ifnet->if_next = ifn;
//printf("prev_ifnet : %p. prev_ifnet->if_next : %p\n", prev_ifnet, prev_ifnet->if_next);
}
ifn->if_index = ++if_index;
}
struct ifnet *ne2k_attach(const int dev_no) {
struct ne2k_softc *ne2k_if = &ne2k_softc[dev_no];
struct ifnet *ifp = &ne2k_if->sc_if;
if_ether_create("eth", ifp, &ne2k_if->sc_ifaddr);
ifp->if_mtu = ETHER_MTU;
ifp->if_unit = dev_no;
ifp->if_init = ne2k_init;
ifp->if_reset = ne2k_reset;
ifp->if_ioctl = ne2k_ioctl;
if_attach(ifp);
#ifdef DEBUG
printf("Called: if_attach(ifp), ifp -> ifnet{} @ %p\n", ifp);
//if_debug(ifp);
#endif
return ifp;
}
void ne2k_init() {}
void ne2k_reset() {}
void ne2k_ioctl() {
}
// For loopback device.
struct pdevinit {
void (*pdev_attach)(int);
int pdev_count;
};
void loioctl() {}
void looutput() {}
void loopattach(int pdev_count) {
struct ifnet *ifp = &loif.lo_ifnet;
memcpy(ifp->ifname, "lo0", 3);
ifp->if_mtu = LOOPBACK_MTU;
ifp->if_flags = IFF_LOOPBACK;
ifp->if_ioctl = loioctl;
ifp->if_output = looutput;
ifp->if_hdrlen = 0;
ifp->if_addrlen = 0;
if_attach(ifp);
}
/*
ioctl(2) call-trace Overview.
ioctl()
|
soo_ioctl()
|
|--------------------|
ifioctl | rtioctl
|---| pr_usrreq
| ifconf
|-if_ioctl
|-----------|
ne2kioctl, loioctl
*/
struct xv6_ifconf {
int ifc_len;
union {
uint ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req
};
struct xv6_ifreq {
#define IFNAMESIZ 16
char ifr_name[IFNAMESIZ];
union {
struct xv6_sockaddr ifru_addr;
struct xv6_sockaddr ifru_dstaddr;
struct xv6_sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
uint ifru_data;
} ifr_ifru;
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.ifru_broadaddr
#define ifr_flags ifr_ifru.ifru_flags
#define ifr_metric ifr_ifru.ifru_metric
#define ifr_data ifr_ifru.ifru_data
};
#define SIOCGIFCONF (1 << 0) // ifioctl -> ifconf(struct ifconf *)
#define SIOCGIFFLAGS (1 << 1) // ifioctl(struct ifreq *)
#define SIOCGIFMETRIC (1 << 2) // ifioctl(struct ifreq *)
#define SIOSGIFFLAGS (1 << 3) // ifioctl(struct ifreq *)
#define SIOCSIFFLAGS (1 << 4) // ifioctl(struct ifreq *)
#define SIOCSIFMETRIC (1 << 5) // ifioctl(struct ifreq *)
// For SIOCGIFCONF (cmd in ifconf() will be ignored...)
/*
struct ifconf ifc;
uchar ifconf_buf[36 * 2];
int s;
ifc.ifc_len = 36 * 2;
ifc.ifc_buf = ifconf_buf;
if(ioctl(s, SIOCGIFCONF, &ifc) < 0) exit(1);
0 ifr_name[] 16 ifr_addr 36
|----------------------------------------|
|e|t|h|0|--------|20|18|1|6|3|6|0|e|t|h|0| 36byte
|l|o|0|----------|20|18|3|24|3|0|0|l|o|0 | 36byte
*/
int ifconf(const int cmd, void *data) {
struct xv6_ifconf *ifc = (struct xv6_ifconf *)data;
struct ifnet *ifp = ifnet;
struct ifaddr *ifa;
return 1;
}
struct ifnet *if_unit(const char *if_name) {
struct ifnet *ifp;
for(ifp = ifnet; ifp->if_next != NULL; ifp = ifp->if_next) {
if(strcmp(ifp->ifname, if_name) == 0) {
break;
} else {
ifp = ifp->if_next;
}
}
return ifp;
}
void if_down(struct ifnet *ifp) {
struct ifaddr *ifa;
ifp->if_flags &= ~IFF_UP;
for(ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) {
// pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
// todo: pfctlinput gives an oppotunity to notify the each of protocol which uses this interface that the interface state is 'down'.
}
// todo: if_qflush(&ifp->if_snd);
}
void if_up(struct ifnet *ifp) {
ifp->if_flags |= IFF_UP;
// rt_ifmsg(ifp);
}
int ifioctl(const int cmd, void *data) {
struct ifnet *ifp;
struct xv6_ifreq *ifr;
if(cmd == SIOCGIFCONF) {
return (ifconf(cmd, data));
}
ifr = (struct xv6_ifreq *)data;
ifp = if_unit(ifr->ifr_name);
if(ifp == NULL) {
#ifdef DEBUG
printf("Error\n");
#endif
}
switch(cmd) {
case SIOCGIFFLAGS:
ifr->ifr_flags = ifp->if_flags;
break;
case SIOCGIFFLAGS:
ifr->ifr_metric = ifp->if_metric;
break;
case SIOSCIFFLAGS:
// todo: SIOSCIFFLAGS, SIOCSIFMETRIC use receive-blocking like splimp(), splx().
// should consider how to design these blocking-calls.
break;
}
return 0;
}
int main(void) {
/*
struct ifnet ifnet_eth0;
struct ifaddr if_addr_eth0;
if_create("eth", &ifnet_eth0, &if_addr_eth0);
*/
struct ifnet *ifp;
ne2k_attach(0);
// Loopback
struct pdevinit pdevinit[] = {{ loopattach, 1 }, { 0, 0 }};
struct pdevinit *pdev;
for(pdev = pdevinit; pdev->pdev_attach != NULL; pdev++) (*pdev->pdev_attach)(pdev->pdev_count);
/*
ifp = if_unit("eth0");
if_debug(ifp);
*/
ifp = get_ifnet();
while(ifp != NULL) {
if_debug(ifp);
ifp = ifp->if_next;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment