-
-
Save gucchan22/7bf7d7b02fa063c0eee41ea7fb25a0e7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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