1 /* ether.c - Raw Ethernet stuff
8 #include <sys/asynchio.h>
10 #include <net/gen/in.h>
11 #include <net/gen/ether.h>
12 #include <net/gen/eth_hdr.h>
13 #include <net/gen/ip_hdr.h>
14 #include <net/gen/icmp.h>
15 #include <net/gen/icmp_hdr.h>
16 #include <net/gen/oneCsum.h>
17 #include <net/gen/udp.h>
18 #include <net/gen/udp_hdr.h>
19 #include <net/gen/dhcp.h>
23 static ether_addr_t BCAST_ETH
= {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
25 #define BCAST_IP htonl(0xFFFFFFFFUL)
26 #define LOCALHOST htonl(0x7F000001UL)
28 #define BCAST_IP HTONL(0xFFFFFFFFUL)
29 #define LOCALHOST HTONL(0x7F000001UL)
32 static u16_t
udp_cksum(ipaddr_t src
, ipaddr_t dst
, udp_hdr_t
*udp
)
34 /* Compute the checksum of an UDP packet plus data. */
42 /* Fill in the UDP pseudo header that must be prefixed to the UDP
43 * packet to compute the checksum of the whole thing.
48 pseudo
.proto
= IPPROTO_UDP
;
49 pseudo
.length
= udp
->uh_length
;
51 len
= ntohs(udp
->uh_length
);
53 /* Length is odd? Pad with a zero. */
56 return oneC_sum(oneC_sum(0, &pseudo
, sizeof(pseudo
)), udp
, len
);
59 void udp2ether(buf_t
*bp
, network_t
*np
)
61 /* Transform a packet in UDP format to raw Ethernet. Ignore the UDP
62 * addresses, always broadcast from 0.0.0.0.
66 /* Save the UDP I/O header. */
69 /* Fill in the Ethernet, IP and UDP headers. */
70 bp
->eth
->eh_dst
= BCAST_ETH
;
71 bp
->eth
->eh_src
= np
->eth
;
73 bp
->eth
->eh_proto
= htons(ETH_IP_PROTO
);
75 bp
->eth
->eh_proto
= HTONS(ETH_IP_PROTO
);
77 bp
->ip
->ih_vers_ihl
= 0x45;
79 bp
->ip
->ih_length
= htons(sizeof(ip_hdr_t
)
80 + sizeof(udp_hdr_t
) + udpio
.uih_data_len
);
83 bp
->ip
->ih_flags_fragoff
= ntohs(0x4000);
85 bp
->ip
->ih_flags_fragoff
= NTOHS(0x4000);
87 bp
->ip
->ih_ttl
= IP_MAX_TTL
;
88 bp
->ip
->ih_proto
= IPPROTO_UDP
;
89 bp
->ip
->ih_hdr_chk
= 0;
91 bp
->ip
->ih_dst
= BCAST_IP
;
92 bp
->ip
->ih_hdr_chk
= ~oneC_sum(0, bp
->ip
, sizeof(*bp
->ip
));
93 bp
->udp
->uh_src_port
= udpio
.uih_src_port
;
94 bp
->udp
->uh_dst_port
= udpio
.uih_dst_port
;
95 bp
->udp
->uh_length
= htons(sizeof(udp_hdr_t
) + udpio
.uih_data_len
);
96 bp
->udp
->uh_chksum
= 0;
97 bp
->udp
->uh_chksum
= ~udp_cksum(bp
->ip
->ih_src
, bp
->ip
->ih_dst
, bp
->udp
);
100 int ether2udp(buf_t
*bp
)
102 /* Transform an UDP packet read from raw Ethernet to normal UDP.
103 * Return true iff the packet is indeed UDP and has no errors.
108 if (bp
->eth
->eh_proto
!= htons(ETH_IP_PROTO
)
110 if (bp
->eth
->eh_proto
!= HTONS(ETH_IP_PROTO
)
112 || bp
->ip
->ih_vers_ihl
!= 0x45
113 || bp
->ip
->ih_proto
!= IPPROTO_UDP
114 || oneC_sum(0, bp
->ip
, 20) != (u16_t
) ~0
115 || udp_cksum(bp
->ip
->ih_src
, bp
->ip
->ih_dst
, bp
->udp
) != (u16_t
) ~0
117 /* Not UDP/IP or checksums bad. */
120 udpio
.uih_src_addr
= bp
->ip
->ih_src
;
121 udpio
.uih_dst_addr
= bp
->ip
->ih_dst
;
122 udpio
.uih_src_port
= bp
->udp
->uh_src_port
;
123 udpio
.uih_dst_port
= bp
->udp
->uh_dst_port
;
124 udpio
.uih_ip_opt_len
= 0;
125 udpio
.uih_data_len
= ntohs(bp
->udp
->uh_length
) - sizeof(udp_hdr_t
);
130 void make_arp(buf_t
*bp
, network_t
*np
)
132 /* Create an ARP packet to query for my IP address. */
133 arp46_t
*arp
= (arp46_t
*) bp
->eth
;
135 memset(arp
, 0, sizeof(*arp
));
136 arp
->dstaddr
= BCAST_ETH
;
137 arp
->srcaddr
= np
->eth
;
139 arp
->ethtype
= htons(ETH_ARP_PROTO
);
140 arp
->hdr
= htons(ARP_ETHERNET
);
141 arp
->pro
= htons(ETH_IP_PROTO
);
142 arp
->op
= htons(ARP_REQUEST
);
144 arp
->ethtype
= HTONS(ETH_ARP_PROTO
);
145 arp
->hdr
= HTONS(ARP_ETHERNET
);
146 arp
->pro
= HTONS(ETH_IP_PROTO
);
147 arp
->op
= HTONS(ARP_REQUEST
);
153 memcpy(arp
->spa
, &np
->ip
, sizeof(np
->ip
));
154 memcpy(arp
->tpa
, &np
->ip
, sizeof(np
->ip
));
157 int is_arp_me(buf_t
*bp
, network_t
*np
)
159 /* True iff an ARP packet is a reply from someone else with an address I
160 * thought was mine. (That's like, bad.)
162 arp46_t
*arp
= (arp46_t
*) bp
->eth
;
166 arp
->ethtype
== htons(ETH_ARP_PROTO
)
167 && arp
->hdr
== htons(ARP_ETHERNET
)
168 && arp
->pro
== htons(ETH_IP_PROTO
)
169 && arp
->op
== htons(ARP_REPLY
)
171 arp
->ethtype
== HTONS(ETH_ARP_PROTO
)
172 && arp
->hdr
== HTONS(ARP_ETHERNET
)
173 && arp
->pro
== HTONS(ETH_IP_PROTO
)
174 && arp
->op
== HTONS(ARP_REPLY
)
176 && memcmp(&arp
->spa
, &np
->ip
, sizeof(np
->ip
)) == 0
177 && memcmp(&arp
->sha
, &np
->eth
, sizeof(np
->eth
)) != 0
179 np
->conflict
= arp
->sha
;
185 void icmp_solicit(buf_t
*bp
)
187 /* Fill in a router solicitation ICMP packet. */
188 icmp_hdr_t
*icmp
= (icmp_hdr_t
*) (bp
->ip
+ 1);
190 bp
->ip
->ih_vers_ihl
= 0x45;
191 bp
->ip
->ih_dst
= BCAST_IP
;
193 icmp
->ih_type
= ICMP_TYPE_ROUTE_SOL
;
195 icmp
->ih_hun
.ihh_unused
= 0;
197 icmp
->ih_chksum
= ~oneC_sum(0, icmp
, 8);
200 void icmp_advert(buf_t
*bp
, network_t
*np
)
202 /* Fill in a router advert to be sent to my own interface. */
203 icmp_hdr_t
*icmp
= (icmp_hdr_t
*) (bp
->ip
+ 1);
205 bp
->ip
->ih_vers_ihl
= 0x45;
206 bp
->ip
->ih_dst
= LOCALHOST
;
208 icmp
->ih_type
= ICMP_TYPE_ROUTER_ADVER
;
210 icmp
->ih_hun
.ihh_ram
.iram_na
= 1;
211 icmp
->ih_hun
.ihh_ram
.iram_aes
= 2;
212 icmp
->ih_hun
.ihh_ram
.iram_lt
= htons(DELTA_ADV
);
213 ((u32_t
*) icmp
->ih_dun
.uhd_data
)[0] = np
->gateway
;
215 ((u32_t
*) icmp
->ih_dun
.uhd_data
)[1] = htonl((u32_t
) -9999);
217 ((u32_t
*) icmp
->ih_dun
.uhd_data
)[1] = HTONL((u32_t
) -9999);
220 icmp
->ih_chksum
= ~oneC_sum(0, icmp
, 16);
223 ipaddr_t
icmp_is_advert(buf_t
*bp
)
225 /* Check if an IP packet is a router advertisement, and if it's genuine,
226 * i.e. the sender is mentioned in the packet.
228 icmp_hdr_t
*icmp
= (icmp_hdr_t
*) (bp
->ip
+ 1);
231 if (icmp
->ih_type
== ICMP_TYPE_ROUTER_ADVER
) {
232 for (i
= 0; i
< icmp
->ih_hun
.ihh_ram
.iram_na
; i
++) {
233 if (((u32_t
*) icmp
->ih_dun
.uhd_data
)[2*i
] == bp
->ip
->ih_src
) {
235 return bp
->ip
->ih_src
;