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 }};
24 #define BCAST_IP htonl(0xFFFFFFFFUL)
25 #define LOCALHOST htonl(0x7F000001UL)
27 static u16_t
udp_cksum(ipaddr_t src
, ipaddr_t dst
, udp_hdr_t
*udp
)
29 /* Compute the checksum of an UDP packet plus data. */
37 /* Fill in the UDP pseudo header that must be prefixed to the UDP
38 * packet to compute the checksum of the whole thing.
43 pseudo
.proto
= IPPROTO_UDP
;
44 pseudo
.length
= udp
->uh_length
;
46 len
= ntohs(udp
->uh_length
);
48 /* Length is odd? Pad with a zero. */
51 return oneC_sum(oneC_sum(0, &pseudo
, sizeof(pseudo
)), udp
, len
);
54 void udp2ether(buf_t
*bp
, network_t
*np
)
56 /* Transform a packet in UDP format to raw Ethernet. Ignore the UDP
57 * addresses, always broadcast from 0.0.0.0.
61 /* Save the UDP I/O header. */
64 /* Fill in the Ethernet, IP and UDP headers. */
65 bp
->eth
->eh_dst
= BCAST_ETH
;
66 bp
->eth
->eh_src
= np
->eth
;
67 bp
->eth
->eh_proto
= htons(ETH_IP_PROTO
);
68 bp
->ip
->ih_vers_ihl
= 0x45;
70 bp
->ip
->ih_length
= htons(sizeof(ip_hdr_t
)
71 + sizeof(udp_hdr_t
) + udpio
.uih_data_len
);
73 bp
->ip
->ih_flags_fragoff
= ntohs(0x4000);
74 bp
->ip
->ih_ttl
= IP_MAX_TTL
;
75 bp
->ip
->ih_proto
= IPPROTO_UDP
;
76 bp
->ip
->ih_hdr_chk
= 0;
78 bp
->ip
->ih_dst
= BCAST_IP
;
79 bp
->ip
->ih_hdr_chk
= ~oneC_sum(0, bp
->ip
, sizeof(*bp
->ip
));
80 bp
->udp
->uh_src_port
= udpio
.uih_src_port
;
81 bp
->udp
->uh_dst_port
= udpio
.uih_dst_port
;
82 bp
->udp
->uh_length
= htons(sizeof(udp_hdr_t
) + udpio
.uih_data_len
);
83 bp
->udp
->uh_chksum
= 0;
84 bp
->udp
->uh_chksum
= ~udp_cksum(bp
->ip
->ih_src
, bp
->ip
->ih_dst
, bp
->udp
);
87 int ether2udp(buf_t
*bp
)
89 /* Transform an UDP packet read from raw Ethernet to normal UDP.
90 * Return true iff the packet is indeed UDP and has no errors.
94 if (bp
->eth
->eh_proto
!= htons(ETH_IP_PROTO
)
95 || bp
->ip
->ih_vers_ihl
!= 0x45
96 || bp
->ip
->ih_proto
!= IPPROTO_UDP
97 || oneC_sum(0, bp
->ip
, 20) != (u16_t
) ~0
98 || udp_cksum(bp
->ip
->ih_src
, bp
->ip
->ih_dst
, bp
->udp
) != (u16_t
) ~0
100 /* Not UDP/IP or checksums bad. */
103 udpio
.uih_src_addr
= bp
->ip
->ih_src
;
104 udpio
.uih_dst_addr
= bp
->ip
->ih_dst
;
105 udpio
.uih_src_port
= bp
->udp
->uh_src_port
;
106 udpio
.uih_dst_port
= bp
->udp
->uh_dst_port
;
107 udpio
.uih_ip_opt_len
= 0;
108 udpio
.uih_data_len
= ntohs(bp
->udp
->uh_length
) - sizeof(udp_hdr_t
);
113 void make_arp(buf_t
*bp
, network_t
*np
)
115 /* Create an ARP packet to query for my IP address. */
116 arp46_t
*arp
= (arp46_t
*) bp
->eth
;
118 memset(arp
, 0, sizeof(*arp
));
119 arp
->dstaddr
= BCAST_ETH
;
120 arp
->srcaddr
= np
->eth
;
121 arp
->ethtype
= htons(ETH_ARP_PROTO
);
122 arp
->hdr
= htons(ARP_ETHERNET
);
123 arp
->pro
= htons(ETH_IP_PROTO
);
124 arp
->op
= htons(ARP_REQUEST
);
129 memcpy(arp
->spa
, &np
->ip
, sizeof(np
->ip
));
130 memcpy(arp
->tpa
, &np
->ip
, sizeof(np
->ip
));
133 int is_arp_me(buf_t
*bp
, network_t
*np
)
135 /* True iff an ARP packet is a reply from someone else with an address I
136 * thought was mine. (That's like, bad.)
138 arp46_t
*arp
= (arp46_t
*) bp
->eth
;
140 if (arp
->ethtype
== htons(ETH_ARP_PROTO
)
141 && arp
->hdr
== htons(ARP_ETHERNET
)
142 && arp
->pro
== htons(ETH_IP_PROTO
)
143 && arp
->op
== htons(ARP_REPLY
)
144 && memcmp(&arp
->spa
, &np
->ip
, sizeof(np
->ip
)) == 0
145 && memcmp(&arp
->sha
, &np
->eth
, sizeof(np
->eth
)) != 0
147 np
->conflict
= arp
->sha
;
153 void icmp_solicit(buf_t
*bp
)
155 /* Fill in a router solicitation ICMP packet. */
156 icmp_hdr_t
*icmp
= (icmp_hdr_t
*) (bp
->ip
+ 1);
158 bp
->ip
->ih_vers_ihl
= 0x45;
159 bp
->ip
->ih_dst
= BCAST_IP
;
161 icmp
->ih_type
= ICMP_TYPE_ROUTE_SOL
;
163 icmp
->ih_hun
.ihh_unused
= 0;
165 icmp
->ih_chksum
= ~oneC_sum(0, icmp
, 8);
168 void icmp_advert(buf_t
*bp
, network_t
*np
)
170 /* Fill in a router advert to be sent to my own interface. */
172 icmp_hdr_t
*icmp
= (icmp_hdr_t
*) (bp
->ip
+ 1);
174 bp
->ip
->ih_vers_ihl
= 0x45;
175 bp
->ip
->ih_dst
= LOCALHOST
;
177 icmp
->ih_type
= ICMP_TYPE_ROUTER_ADVER
;
179 icmp
->ih_hun
.ihh_ram
.iram_na
= 1;
180 icmp
->ih_hun
.ihh_ram
.iram_aes
= 2;
181 icmp
->ih_hun
.ihh_ram
.iram_lt
= htons(DELTA_ADV
);
182 data
= (u32_t
*) icmp
->ih_dun
.uhd_data
;
183 data
[0] = np
->gateway
;
184 data
[1] = htonl((u32_t
) -9999);
186 icmp
->ih_chksum
= ~oneC_sum(0, icmp
, 16);
189 ipaddr_t
icmp_is_advert(buf_t
*bp
)
191 /* Check if an IP packet is a router advertisement, and if it's genuine,
192 * i.e. the sender is mentioned in the packet.
194 icmp_hdr_t
*icmp
= (icmp_hdr_t
*) (bp
->ip
+ 1);
197 if (icmp
->ih_type
== ICMP_TYPE_ROUTER_ADVER
) {
198 for (i
= 0; i
< icmp
->ih_hun
.ihh_ram
.iram_na
; i
++) {
199 if (((u32_t
*) icmp
->ih_dun
.uhd_data
)[2*i
] == bp
->ip
->ih_src
) {
201 return bp
->ip
->ih_src
;