# xv6 network-net 3
最近土法煉鋼完成三方交握的部分,沒錯這個實驗還在繼續,為了證明最初的概念是對的。
# server
我們要完成的是三方交握的第一階段,也就是
bind - listening - accept
能不能節省掉這個步驟是可以的
![](https://i.imgur.com/3T3N11T.png)
![](https://i.imgur.com/fJ53VR4.png)
當我把sockecvudp while 迴圈裡 if判斷是拿掉的當下就是變成所有流量只要有socket 監聽就可以直接回傳。
# tcp header
![](https://i.imgur.com/cWDGkCw.png)
目前就已經整合進修改過後的xv6 kernel
可以對一般的socket 進行到三方交握階段,
# multi-network card qemu tap
透過這些設定,可以讓我們的xv6 支援更多張網卡
```bahs
ip tuntap add mode tap name tap0
ip addr add 172.16.100.1/24 dev tap0
ip link set tap0 up
```
```makefile
# QEMUOPTS += -netdev user,id=net0,hostfwd=udp::$(FWDPORT)-:2000,hostfwd=tcp::7-:7 -object filter-dump,id=net0,netdev=net0,file=packets.pcap
# QEMUOPTS += -device e1000,netdev=net0,bus=pcie.0
QEMUOPTS += -netdev tap,id=net1,ifname=tap0 -object filter-dump,id=net1,netdev=net1,file=packets2.pcap
QEMUOPTS += -device e1000,netdev=net1
```
![](https://i.imgur.com/Tp615Sa.png)
# debug checksuming
最主要的部份如果真的要實現一個tcp 協議需要對封包處理很熟悉,如果有多張網卡的情況可以透過下列指令關閉網卡的checksum 驗證,不然你的封包會莫名其妙地消失
ethtool -K ethx tx off rx off
下列網卡就是針對 tap0 但是可以看到 他寫的是fixed (有關等於沒關
![](https://i.imgur.com/0JQsRmO.png)
下列是出現封包遺失階段的畫面,網路上資料非常少
![](https://i.imgur.com/EUiMoZd.png)
server 可以看到有發送syn/ack 但是client遲遲不能解析封包
沒有gui介面可以透過
```bash=
sudo tcpdump -i tap0 -nn tcp
```
我找了一個https://github.com/pandax381/xv6-net
虛擬機可以研究了一段時間,稍微研究了他的封包之間的協議可以發現上方是對方的封包訊息,下方是我的
![](https://i.imgur.com/krvMnEW.png)
![](https://i.imgur.com/Q7lPY5E.png)
透過
```bash=
netstat --statistics --tcp
```
![](https://i.imgur.com/PympDTq.png)
可以看到我們的封包 被網卡拋棄了!
在檢查碼的這部分我發現我的檢查碼每次算會跟真實checksuming 差
```c=
uint16 tmp = 0x4fb;
```
開啟wireshark 可以看到封包checksum狀況
![](https://i.imgur.com/od6vCiN.png)
這是錯誤範例
![](https://i.imgur.com/wAoMAYG.png)
後面還有異動幾個版本,最後結論就是
最後懶得改了直接 答案-4fb
```c=
static void
net_rx_udp(struct mbuf *m, uint16 len, struct ip *iphdr)
{
struct tcp *udphdr, *udphdr2;
uint16 src;
uint16 dst;
uint32 tmp, seq;
uint8 flg;
uint8 flg2;
uint8 dst1;
uint8 dst2;
uint8 dst3;
uint8 dst4;
uint32 ack;
// uint32 sip;
uint16 sport, dport;
printf("test16\n");
struct mbuf *m2;
m2 = mbufalloc(MBUF_DEFAULT_HEADROOM);
udphdr = mbufpullhdr(m, *udphdr);
udphdr2 = mbufpushhdr(m2, (*udphdr2));
if (!udphdr)
goto fail;
printf("pre recv\n");
// // TODO: validate UDP checksum
// // validate lengths reported in headers
// if (ntohs(udphdr->ulen) != len)
// goto fail;
// len -= sizeof(*udphdr);
// if (len > m->len)
// goto fail;
// // minimum packet size could be larger than the payload
// mbuftrim(m, m->len - len);
// printf("test14\n");
// // parse the necessary fields
src = ntohl(iphdr->ip_src);
tmp = udphdr->dst;
udphdr->dst = udphdr->src;
udphdr->src = tmp;
udphdr2->src = udphdr->dst;
udphdr2->dst = udphdr->src;
// udphdr2->src = udphdr->dst;
// udphdr2->dst = udphdr->src;
// udphdr2->seq = 0;
// udphdr2->ack = 0;
// udphdr2->off = 0;
// udphdr2->win = 0;
// udphdr2->sum = 0;
// udphdr2->urg =0;
// uint16 src;
// uint16 dst;
// uint32 seq;
// uint32 ack;
// uint8 off;
// uint8 flg;
// uint16 win;
// uint16 sum;
// uint16 urg;
dst = ntohs(udphdr->dst);
seq = udphdr->seq;
flg = udphdr->flg;
flg2 = 18;
dst = (iphdr->ip_src << 24) | (iphdr->ip_src << 16) | (iphdr->ip_src << 8) | (iphdr->ip_src << 0);
dst1 = (iphdr->ip_src >> 24);
dst2 = (iphdr->ip_src >> 16);
dst3 = (iphdr->ip_src >> 8);
dst4 = (iphdr->ip_src >> 0);
ack = udphdr->ack;
// | (0 << 16) | (2 << 8) | (2 << 0);
printf("dst%u\n", dst);
printf("src%u\n", src);
// printf("dst %u\n", udphdr->dst);
printf("src%d\n", ntohs(udphdr->src));
printf("dst %d\n", ntohs(udphdr->dst));
printf("seq %u\n", ntohl(seq));
printBits(flg);
printBits(flg2);
printf("flg %d\n", flg);
printf("flg2 %d\n", flg2);
printf("addr4 %d\n", dst4);
printf("addr3 %d\n", dst3);
printf("addr2 %d\n", dst2);
printf("addr1 %d\n", dst1);
dst1 = (iphdr->ip_dst >> 24);
dst2 = (iphdr->ip_dst >> 16);
dst3 = (iphdr->ip_dst >> 8);
dst4 = (iphdr->ip_dst >> 0);
printf("addr4 %d\n", dst4);
printf("addr3 %d\n", dst3);
printf("addr2 %d\n", dst2);
printf("addr1 %d\n", dst1);
printf("ack %u\n", ntohl(ack));
printf("seq ntohs %u\n", ntohs(seq) + 1);
printf("seq ntohl %u\n", ntohl(seq) + 1);
udphdr->flg = flg2;
if (stseq == 0)
{
udphdr->seq = htonl(ntohl(seq) + 99);
}
else
{
udphdr->seq = htonl(ntohl(stseq) + 1);
stseq = ntohl(stseq) + 1;
}
// 172.17.35.175
// tmp = (192 << 24) | (168<< 16) | (100<< 8) | (1 << 0);
udphdr2->src = udphdr->src;
udphdr2->dst = udphdr->dst;
udphdr2->ack = htonl(ntohl(seq) + 1);
udphdr2->seq = htonl(ntohl(seq) + 123123123);
udphdr2->flg = flg2;
udphdr2->off = (sizeof(struct tcp) >> 2) << 4;
udphdr2->win = udphdr->win;
udphdr2->sum = 0;
udphdr2->urg = 0;
// udphdr2->option = udphdr->option;
uint32 pseudo = 0;
// tmp = (172 << 24) | (16 << 16) | (100 << 8) | (2 << 0);
// tmp = (10 << 24) | (0 << 16) | (2 << 8) | (15 << 0);
pseudo += ((local_ip) >> 16) & 0xffff;
pseudo += (local_ip)&0xffff;
// tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
pseudo += (tmp >> 16) & 0xffff;
pseudo += tmp & 0xffff;
pseudo += htons((uint16)IP_PROTOCOL_TCP);
pseudo += htons(sizeof(struct tcp));
uint16 tmp2 = 0x4fb;
printf("%u\n", tmp2);
// udphdr2->sum =cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo);
udphdr2->sum = cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo);
printf("%u\n", udphdr2->sum);
printf("%u\n", udphdr2->sum + tmp2);
printf("%u\n", htons(udphdr2->sum));
printf("%u\n", htons(tmp2));
printf("%u\n", htons(udphdr2->sum) + tmp2);
udphdr2->sum = htons(htons(udphdr2->sum) + tmp2);
printf("%u\n", htons(udphdr2->sum) + htons(tmp2));
uint32 pseudo2 = 0;
// tmp = (172 << 24) | (16 << 16) | (100 << 8) | (2 << 0);
// tmp = (10 << 24) | (0 << 16) | (2 << 8) | (15 << 0);
pseudo2 += (local_ip) >> 16;
pseudo2 += (local_ip)&0xffff;
// tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
// 3 0.005475 172.29.64.1 10.0.2.15 TCP 58 58866 → 11111 [SYN] Seq=0 Win=65535 Len=0 MSS=1460
tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
pseudo2 += tmp >> 16;
pseudo2 += tmp & 0xffff;
pseudo2 += htons((uint16)IP_PROTOCOL_TCP);
pseudo2 += htons(sizeof(struct tcp));
// in_cksum()
if (cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo2) != 0)
{
printf("tcp checksum error!\n");
}
else
printf("tcp checksum ok!\n");
// mbuftrim(m2,4)
printf("%x\n", cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo));
printf("%x\n", cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo2));
// uint16 src;
// uint16 dst;
// uint32 seq;
// uint32 ack;
// uint8 off;
// uint8 flg;
// uint16 win;
// uint16 sum;
// uint16 urg;
// printf("seq ntohs %u\n", ntohs(seq));
// printf("seq ntohs %u\n", ntohl( seq));
// printf("ack %u\n", ntohl ( udphdr->ack ));
udphdr->ack = htonl(ntohl(seq) + 1);
ack = udphdr2->seq;
seq = udphdr2->ack;
// uint8_t *buf;
// memcpy(udphdr2 + 1, buf, sizeof(20));
printf("ack %u\n", ntohl(ack));
printf("seq %u\n", ntohl(seq));
// struct udp *udphdr;
// udphdr = mbufpushhdr(m2, *udphdr);
// // put the UDP header
// udphdr = mbufpushhdr(m, *udphdr);
// udphdr->sport = htons(sport);
// udphdr->dport = htons(dport);
// udphdr->ulen = htons(m->len);
// udphdr->sum = 0; // zero means no checksum is provided
// // 172.18.86.160
// R(172, 16, 100, 2)
tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
// now on to the IP layer
// struct mbuf *m2;
// m2 = mbufalloc(MBUF_DEFAULT_HEADROOM);
// if (!m2)
// return -1;
// if (copyin(pr->pagetable, mbufput(m, n), addr, n) == -1)
// {
// mbuffree(m);
// return -1;
// }
// udphdr = mbufpullhdr(m, *udphdr);
sport = 1;
dport = 2;
printf("src%d\n", ntohs(udphdr->src));
printf("dst %d\n", ntohs(udphdr->dst));
printf("%d\n", sizeof(udphdr2));
printf("%d\n", sizeof(udphdr));
// char *obuf = "a message from xv6!";
// mbufput(m2, sizeof(obuf));
// m2->len = m2->len+sizeof(obuf);
if (count222 == 0)
{
flg2 = (1 << 4) | (1 << 1);
udphdr2->flg = flg2;
net_tx_ip(m2, IPPROTO_TCP, tmp);
// net_tx_ip(m2, IPPROTO_TCP, tmp);
// net_tx_ip(m2, IPPROTO_TCP, tmp);
// net_tx_ip(m2, IPPROTO_TCP, tmp);
// net_tx_ip(m2, IPPROTO_TCP, tmp);
// net_tx_ip(m2, IPPROTO_TCP, tmp);
// net_tx_ip(m2, IPPROTO_TCP, tmp);
// mbuffree(m2);
count222++;
mbuffree(m2);
}
else
{
// flg2 = (1 << 4);
// udphdr2->flg = flg2;
// net_tx_ip(m, IPPROTO_TCP, tmp);
// udphdr2->flg = flg2;
// net_tx_ip(m2, IPPROTO_TCP, tmp);
}
// }
// else
sockrecvudp2(m, tmp, dport, sport);
// sip = htonl(local_ip);;
// sockrecvudp(m, sip, dport, sport);
// printf("-------------------\n");
// sockrecvudp2(m, tmp, dport, sport);
return;
fail:
mbuffree(m);
}
```
算是比較作弊的方式,最近比較忙沒空看檢查碼這部分哪裡有問題,最後看到我的程式碼成功收到來自xv6 的確認封包。
![](https://i.imgur.com/2vpVYJk.jpg)
這些問題解決完後面要做的事情就是
![](https://i.imgur.com/WTtyChi.png)
![](https://i.imgur.com/mtDdeFO.png)
增加http 協議和 arp 緩存,要看有沒有時間去弄了,最近整理一下再放github