FreeBSD/Linux Kernel Cross Reference
sys/ttd/ttd_comm.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * TTD Communications parsing code for the kernel ttd server.
28 *
29 * HISTORY:
30 * $Log: ttd_comm.c,v $
31 * Revision 2.2 93/05/10 23:24:28 rvb
32 * Checkin for MK80 branch.
33 * [93/05/10 15:05:52 grm]
34 *
35 * Revision 2.1.2.2 93/04/20 10:51:43 grm
36 * Changed for use with mips and machines of both endian types.
37 * Changed many of the types so that the same protocol will be
38 * decodable by many machine types.
39 * [93/04/20 grm]
40 *
41 * Revision 2.1.2.1 93/03/03 14:35:46 grm
42 * Second version of code. It works.
43 * [93/03/03 grm]
44 *
45 * Revision 2.1.1.10 93/01/22 15:51:24 grm
46 * Added request pkt length checks.
47 *
48 * Revision 2.1.1.9 93/01/21 13:02:00 grm
49 * Changed to ansi prototypes.
50 *
51 * Revision 2.1.1.8 92/10/23 21:16:53 grm
52 * Fixed bug in kttd_valid_request so that it looks at correct
53 * incoming packet.
54 * [92/10/23 grm]
55 *
56 * Revision 2.1.1.7 92/10/08 14:27:10 grm
57 * Now sends and receives packets.
58 * [92/10/08 grm]
59 *
60 * Revision 2.1.1.6 92/10/01 15:35:50 grm
61 * Restructuring of ttd code checkpoint.
62 * [92/10/01 grm]
63 *
64 * Revision 2.1.1.5 92/09/30 13:32:31 grm
65 * Changed for use with Mach specific kttd routines (sync and async).
66 * Added get_request, and valid_request.
67 * [92/09/30 grm]
68 *
69 * Revision 2.1.1.4 92/09/25 15:15:34 grm
70 * checkpointing...
71 * [92/09/25 grm]
72 *
73 * Revision 2.1.1.3 92/09/21 13:22:17 grm
74 * This version uses bootp, and responds to arp requests.
75 * [92/09/21 grm]
76 *
77 * Revision 2.1.1.2 92/09/15 18:27:57 grm
78 * Checkpoint version with bootp working.
79 *
80 * Revision 2.1.1.1 92/09/09 14:44:07 grm
81 * Initial checkin.
82 *
83 */
84 /***********************************************************
85 Copyright 1992 by Digital Equipment Corporation, Maynard, Massachusetts,
86
87 All Rights Reserved
88
89 Permission to use, copy, modify, and distribute this software and its
90 documentation for any purpose and without fee is hereby granted, provided
91 that the above copyright notice appear in all copies and that both that
92 copyright notice and this permission notice appear in supporting
93 documentation, and that the name of Digital not be used in advertising
94 or publicity pertaining to distribution of the software without specific,
95 written prior permission. Digital makes no representations about the
96 suitability of this software for any purpose. It is provided "as is"
97 without express or implied warranty.
98
99 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
100 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
101 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
102 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
103 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
104 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
105 SOFTWARE.
106
107 ******************************************************************/
108
109 /*****************************************************/
110 /* ttd_comm.c */
111 /* Simple TTD/UDP/IP/ARP protocol package for lowttd */
112 /*****************************************************/
113
114 #include <device/if_ether.h>
115 #include <device/net_status.h>
116 #include <ttd/ttd_stub.h>
117 #include <ttd/ttd_comm.h>
118 #include <ttd/ttd_types.h>
119 #include <ttd/ttd_msg.h>
120 #include <ttd/ttd_debug.h>
121
122
123 static struct ether_hardware_address broadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
124
125 static struct ip_address my_ip_addr;
126 static struct ip_address ip_broadcast = {0xff, 0xff, 0xff, 0xff};
127 static struct ip_address ip_undefined = {0x00, 0x00, 0x00, 0x00};
128
129 #define skip_pkt_header(pkt) (arp_packet_t)((natural_t)pkt + sizeof(struct packet_header))
130
131 /*
132 * My own damn byte swapping routines:
133 */
134 #if BYTE_MSF
135 #else
136 u_short netswap_2_bytes(u_short n)
137 {
138 u_short tmp0;
139
140 tmp0 = (n << 8);
141 tmp0 |= (n >> 8);
142
143 return tmp0;
144 }
145
146 uint32 netswap_4_bytes(uint32 n)
147 {
148 uint32 tmp0, tmp1;
149
150 tmp0 = (n << 24) | (n >> 24);
151 tmp1 = (n & 0xff00) << 8;
152 tmp0 |= tmp1;
153 tmp1 = (n >> 8) & 0xff00;
154 return tmp0 | tmp1;
155 }
156 #endif /* BYTE_MSF */
157
158 /***************************************/
159 /* Checksum routines */
160 /***************************************/
161
162 /*
163 * finish_checksum converts a two's complement accumulation of
164 * HalfWords into the one's complement checksum.
165 */
166 static int finish_checksum(int w)
167 {
168 if (w == 0)
169 return 0xffff;
170 while (w > 0xffff)
171 w = (w & 0xffff) + (w >> 16);
172 return w ^ 0xffff;
173 }
174
175 /*
176 * checksum_ip_header is applied to an IP direct from the
177 * network interface, before any byteswapping.
178 * Note that this means that the addition is
179 * performed with the bytes of each halfword
180 * reversed, but this is OK due to the magic
181 * nature of ones complement arithmetic!
182 * A checksum in network order is returned.
183 */
184 static int checksum_ip_header(struct ip_header *ip)
185 {
186 half_word_t *wp;
187 int all, i, ip_header_halfwords;
188
189 all = - ip->header_checksum; /* don't count checksum field */
190 wp = (half_word_t *) ip;
191 ip_header_halfwords = ip->header_words * 2;
192 for (i = 0; i < ip_header_halfwords; i++)
193 all += wp[i];
194 return (finish_checksum(all));
195 }
196
197 static boolean_t ip_checksum_ok(struct ip_header *ip)
198 {
199 int net_check;
200
201 net_check = ip->header_checksum;
202 return ((net_check == 0) || (checksum_ip_header(ip) == net_check));
203 }
204
205 static void set_ip_checksum(struct ip_header *ip)
206 {
207 ip->header_checksum = checksum_ip_header(ip);
208 }
209
210 static void byteswap_ip_header(struct ip_header *ip_hdr)
211 {
212 ip_hdr->length = netswap_2_bytes(ip_hdr->length);
213 ip_hdr->id = netswap_2_bytes(ip_hdr->id);
214 ip_hdr->fragment_stuff = netswap_2_bytes(ip_hdr->fragment_stuff);
215 ip_hdr->header_checksum = netswap_2_bytes(ip_hdr->header_checksum);
216 }
217
218 /*
219 * Use this after checking the IP header checksum.
220 * A checksum in network order is returned.
221 */
222 static int checksum_udp(struct udp_header *udp,
223 struct udp_pseudo_header pseudo_hdr)
224 {
225 half_word_t *wp;
226 byte_t *bp;
227 int all, i, udp_bytes, udp_halfwords;
228
229 all = - udp->checksum; /* don't count checksum field */
230 wp = (half_word_t *) &pseudo_hdr;
231 for (i = 0; i < sizeof(struct udp_pseudo_header) / sizeof(half_word_t); i++)
232 all += wp[i];
233 udp_bytes = netswap_2_bytes(udp->length);
234 udp_halfwords = udp_bytes / 2;
235 wp = (half_word_t *) udp;
236 for (i = 0; i <= udp_halfwords - 1; i++)
237 all += wp[i];
238 if ((udp_bytes % 2) == 1) {
239 bp = (byte_t *) wp;
240 all += bp[udp_bytes - 1];
241 }
242 return (finish_checksum (all));
243 }
244
245 static boolean_t udp_checksum_ok(struct udp_header *udp,
246 struct udp_pseudo_header pseudo_hdr)
247 {
248 int net_check;
249
250 net_check = udp->checksum;
251 return ((net_check == 0) ||
252 (checksum_udp(udp, pseudo_hdr) == net_check));
253 }
254
255 static void set_udp_checksum(struct udp_header *udp,
256 struct udp_pseudo_header ph)
257 {
258 udp->checksum = checksum_udp(udp, ph);
259 }
260
261 /*****************************************/
262 /* Simple-minded ARP Server */
263 /*****************************************/
264
265 static boolean_t eq_ip(struct ip_address a, struct ip_address b)
266 {
267 int i;
268
269 for (i = 0; i < IP_ADDRESS_LENGTH; i++)
270 if (a.array[i] != b.array[i])
271 return FALSE;
272 return TRUE;
273 }
274
275 static foocount = 10;
276
277 void dump_arp_packet(struct ttd_ether_header * e, arp_packet_t p)
278 {
279 printf("\neh.dest %x:%x:%x:%x:%x:%x, ",
280 e->dest.array[0],
281 e->dest.array[1],
282 e->dest.array[2],
283 e->dest.array[3],
284 e->dest.array[4],
285 e->dest.array[5]);
286 printf("eh.source %x:%x:%x:%x:%x:%x, ",
287 e->source.array[0],
288 e->source.array[1],
289 e->source.array[2],
290 e->source.array[3],
291 e->source.array[4],
292 e->source.array[4]);
293 printf("eh.protocol = %x, ", e->protocol);
294 printf("arp.hat %x, ", p->hardware_addr_type);
295 printf("arp.pat %x, ", p->protocol_addr_type);
296 printf("arp.hal %x, ", p->hardware_addr_length);
297 printf("arp.pal %x, ", p->protocol_addr_length);
298 printf("arp.aop %x, ", p->arp_opcode);
299 printf("arp.sha %x:%x:%x:%x:%x:%x",
300 p->ip.source_hardware_addr.array[0],
301 p->ip.source_hardware_addr.array[1],
302 p->ip.source_hardware_addr.array[2],
303 p->ip.source_hardware_addr.array[3],
304 p->ip.source_hardware_addr.array[4],
305 p->ip.source_hardware_addr.array[5]);
306 printf("arp.spa %d.%d.%d.%d, ",
307 p->ip.source_protocol_addr.array[0],
308 p->ip.source_protocol_addr.array[1],
309 p->ip.source_protocol_addr.array[2],
310 p->ip.source_protocol_addr.array[3]);
311 printf("arp.dha %x:%x:%x:%x:%x:%x",
312 p->ip.dest_hardware_addr.array[0],
313 p->ip.dest_hardware_addr.array[1],
314 p->ip.dest_hardware_addr.array[2],
315 p->ip.dest_hardware_addr.array[3],
316 p->ip.dest_hardware_addr.array[4],
317 p->ip.dest_hardware_addr.array[5]);
318 printf("arp.dpa %d.%d.%d.%d, ",
319 p->ip.dest_protocol_addr.array[0],
320 p->ip.dest_protocol_addr.array[1],
321 p->ip.dest_protocol_addr.array[2],
322 p->ip.dest_protocol_addr.array[3]);
323
324 if (!foocount--)
325 while(1);
326 }
327
328 static void handle_arp_packet(int unit,
329 struct ttd_ether_header * ehp,
330 struct packet_header * pkt)
331
332 {
333 arp_packet_t p;
334 arpether_packet_t rpkt;
335
336 /*
337 * Set to point at the separate arp part of the received message
338 */
339 p = skip_pkt_header(pkt);
340
341 /* ARP is simple; req is turned into reply and xmitted inline. */
342
343 if (p->hardware_addr_type != ARPTYPE_ETHER) { /* != 0x0100 */
344 return;
345 }
346 if (p->protocol_addr_type != ETHERTYPE_IP) { /* != 0x0008 */
347 return;
348 }
349 if (p->hardware_addr_length != ETHER_ADDRESS_LENGTH) { /* != 0x06 */
350 return;
351 }
352 if (p->protocol_addr_length != IP_ADDRESS_LENGTH) { /* != 0x04 */
353 return;
354 }
355 if (p->arp_opcode != ARPOP_REQUEST) { /* != 0x0100 */
356 return;
357 }
358 if (!eq_ip(p->ip.dest_protocol_addr, my_ip_addr)) {
359 return;
360 }
361
362 /*
363 * Fix up the reply message:
364 */
365
366 rpkt = (arpether_packet_t)ttd_reply_msg;
367
368 bzero(rpkt, MIN_PACKET);
369
370 rpkt->eh.dest = ehp->source;
371 rpkt->eh.source = ttd_host_ether_id;
372 rpkt->eh.protocol = ETHERTYPE_ARP;
373
374 rpkt->arp.hardware_addr_type = ARPTYPE_ETHER;
375 rpkt->arp.protocol_addr_type = ETHERTYPE_IP;
376 rpkt->arp.hardware_addr_length = ETHER_ADDRESS_LENGTH;
377 rpkt->arp.protocol_addr_length = IP_ADDRESS_LENGTH;
378
379 rpkt->arp.ip.dest_protocol_addr = p->ip.source_protocol_addr;
380 rpkt->arp.ip.dest_hardware_addr = p->ip.source_hardware_addr;
381 rpkt->arp.ip.source_protocol_addr = my_ip_addr;
382 rpkt->arp.ip.source_hardware_addr = ttd_host_ether_id;
383 rpkt->arp.arp_opcode = ARPOP_REPLY;
384
385 /*
386 * Send a reply....
387 */
388
389 ttd_send_packet(ttd_device_unit, rpkt, MIN_PACKET);
390 }
391
392 /*****************************************/
393 /* Bootp Packet Handling */
394 /*****************************************/
395
396 /*
397 * Generate a ``random'' transaction id number. It builds it out of the
398 * hardware ethernet id. It's not unique -- XXX
399 */
400 static uint32 build_xid(void)
401 {
402 natural_t ret;
403
404 ret = ((ttd_host_ether_id.array[0] <<12) ||
405 (ttd_host_ether_id.array[5] <<8) ||
406 (ttd_host_ether_id.array[1] <<4) ||
407 ttd_host_ether_id.array[4]);
408
409 ret ^= ((ttd_host_ether_id.array[2] <<12) ||
410 (ttd_host_ether_id.array[3] <<4));
411
412 return ret;
413 }
414
415 void dump_ipudpbootp(char * s, sndbootp_t ptr)
416 {
417 recbootp_t p = (recbootp_t)&ptr->ui;
418 bootp_t bp = (bootp_t)p->bpbuf;
419
420 printf("%s",s);
421
422 if (bp->bp_op == BOOTREQUEST) {
423 printf(", bootrequest is ok\n");
424 return;
425 }else{
426 printf("\n");
427 }
428
429 printf("UDP Header: source %d (%d)\n",p->ui.udp_h.source_port,
430 ((natural_t)&p->ui.udp_h.dest_port-(natural_t)&p->ui.udp_h.source_port));
431 printf("dest %d, (%d)\n",p->ui.udp_h.dest_port,
432 ((natural_t)&p->ui.udp_h.length - (natural_t)&p->ui.udp_h.dest_port));
433 printf("length %d, (%d)\n",p->ui.udp_h.length,
434 ((natural_t)&p->ui.udp_h.checksum - (natural_t)&p->ui.udp_h.length));
435 printf("checksum %d, (%d)\n",p->ui.udp_h.checksum,
436 ((natural_t)&bp->bp_op - (natural_t)&p->ui.udp_h.checksum));
437 printf("BOOTP Contents: bp_op %d, (%d)\n", bp->bp_op,
438 ((natural_t)&bp->bp_htype - (natural_t)&bp->bp_op));
439 printf("bp_htype %d, (%d)\n", bp->bp_htype,
440 ((natural_t)&bp->bp_hlen - (natural_t)&bp->bp_htype));
441 printf("bp_hlen %d, (%d)\n", bp->bp_hlen,
442 ((natural_t)&bp->bp_hops - (natural_t)&bp->bp_hlen));
443 printf("bp_hops %d, (%d)\n", bp->bp_hops,
444 ((natural_t)&bp->bp_xid - (natural_t)&bp->bp_hops));
445 printf("bp_xid %d, (%d)\n", bp->bp_xid,
446 ((natural_t)&bp->bp_secs - (natural_t)&bp->bp_xid));
447 printf("bp_secs %d, (%d)\n", bp->bp_secs,
448 ((natural_t)&bp->bp_unused - (natural_t)&bp->bp_secs));
449 printf("bp_unused %d, (%d)\n", bp->bp_unused,
450 ((natural_t)&bp->bp_ciaddr - (natural_t)&bp->bp_unused));
451 printf("bp_ciaddr %d.%d.%d.%d, (%d)\n",
452 bp->bp_ciaddr.array[0],
453 bp->bp_ciaddr.array[1],
454 bp->bp_ciaddr.array[2],
455 bp->bp_ciaddr.array[3],
456 ((natural_t)&bp->bp_yiaddr - (natural_t)&bp->bp_ciaddr));
457 printf("bp_yiaddr %d.%d.%d.%d, (%d)\n",
458 bp->bp_yiaddr.array[0],
459 bp->bp_yiaddr.array[1],
460 bp->bp_yiaddr.array[2],
461 bp->bp_yiaddr.array[3],
462 ((natural_t)&bp->bp_siaddr - (natural_t)&bp->bp_yiaddr));
463 printf("bp_siaddr %d.%d.%d.%d, (%d)\n",
464 bp->bp_siaddr.array[0],
465 bp->bp_siaddr.array[1],
466 bp->bp_siaddr.array[2],
467 bp->bp_siaddr.array[3],
468 ((natural_t)&bp->bp_giaddr - (natural_t)&bp->bp_siaddr));
469 printf("bp_giaddr %d.%d.%d.%d, (%d)\n",
470 bp->bp_giaddr.array[0],
471 bp->bp_giaddr.array[1],
472 bp->bp_giaddr.array[2],
473 bp->bp_giaddr.array[3],
474 ((natural_t)&bp->bp_chaddr - (natural_t)&bp->bp_giaddr));
475 printf("bp_chaddr %x:%x:%x:%x:%x:%x, (%d)\n",
476 bp->bp_chaddr[0],
477 bp->bp_chaddr[1],
478 bp->bp_chaddr[2],
479 bp->bp_chaddr[3],
480 bp->bp_chaddr[4],
481 bp->bp_chaddr[5],
482 ((natural_t)&bp->bp_sname - (natural_t)&bp->bp_chaddr));
483
484 while(1);
485 }
486
487 /*
488 * Builds an ethernet packet that contains a valid bootp
489 * request. This consists of a valid ethernet header, valid
490 * ip header, udp header, and bootp request record.
491 */
492 static void build_bootp_packet(sndbootp_t buf, int size)
493 {
494 bootp_t bp;
495 uint32 tmp;
496
497 bp = (bootp_t)buf->bpbuf;
498
499 /*
500 * Clean out the buffer.
501 */
502 bzero(buf,size);
503
504 /*
505 * Set up ethernet header:
506 */
507 buf->eh.dest = broadcast;
508 buf->eh.source = ttd_host_ether_id;
509 buf->eh.protocol = ETHERTYPE_IP;
510
511 /*
512 * Set up ip header:
513 */
514 buf->ui.ip_h.header_checksum = 0;
515 buf->ui.ip_h.id = 1;
516 buf->ui.ip_h.fragment_stuff = 0;
517
518 /* Don't know about these two!! XXX */
519 buf->ui.ip_h.type_of_service = 0;
520 buf->ui.ip_h.version = 4;
521
522 buf->ui.ip_h.header_words = OUT_IP_HEADER_WORDS;
523 buf->ui.ip_h.time_to_live = 0xff;
524
525 buf->ui.ip_h.protocol = PROTOCOL_UDP;
526 buf->ui.ip_h.source = ip_undefined;
527 buf->ui.ip_h.dest = ip_broadcast;
528 buf->ui.ip_h.length = sizeof(struct recbootp);
529
530 /* Fix up for network byte order. */
531 byteswap_ip_header(&buf->ui.ip_h);
532 set_ip_checksum(&buf->ui.ip_h);
533
534 /*
535 * Set up the udp header:
536 */
537 buf->ui.udp_h.source_port = netswap_2_bytes(UDP_BOOTPC);
538 buf->ui.udp_h.dest_port = netswap_2_bytes(UDP_BOOTPS);
539 buf->ui.udp_h.length = netswap_2_bytes(sizeof(struct udp_header)+
540 sizeof(struct bootp));
541 buf->ui.udp_h.checksum = 0;
542
543 /*
544 * Set up bootp info:
545 */
546 bp->bp_op = BOOTREQUEST;
547 bp->bp_htype = ETHER_HTYPE;
548 bp->bp_hlen = ETHER_ADDRESS_LENGTH;
549 tmp = netswap_4_bytes(build_xid());
550 bp->bp_xid[0] = tmp & 0xf;
551 bp->bp_xid[1] = (tmp & 0xf0) >> 8;
552 bp->bp_xid[2] = (tmp & 0xf00) >> 8;
553 bp->bp_xid[3] = (tmp & 0xf000) >> 8;
554 bp->bp_chaddr[0] = ttd_host_ether_id.array[0];
555 bp->bp_chaddr[1] = ttd_host_ether_id.array[1];
556 bp->bp_chaddr[2] = ttd_host_ether_id.array[2];
557 bp->bp_chaddr[3] = ttd_host_ether_id.array[3];
558 bp->bp_chaddr[4] = ttd_host_ether_id.array[4];
559 bp->bp_chaddr[5] = ttd_host_ether_id.array[5];
560 }
561
562 /*
563 * Check an incoming message for a valid bootp reply.
564 */
565 static boolean_t check_bootp_reply(void)
566 {
567 recbootp_t rbootp;
568 struct ttd_ether_header * ehp;
569 bootp_t bp;
570 uint32 tmp;
571
572 /*
573 * Set up the pointers to point at the separate ether and ip data
574 * in the netkmsg.
575 */
576 ehp = (struct ttd_ether_header *)
577 &((net_rcv_msg_t)&((ipc_kmsg_t)ttd_request_msg)->ikm_header)->header[0];
578 rbootp = (recbootp_t)((natural_t)(&((net_rcv_msg_t)
579 &((ipc_kmsg_t)ttd_request_msg)->ikm_header)->packet[0])
580 +(natural_t)(sizeof(struct packet_header)));
581
582 bp = (bootp_t)rbootp->bpbuf;
583
584 #if DEBUG_ETHER_PACKETS
585 printf("cBr.1 %x:%x:%x:%x:%x:%x %x:%x:%x:%x:%x:%x ",
586 ehp->dest.array[0],
587 ehp->dest.array[1],
588 ehp->dest.array[2],
589 ehp->dest.array[3],
590 ehp->dest.array[4],
591 ehp->dest.array[5],
592 ehp->source.array[0],
593 ehp->source.array[1],
594 ehp->source.array[2],
595 ehp->source.array[3],
596 ehp->source.array[4],
597 ehp->source.array[5]);
598 #endif /* DEBUG_ETHER_PACKETS */
599
600 /*
601 * Check the ethernet header for my destination address and
602 * the Ethernet IP protocol.
603 */
604 if (!ETHER_ADDRESS_EQ(&ehp->dest, &ttd_host_ether_id))
605 return FALSE;
606 if (ehp->protocol != ETHERTYPE_IP)
607 return FALSE;
608 /*
609 * Got a packet for my machine. Check the IP for datagram packet.
610 */
611
612 if (!ip_checksum_ok(&rbootp->ui.ip_h))
613 return FALSE;
614 byteswap_ip_header(&rbootp->ui.ip_h);
615
616 if (rbootp->ui.ip_h.protocol != PROTOCOL_UDP)
617 return FALSE;
618
619 /*
620 * It's a UDP datagram (maybe :-))
621 * Check for bootp udp ports, udp length, xid, etc...
622 */
623
624 if (rbootp->ui.udp_h.source_port != netswap_2_bytes(UDP_BOOTPS))
625 return FALSE;
626 if (rbootp->ui.udp_h.dest_port != netswap_2_bytes(UDP_BOOTPC))
627 return FALSE;
628 if (netswap_2_bytes(rbootp->ui.udp_h.length) <
629 (sizeof(struct udp_header) + sizeof(struct bootp)))
630 return FALSE;
631
632 if (bp->bp_op != BOOTREPLY)
633 return FALSE;
634 tmp = netswap_4_bytes(build_xid());
635 if ((bp->bp_xid[0] != tmp & 0xf) &&
636 (bp->bp_xid[1] != (tmp & 0xf0) >> 8) &&
637 (bp->bp_xid[2] != (tmp & 0xf00) >> 8) &&
638 (bp->bp_xid[3] != (tmp & 0xf000) >> 8))
639 return FALSE;
640
641 if (bp->bp_htype != ETHER_HTYPE)
642 return FALSE;
643 if (bp->bp_hlen != ETHER_ADDRESS_LENGTH)
644 return FALSE;
645
646 my_ip_addr = bp->bp_yiaddr;
647 return TRUE;
648 }
649
650 /*
651 * Try to get my host ip via the bootp protocol. This routine
652 * sends a bootp packet and then waits for a valid bootp return
653 * call. The routine returns true upon success, false if no bootp
654 * server responds within the timeout period.
655 */
656 static boolean_t do_bootp(void)
657 {
658 natural_t max_tries;
659 natural_t backoff;
660 natural_t recvd;
661
662 /*
663 * Only send BOOTPMAX_TRIES bootp queries before giving up.
664 */
665 for(max_tries = BOOTPMAX_TRIES, backoff = 4;
666 max_tries;
667 max_tries--, backoff = ((backoff < 60) ? (backoff*2) : 60)) {
668
669 build_bootp_packet((sndbootp_t)ttd_request_msg, BOOTPMSG_SIZE);
670
671 ttd_send_packet(ttd_device_unit, ttd_request_msg, BOOTPMSG_SIZE);
672
673 for(recvd = 0;
674 recvd < backoff;
675 recvd++) {
676 /*
677 * Clean up receive buffer and get a message
678 */
679 bzero(ttd_request_msg, BOOTPMSG_SIZE);
680 ttd_get_packet(ttd_device_unit);
681
682 if (check_bootp_reply())
683 return TRUE;
684 }
685 }
686 return FALSE;
687 }
688
689 boolean_t ttd_ip_bootp(void)
690 {
691 boolean_t ret;
692
693 /*
694 * Turn on ttd so that ether drivers work with the polling routines.
695 */
696
697 printf("Looking for bootp server...");
698 kttd_active = MAX_KTTD_ACTIVE;
699 ret = do_bootp();
700 kttd_active = MIN_KTTD_ACTIVE;
701
702 if(ret) {
703 printf("found bootp server, ip address = %d.%d.%d.%d\n",
704 my_ip_addr.array[0],
705 my_ip_addr.array[1],
706 my_ip_addr.array[2],
707 my_ip_addr.array[3]);
708 }else{
709 kttd_enabled = FALSE;
710 printf("\ncouldn't find a bootp server.\n");
711 }
712
713 return ret;
714 }
715
716 /***************************************/
717 /* IP Packet Handling */
718 /***************************************/
719
720 static void pseudo_header(struct ip_header *ip,
721 struct udp_pseudo_header *pseudo_hdr)
722 {
723 pseudo_hdr->source = ip->source;
724 pseudo_hdr->dest = ip->dest;
725 pseudo_hdr->zero = 0;
726 pseudo_hdr->protocol = ip->protocol;
727 /* pseudo_hdr->udpLength = <set later>; -- must be in network order */
728 }
729
730 void dump_ether_header(char * mess, struct ttd_ether_header * ehp)
731 {
732 printf("%s dhost: %x:%x:%x:%x:%x:%x",
733 mess,
734 ehp->dest.array[0],
735 ehp->dest.array[1],
736 ehp->dest.array[2],
737 ehp->dest.array[3],
738 ehp->dest.array[4],
739 ehp->dest.array[5]);
740
741 printf(" shost: %x:%x:%x:%x:%x:%x",
742 ehp->source.array[0],
743 ehp->source.array[1],
744 ehp->source.array[2],
745 ehp->source.array[3],
746 ehp->source.array[4],
747 ehp->source.array[5]);
748
749 printf(" type = %x",ehp->protocol);
750 }
751
752 /*
753 * New routines for kttd:
754 */
755
756 /*
757 * poll_request:
758 *
759 * Get a packet from the ethernet via polling.
760 *
761 */
762 static void kttd_poll_request(void)
763 {
764 ttd_get_packet(ttd_device_unit);
765 }
766
767 static boolean_t valid_udp_packet(struct udp_packet *udp,
768 struct udp_pseudo_header udp_phdr,
769 natural_t udp_length,
770 vm_offset_t *ttd_pkt)
771 {
772
773 udp_phdr.udp_length = udp->hdr.length; /* in network order */
774
775 if (!udp_checksum_ok(&udp->hdr, udp_phdr))
776 return FALSE;
777
778 if (udp->hdr.dest_port != TTD_PORT) /* in network order */
779 return FALSE;
780
781 if (netswap_2_bytes(udp->hdr.length) > udp_length) {
782 if (kttd_debug)
783 printf("INVALID UDP Header Length!!!\n");
784 return FALSE;
785 }
786
787 *ttd_pkt = (vm_offset_t)&udp->data[0];
788
789 return TRUE;
790 }
791
792 static boolean_t valid_ip_packet(ip_packet_t *ip,
793 natural_t ip_len,
794 struct udp_pseudo_header *udp_phdr)
795 {
796 /*
797 * Make sure checksum adds up!
798 */
799 if (!ip_checksum_ok (&ip->hdr))
800 return FALSE;
801
802 pseudo_header(&ip->hdr, udp_phdr); /* pseudo-header for UDP */
803
804 byteswap_ip_header(&ip->hdr); /* Can't touch header fields before this! */
805
806 /*
807 * IP's length is bad, throw packet away...
808 */
809 if ((ip->hdr.length > ip_len) || (ip_len > MAX_ETHER_DATA)) {
810 byteswap_ip_header(&ip->hdr);
811 if (kttd_debug)
812 printf("INVALID IP LENGTH!!! 0x%x:0x%x\n",
813 ip->hdr.length, ip_len);
814 return FALSE;
815 }
816
817 /*
818 * TTD packets are type UDP, discard others...
819 */
820 if (ip->hdr.protocol != PROTOCOL_UDP) {
821 byteswap_ip_header(&ip->hdr);
822 return FALSE;
823 }
824
825 return TRUE;
826
827 }
828
829 static boolean_t valid_ether_packet(struct ttd_ether_header *ehp,
830 struct packet_header *pkt,
831 boolean_t handle_arp)
832 {
833 /*
834 * ignore broadcast replies
835 */
836 if (ETHER_ADDRESS_EQ (&ehp->source, &broadcast)) {
837 return FALSE;
838 }
839
840 /*
841 * If arp packet then check for broadcast request.
842 */
843 if ((ehp->protocol == ETHERTYPE_ARP) && handle_arp) {
844 handle_arp_packet(ttd_device_unit, ehp, pkt);
845 return FALSE;
846 }
847
848 if (ehp->protocol != ETHERTYPE_IP) {
849 return FALSE;
850 }
851
852 /*
853 * IP packet, means this might be a ttd packet.
854 *
855 * We aren't looking for broadcast ip dest though....
856 */
857
858 if (ETHER_ADDRESS_EQ(&ehp->dest, &broadcast))
859 return FALSE;
860
861 /*
862 * Passes the ethernet header check...
863 */
864 return TRUE;
865 }
866
867 /*
868 * kttd_valid_request(request, handle_arp):
869 *
870 * Given a pointer to an ipc_kmsg, determine whether it is a valid kttd
871 * request packet.
872 *
873 * Arp packets are handled here handle_arp is TRUE.
874 *
875 * If the packet is a valid KTTD packet, the procedure sets the ttd_data
876 * paramter to point to the start of the TTD message and returns TRUE. If
877 * it is not a valid ttd packet it returns FALSE.
878 *
879 */
880 boolean_t kttd_valid_request(ipc_kmsg_t request,
881 boolean_t handle_arp,
882 vm_offset_t *ttd_data,
883 natural_t *request_length)
884 {
885 struct ttd_ether_header *ehp;
886 struct packet_header *pkt;
887
888 ip_packet_t *ip;
889 natural_t length;
890 natural_t ip_hsize;
891
892 struct udp_packet *udp_pkt;
893 struct udp_pseudo_header udp_phdr;
894 #if 1
895 int i;
896 u_char *ptr;
897 #endif 1
898
899 vm_offset_t ttd_pkt;
900
901 /*
902 * Check Ether packet:
903 */
904 ehp = (struct ttd_ether_header *)
905 &((net_rcv_msg_t)
906 &((ipc_kmsg_t)request)->ikm_header)->header[0];
907 pkt = (struct packet_header *)
908 &((net_rcv_msg_t)
909 &((ipc_kmsg_t)request)->ikm_header)->packet[0];
910
911 if (!valid_ether_packet(ehp, pkt, handle_arp))
912 return FALSE;
913
914 /*
915 * Check IP Packet:
916 */
917 length = pkt->length;
918 ip = (ip_packet_t *)skip_pkt_header(pkt);
919
920 if (!valid_ip_packet(ip, length, &udp_phdr))
921 return FALSE;
922
923 /*
924 * Check UDP Packet:
925 */
926
927 length -= sizeof(struct ip_header);
928 ip_hsize = ip->hdr.header_words * 4;
929 udp_pkt = (udp_packet_t) &ip->data[ip_hsize / 2];
930
931 if (!valid_udp_packet(udp_pkt, udp_phdr, length, ttd_data)) {
932 byteswap_ip_header(&ip->hdr);
933 return FALSE;
934 }
935
936 /*
937 * Passed all of the tests, it's a TTD packet.
938 */
939
940 /* ttd_data was set by valid_udp_packet */
941
942 *request_length = (length - sizeof(struct udp_header) -
943 sizeof(struct packet_header));
944
945 #if DEBUG_ETHER_PACKETS
946 dump_ether_header("Ether header: ", ehp);
947 printf("\nPacket contents: ");
948 ptr = (u_char *)ip;
949 for (i = 0; i < 100; i++) {
950 printf("%x:",(u_char) *ptr);
951 ptr++;
952 }
953 printf("\n");
954 #endif /* DEBUG_ETHER_PACKETS */
955
956 return TRUE;
957 }
958
959 /*
960 * kttd_get_request:
961 *
962 * This routines waits for a ttd request packet to arrive on the
963 * ethernet. It does a polling input for a packet, and then checks
964 * the packet for a valid ttd request. It loops until it receives
965 * a valid ttd request.
966 *
967 * Note: this routine only called from the synchronous ttd code,
968 * so arp requests are handled.
969 *
970 * We assume that the ttd driver support has been checked and is
971 * present.
972 */
973 boolean_t kttd_get_request(vm_offset_t *ttd_request,
974 natural_t *request_length)
975 {
976 #if VERBOSE
977 if (kttd_debug)
978 printf("kttd_get_request entered.\n");
979 #endif /* VERBOSE */
980
981 /*
982 * clean it out, just to be safe.
983 */
984 bzero(ttd_request_msg, MAX_TTD_MSG_SIZE);
985
986 for(;;) {
987 kttd_poll_request();
988
989 #if VERBOSE
990 if (kttd_debug)
991 printf("-");
992 #endif /* VERBOSE */
993
994 if (kttd_valid_request((ipc_kmsg_t)ttd_request_msg,
995 TRUE,
996 (vm_offset_t *)ttd_request,
997 request_length))
998 break;
999 }
1000
1001 return TRUE;
1002 }
1003
1004 /*
1005 * Index into the reply.
1006 */
1007 ttd_reply_t skip_net_headers(char * ptr)
1008 {
1009 /*
1010 * Skip ether header.
1011 */
1012 ptr += sizeof (struct ttd_ether_header);
1013
1014 /*
1015 * Skip IP header.
1016 *
1017 * This is dangerous!!! IP header length is assumed to
1018 * be constant for this to work. Make sure when we
1019 * build the reply packet that we are setting the header
1020 * words field correctly.
1021 */
1022 ptr += OUT_IP_HEADER_BYTES;
1023
1024 /*
1025 * Skip UDP header.
1026 */
1027 ptr += sizeof (struct udp_header);
1028
1029 return (ttd_reply_t)ptr;
1030 }
1031
1032 /*
1033 * Wrap the old build and finish routines into one build
1034 * routine.
1035 */
1036 void complete_and_send_ttd_reply(natural_t kttd_reply_length)
1037 {
1038 struct ttd_ether_header *req_ether_header;
1039 struct packet_header *req_ether_pkt;
1040 struct ttd_ether_header *rpy_ether_header;
1041
1042 struct ip_header *req_ip_header;
1043
1044 struct udp_header *req_udp_header;
1045
1046 struct udp_header *rpy_udp_header;
1047 struct ip_header *rpy_ip_header;
1048
1049 natural_t tmp_length;
1050 struct udp_pseudo_header uph;
1051
1052 ipc_kmsg_t tmp_kmsg;
1053
1054 tmp_kmsg = (ipc_kmsg_t)((kttd_current_kmsg == (ipc_kmsg_t)NULL) ?
1055 ttd_request_msg :
1056 kttd_current_kmsg);
1057
1058 /*
1059 * Build the ethernet part of the reply.
1060 */
1061
1062 req_ether_header = (struct ttd_ether_header *)
1063 &((net_rcv_msg_t)&(tmp_kmsg)->ikm_header)->header[0];
1064 req_ether_pkt = (struct packet_header *)
1065 &((net_rcv_msg_t)&(tmp_kmsg)->ikm_header)->packet[0];
1066
1067
1068 /*
1069 * The ttd_reply_msg is just the ether/ip/udp/ttd, it doesn't
1070 * have the kmsg header junk that the ttd_request_msg has.
1071 */
1072 rpy_ether_header = (struct ttd_ether_header *)ttd_reply_msg;
1073
1074 rpy_ether_header->source = req_ether_header->dest;
1075 rpy_ether_header->dest = req_ether_header->source;
1076 rpy_ether_header->protocol = req_ether_header->protocol;
1077
1078 /*
1079 * Partially build the IP header.
1080 *
1081 * Note: Everything at this point is NOT in network order.
1082 * The finish_ttd_build procedure must insert the
1083 * correct length, byteswap the reply header and
1084 * generate the checksum and insert it.
1085 */
1086
1087 req_ip_header = (struct ip_header *)skip_pkt_header(req_ether_pkt);
1088 rpy_ip_header = (struct ip_header *)((natural_t)rpy_ether_header +
1089 sizeof (struct ttd_ether_header));
1090
1091 rpy_ip_header->header_words = OUT_IP_HEADER_WORDS;
1092 rpy_ip_header->version = req_ip_header->version;
1093 rpy_ip_header->type_of_service = req_ip_header->type_of_service;
1094 /* rpy_ip_header->length = <set later>; */
1095 rpy_ip_header->fragment_stuff = 0;
1096 rpy_ip_header->id = 0;
1097 /* rpy_ip_header->header_checksum = <set later>; */
1098 rpy_ip_header->protocol = req_ip_header->protocol;
1099 rpy_ip_header->time_to_live = 255;
1100 rpy_ip_header->source = req_ip_header->dest;
1101 rpy_ip_header->dest = req_ip_header->source;
1102
1103 /*
1104 * Partially build the UDP header.
1105 *
1106 * Note: Same problem here as the IP layer. We will still need
1107 * to set the length in the finish_ttd_build section along
1108 * with the checksum (if not using zero).
1109 */
1110
1111 req_udp_header = (struct udp_header *)((natural_t)req_ip_header +
1112 ((natural_t)req_ip_header->header_words * 4));
1113 rpy_udp_header = (struct udp_header *)((natural_t)rpy_ip_header +
1114 OUT_IP_HEADER_BYTES);
1115
1116 rpy_udp_header->source_port = req_udp_header->dest_port;
1117 rpy_udp_header->dest_port = req_udp_header->source_port;
1118 /* rpy_udp_header->length = <set later>; */
1119 /* rpy_udp_header->checksum = <set later>; */
1120
1121 /*
1122 * Sanity check. Make sure that the calculated ttd_reply_msg
1123 * is the same one we just came up with!!!
1124 */
1125
1126 if (kttd_debug && ((natural_t) skip_net_headers(ttd_reply_msg) !=
1127 ((natural_t)rpy_udp_header + (sizeof(struct udp_header))))) {
1128 printf("TTDComm.c: Woah!!! ttd_reply_msg is skewed!!\n");
1129 }
1130
1131 #if VERBOSE
1132 if (kttd_debug)
1133 printf("build_partial: ttd_reply should start at: 0x%x, ttd_kmsg 0x%x\n",
1134 (natural_t)rpy_udp_header + sizeof(struct udp_header),
1135 ttd_reply_msg);
1136 #endif /* VERBOSE */
1137
1138 /*
1139 * Fix up UDP length and checksum:
1140 */
1141
1142 tmp_length = kttd_reply_length + sizeof(struct udp_header);
1143 rpy_udp_header->length = netswap_2_bytes(tmp_length);
1144
1145 uph.source = rpy_ip_header->source;
1146 uph.dest = rpy_ip_header->dest;
1147 uph.zero = 0;
1148 uph.protocol = rpy_ip_header->protocol;
1149 uph.udp_length = rpy_udp_header->length;
1150
1151 set_udp_checksum(rpy_udp_header, uph);
1152
1153 /*
1154 * Fix up IP length and checksum:
1155 */
1156
1157 tmp_length += OUT_IP_HEADER_BYTES;
1158 rpy_ip_header->length = tmp_length;
1159 byteswap_ip_header(rpy_ip_header);
1160 set_ip_checksum(rpy_ip_header);
1161
1162 #if DEBUG_ETHER_PACKETS
1163 if (kttd_debug) {
1164 int i;
1165 u_char * ptr;
1166
1167 ptr = (u_char *)ttd_reply_msg;
1168
1169 for (i = 0; i< 100; i++)
1170 printf("%x: ", *ptr++);
1171
1172 printf("\nlength = %d",tmp_length);
1173
1174 }
1175 #endif /* DEBUG_ETHER_PACKETS */
1176
1177 /*
1178 * We've built it, let's send it off!!!
1179 */
1180 ttd_send_packet(ttd_device_unit, ttd_reply_msg,
1181 ((MIN_PACKET > tmp_length + sizeof(struct ttd_ether_header)) ?
1182 MIN_PACKET : tmp_length + sizeof(struct ttd_ether_header)));
1183 }
Cache object: fe8b29c6d0bfdae04c3ba0c2fe59c423
|