FreeBSD/Linux Kernel Cross Reference
sys/norma/ipc_ether.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,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 * HISTORY
28 * $Log: ipc_ether.c,v $
29 * Revision 2.9 93/05/15 19:33:40 mrt
30 * machparam.h -> machspl.h
31 *
32 * Revision 2.8 93/01/14 17:53:37 danner
33 * 64bit cleanup. Proper spl typing.
34 * [92/12/01 af]
35 *
36 * Revision 2.7 92/03/10 16:27:23 jsb
37 * Merged in norma branch changes as of NORMA_MK7.
38 * [92/03/09 12:48:43 jsb]
39 *
40 * Revision 2.5.3.3 92/01/21 21:51:03 jsb
41 * Use a field in fragment header to record true length, since udp
42 * length field can no longer be trusted due to ETHERMIN logic.
43 * [92/01/21 21:30:47 jsb]
44 *
45 * Don't send packets smaller than ETHERMIN.
46 * [92/01/21 19:35:34 jsb]
47 *
48 * Changed parameters to netipc_net_packet in preparation for saving
49 * packets that arrive before a new recv_netvec has been supplied.
50 * Added fragment information to debugging printfs.
51 * [92/01/17 18:36:34 jsb]
52 *
53 * Moved node_incarnation declaration from here to norma/ipc_net.c.
54 * [92/01/17 14:38:17 jsb]
55 *
56 * Fixed udp checksum bug. Drop packets whose length (as claimed by
57 * driver) differs from length as recorded in udp header.
58 * Set recv_netvec to zero before calling netipc_recv_intr
59 * so that any new incoming packets won't corrupt netvec.
60 * (This shouldn't happen anyway because interrupts will be blocked.)
61 * Panic if fragment send completions occur out-of-order.
62 * (This also shouldn't happen.)
63 * [92/01/16 22:05:57 jsb]
64 *
65 * Replaced small, incomprehensible, and incorrect loop in netipc_send
66 * responsible for copying from fragments into vector elements with
67 * comprehensible and correct code. De-linted.
68 * [92/01/14 21:45:52 jsb]
69 *
70 * Moved c_netipc_frag_drop* count definitions here from norma/ipc_net.c.
71 * [92/01/10 20:37:07 jsb]
72 *
73 * Revision 2.5.3.2 92/01/09 18:45:07 jsb
74 * Added netipc_node_valid.
75 * From durriya@ri.osf.org: added norma_ether_boot_info.
76 * [92/01/08 16:45:45 jsb]
77 *
78 * Added comment about reentrancy above netipc_send.
79 * Replaced small, incomprehensible, and incorrect loop in netipc_send
80 * responsible for copying from vector elements into fragments with
81 * comprehensible and correct code.
82 * [92/01/08 10:02:33 jsb]
83 *
84 * Moved ntohl, etc. here from norma/ipc_net.c.
85 * [92/01/04 22:11:30 jsb]
86 *
87 * Revision 2.5.3.1 92/01/03 16:37:12 jsb
88 * Made node_incarnation be unsigned long, and changed its name.
89 * (It used to be node_instance. I also changed the log message below.)
90 * [91/12/29 10:10:30 jsb]
91 *
92 * Added code to set node_incarnation, using config info if available;
93 * node_incarnation will allow norma ipc to cope with node crashes.
94 * Fixed code that waits for nd table info to arrive from network;
95 * it now detects and processes the first packet that arrives.
96 * Split nd_reply routine into nd_reply, which calls either
97 * nd_table_reply or nd_config_reply based on magic number.
98 * Removed magic number checking code from the latter two routines,
99 * and removed call to nd_config from netipc_net_packet.
100 * [91/12/27 17:15:00 jsb]
101 *
102 * Corrected log. Fixed merge error in nd_reply.
103 * [91/12/24 14:34:55 jsb]
104 *
105 * Revision 2.5 91/12/14 14:32:44 jsb
106 * Picked up bootconfig code from sjs@osf.org.
107 *
108 * Revision 2.4 91/11/14 16:52:20 rpd
109 * Added XLAS/XLA/XSA macros to solve alignment problems.
110 * [91/11/00 jsb]
111 *
112 * Revision 2.3 91/08/28 11:15:54 jsb
113 * Generalized netipc_swap_device code.
114 * [91/08/16 14:30:15 jsb]
115 *
116 * Added fields to support nrp (node table resolution protocol),
117 * allowing removal of hardwired table of node/ip/ether addresses.
118 * [91/08/15 08:58:04 jsb]
119 *
120 * Revision 2.2 91/08/03 18:19:14 jsb
121 * Restructured to work with completely unmodified ethernet driver.
122 * Added code to automatically find a usable ethernet device.
123 * Removed NODE_BY_SUBNET case. Perform initialization earlier.
124 * [91/08/02 14:21:08 jsb]
125 *
126 * Use IO_LOANED technology.
127 * [91/07/27 22:56:42 jsb]
128 *
129 * Added fragmentation.
130 * [91/07/27 18:54:37 jsb]
131 *
132 * First checkin.
133 * [91/07/24 23:38:03 jsb]
134 *
135 */
136 /*
137 * File: norma/ipc_ether.c
138 * Author: Joseph S. Barrera III
139 * Date: 1991
140 *
141 * Functions for NORMA_IPC over ethernet.
142 */
143
144 #include <machine/machspl.h>
145 #include <vm/vm_kern.h>
146 #include <vm/vm_page.h>
147 #include <mach/vm_param.h>
148 #include <mach/port.h>
149 #include <mach/message.h>
150 #include <kern/assert.h>
151 #include <kern/host.h>
152 #include <kern/sched_prim.h>
153 #include <kern/ipc_sched.h>
154 #include <kern/ipc_kobject.h>
155 #include <kern/zalloc.h>
156 #include <ipc/ipc_mqueue.h>
157 #include <ipc/ipc_thread.h>
158 #include <ipc/ipc_kmsg.h>
159 #include <ipc/ipc_port.h>
160 #include <ipc/ipc_pset.h>
161 #include <ipc/ipc_space.h>
162 #include <ipc/ipc_marequest.h>
163 #include <device/io_req.h>
164 #include <device/if_hdr.h>
165 #include <device/net_io.h>
166 #include <device/net_status.h>
167 #include <norma/ipc_net.h>
168 #include <norma/ipc_ether.h>
169
170 #define MAXFRAG 8
171 #define FHP_OVERHEAD sizeof(struct netipc_fragment_header)
172
173 typedef struct netipc_fragment_header *netipc_fragment_header_t;
174
175 struct netipc_fragment_header {
176 unsigned short f_offset;
177 unsigned char f_id;
178 unsigned char f_last;
179 unsigned long f_length;
180 };
181
182 int NoiseEther = 0;
183
184 struct io_req netipc_ior[MAXFRAG];
185 char netipc_ether_buf[MAXFRAG * ETHERMTU];
186
187 struct netvec *recv_netvec = 0;
188 int recv_netvec_count;
189
190 /*
191 * Quick-and-dirty macros for getting around alignment problems
192 * XSA/XLA -> Transfer Short/Long in an Alignment friendly way.
193 * XLAS is statement form of XLA which includes a temporary declaration,
194 * allowing second parameter to be an arbitary (aligned) expression.
195 */
196 #define XSA(a,b,o) (*(o+(short *)&(a)) = *(o+(short *)&(b)))
197 #define XLA(a,b) (XSA((a),(b),0),XSA((a),(b),1))
198 #define XLAS(a,b) {long _l = *(long *)(b); XLA((a),_l);}
199
200 #define BCOPY(src, dst, len) bcopy((char *)(src), (char *)(dst), (int)(len))
201 #define HTONS(s) htons((unsigned short)(s))
202 #define NTOHS(s) ntohs((unsigned short)(s))
203 #define HTONL(l) htonl((unsigned long)(l))
204 #define NTOHL(l) ntohl((unsigned long)(l))
205
206 /*
207 * Definitions for ntohl, etc. for architectures that don't otherwise
208 * provide them.
209 */
210 #if mips || lint
211 unsigned long
212 ntohl(x)
213 register unsigned long x;
214 {
215 return (((x & 0x000000ff) << 24)|
216 ((x & 0x0000ff00) << 8)|
217 ((x & 0x00ff0000) >> 8)|
218 ((x & 0xff000000) >> 24));
219 }
220
221 unsigned long
222 htonl(x)
223 register unsigned long x;
224 {
225 return (((x & 0x000000ff) << 24)|
226 ((x & 0x0000ff00) << 8)|
227 ((x & 0x00ff0000) >> 8)|
228 ((x & 0xff000000) >> 24));
229 }
230
231 unsigned short
232 ntohs(x)
233 register unsigned short x;
234 {
235 return (((x & 0x00ff) << 8)|
236 ((x & 0xff00) >> 8));
237 }
238
239 unsigned short
240 htons(x)
241 register unsigned short x;
242 {
243 return (((x & 0x00ff) << 8)|
244 ((x & 0xff00) >> 8));
245 }
246 #endif
247
248 /*
249 * Netipc_recv_fragment_ip_src is 0 if no current frag.
250 * If we get packet from ip_src which is not a completing frag,
251 * we should ask for missing frags. This is therefor a sender timeout driven
252 * mechanism, tied in with higher level timeouts.
253 *
254 * We should have several pages for reassembly. This should be tied in with
255 * the ability to subsitute buffers of same size or smaller.
256 * E.g. substituting small kmsgs for pages.
257 *
258 * For now, if a frag assembly is in progress, we drop everything
259 * else aimed at us. An immediate refinement would be to have one
260 * page reserved for reassembly, leaving another for recording nacks.
261 *
262 * Maybe upper level should be allowed to provide several receive buffers
263 * and we find best fit. That would seem to minimize our knowledge
264 * of what buffers are all about.
265 */
266
267 int netipc_recv_fragment_ip_src;
268 int netipc_recv_fragment_f_id;
269
270 int netipc_ip_id = 1;
271
272 #define NODE_INVALID -1
273 int _node_self = NODE_INVALID;
274 extern unsigned long node_incarnation;
275 struct node_addr *node_self_addr;
276
277 #define MAX_NODE_TABLE_SIZE 256
278
279 struct node_addr node_table[MAX_NODE_TABLE_SIZE];
280 int node_table_size = 0;
281
282 #define NODE_ID(index) (index)
283
284 struct node_addr *
285 node_addr_by_node(node)
286 unsigned long node;
287 {
288 return &node_table[node];
289 }
290
291 boolean_t
292 netipc_node_valid(node)
293 unsigned long node;
294 {
295 return (node < node_table_size);
296 }
297
298 node_self()
299 {
300 if (_node_self == NODE_INVALID) {
301 printf("... premature node_self() call\n");
302 netipc_network_init();
303 }
304 if (_node_self == NODE_INVALID) {
305 panic("node_self: I don't know what node I am\n");
306 }
307 return _node_self;
308 }
309
310 #if 1
311 /* debugging */
312 node_id(node_ether_addr)
313 unsigned short *node_ether_addr;
314 {
315 int i;
316
317 if (node_table_size == 0) {
318 panic("bad node_table_size\n");
319 }
320 for (i = 0; i < node_table_size; i++) {
321 if (node_ether_addr[0] == node_table[i].node_ether_addr[0] &&
322 node_ether_addr[1] == node_table[i].node_ether_addr[1] &&
323 node_ether_addr[2] == node_table[i].node_ether_addr[2]) {
324 return NODE_ID(i);
325 }
326 }
327 return NODE_INVALID;
328 }
329
330 node_ip_id(ip_addr)
331 unsigned long ip_addr;
332 {
333 int i;
334
335 if (node_table_size == 0) {
336 panic("bad node_table_size\n");
337 }
338 for (i = 0; i < node_table_size; i++) {
339 if (node_table[i].node_ip_addr == ip_addr) {
340 return NODE_ID(i);
341 }
342 }
343 return NODE_INVALID;
344 }
345 #endif
346
347 struct dev_ops *netipc_device;
348 int netipc_device_unit = 0;
349
350 #define is_nulldev(func) ((func)==nodev || (func)==nulldev)
351
352 unsigned long eaddr_l[2]; /* XXX */
353
354 char netipc_boot_config[BOOT_CONFIG_SIZE]; /* boot configuration block */
355
356 char *
357 norma_ether_boot_info()
358 {
359 return netipc_boot_config;
360 }
361
362 netipc_network_init()
363 {
364 unsigned long count;
365 int unit = netipc_device_unit; /* XXX */
366 struct dev_ops *dp;
367
368 /*
369 * Return if already initialized.
370 */
371 if (netipc_device) {
372 return;
373 }
374
375 /*
376 * Look for a network device.
377 */
378 dev_search(dp) {
379 if (is_nulldev(dp->d_write) ||
380 is_nulldev(dp->d_getstat) ||
381 ! is_nulldev(dp->d_read)) {
382 continue;
383 }
384 if ((*dp->d_open)(unit, 0) != 0) {
385 /*
386 * Open failed. Try another one.
387 */
388 continue;
389 }
390 if ((*dp->d_getstat)(unit, NET_ADDRESS, eaddr_l, &count) == 0){
391 /*
392 * Success!
393 */
394 netipc_device = dp;
395 printf("netipc: using %s%d\n",
396 netipc_device->d_name,
397 netipc_device_unit);
398 break;
399 }
400 /*
401 * Opened the wrong device. Close and try another one.
402 */
403 if (dp->d_close) {
404 (*dp->d_close)(unit);
405 }
406 }
407
408 if (! netipc_device) {
409 panic("netipc_network_init: could not find network device\n");
410 }
411
412 /*
413 * Set address and calculate node number.
414 */
415 eaddr_l[0] = NTOHL(eaddr_l[0]);
416 eaddr_l[1] = NTOHL(eaddr_l[1]);
417 printf("netipc: waiting for node table\n");
418 for (;;) {
419 spl_t s;
420
421 nd_request();
422 s = splsched();
423 if (node_self_addr) {
424 splx(s);
425 break;
426 }
427 assert_wait((vm_offset_t) &node_self_addr, TRUE);
428 thread_set_timeout(5 * hz);
429 thread_block((void (*)()) 0);
430 if (node_self_addr) {
431 splx(s);
432 break;
433 }
434 splx(s);
435 }
436 printf("netipc: node %d internet 0x%x ethernet %s\n",
437 node_self(),
438 NTOHL(node_self_addr->node_ip_addr),
439 ether_sprintf(node_self_addr->node_ether_addr));
440 if (netipc_boot_config[0] != '\0') {
441 printf("netipc: boot config:\n%s", netipc_boot_config);
442 }
443 printf("netipc: incarnation %d\n", node_incarnation);
444 }
445
446 boolean_t nd_request_in_progress = FALSE;
447
448 request_ior_done()
449 {
450 nd_request_in_progress = FALSE;
451 }
452
453 nd_request()
454 {
455 netipc_ether_header_t ehp;
456 netipc_udpip_header_t uhp;
457 struct nd_request *ndrq;
458 int i, total_length, udp_length;
459 unsigned long checksum;
460
461 if (nd_request_in_progress) {
462 return;
463 }
464 nd_request_in_progress = TRUE;
465
466 ehp = (netipc_ether_header_t) netipc_ether_buf;
467 uhp = (netipc_udpip_header_t) (((char *) ehp) + EHLEN);
468 ndrq = (struct nd_request *) (uhp + 1);
469
470 udp_length = UDP_OVERHEAD + sizeof(struct nd_request);
471 total_length = EHLEN + IP_OVERHEAD + udp_length;
472
473 netipc_ior[0].io_count = total_length;
474 netipc_ior[0].io_data = (char *) ehp;
475 netipc_ior[0].io_done = request_ior_done;
476 netipc_ior[0].io_op = IO_LOANED;
477
478 ehp->e_ptype = HTONS(ETHERTYPE_IP);
479 BCOPY(eaddr_l, ehp->e_src, 6);
480 ehp->e_dest[0] = 0xffff;
481 ehp->e_dest[1] = 0xffff;
482 ehp->e_dest[2] = 0xffff;
483
484 uhp->ip_version = IPVERSION;
485 uhp->ip_header_length = 5;
486 uhp->ip_type_of_service = 0;
487 uhp->ip_total_length = HTONS(udp_length + IP_OVERHEAD);
488 uhp->ip_id = HTONS(netipc_ip_id++);
489 uhp->ip_fragment_offset = HTONS(0);
490 uhp->ip_time_to_live = 0xff;
491 uhp->ip_protocol = UDP_PROTOCOL;
492 uhp->ip_checksum = 0;
493
494 #if 0
495 uhp->ip_src = 0;
496 uhp->ip_dst = HTONL(0xffffffff);
497 #else
498 {
499 int ip_src = 0;
500 int ip_dst = HTONL(0xffffffff);
501
502 XLA(uhp->ip_src, ip_src);
503 XLA(uhp->ip_dst, ip_dst);
504 }
505 #endif
506
507 for (checksum = i = 0; i < 10; i++) {
508 checksum += ((unsigned short *) uhp)[i];
509 }
510 checksum = (checksum & 0xffff) + (checksum >> 16);
511 checksum = (checksum & 0xffff) + (checksum >> 16);
512 uhp->ip_checksum = (~checksum & 0xffff);
513
514 uhp->udp_source_port = HTONS(IPPORT_NDREPLY);
515 uhp->udp_dest_port = HTONS(IPPORT_NDREQUEST);
516 uhp->udp_length = HTONS(udp_length);
517 uhp->udp_checksum = 0;
518
519 #if 0
520 ndrq->ndrq_magic = HTONL(NDRQ_MAGIC);
521 ndrq->ndrq_start = HTONS(0);
522 #else
523 {
524 int ndrq_magic = HTONL(NDRQ_MAGIC);
525 int ndrq_start = HTONS(0);
526
527 XLA(ndrq->ndrq_magic, ndrq_magic);
528 XLA(ndrq->ndrq_start, ndrq_start);
529 }
530 #endif
531 BCOPY(eaddr_l, ndrq->ndrq_eaddr, 6);
532
533 /*
534 * Send the packet.
535 */
536 (*netipc_device->d_write)(netipc_device_unit, &netipc_ior[0]);
537 }
538
539 nd_config_parse_incarnation(s)
540 char *s;
541 {
542 char *incarnation_env = "INCARNATION=";
543 unsigned long incarnation = 0;
544
545 if (strncmp(s, incarnation_env, strlen(incarnation_env))) {
546 return;
547 }
548 for (s += strlen(incarnation_env); *s >= '' && *s <= '9'; s++) {
549 incarnation = 10 * incarnation + (*s - '');
550 }
551 if (incarnation != 0) {
552 node_incarnation = incarnation;
553 }
554 }
555
556 nd_config_reply(uhp, count)
557 netipc_udpip_header_t uhp;
558 unsigned long count;
559 {
560 struct nd_config *ndrc = (struct nd_config *) (uhp + 1);
561 int bootconfigsize, bootmsgcnt, bootoffset;
562
563 bootmsgcnt = NTOHS(ndrc->ndrc_msg_size);
564 bootoffset = NTOHS(ndrc->ndrc_offset);
565 if ((bootoffset + bootmsgcnt) > sizeof(netipc_boot_config)) {
566 printf("nd_config: Too much config data!");
567 return;
568 }
569 bootconfigsize = NTOHS(ndrc->ndrc_config_size);
570 BCOPY(ndrc->ndrc_boot_data, &netipc_boot_config[bootoffset],
571 bootmsgcnt);
572 netipc_boot_config[bootconfigsize] = '\0';
573 if (bootoffset + bootmsgcnt >= bootconfigsize) {
574 nd_config_parse_incarnation(netipc_boot_config);
575 }
576 }
577
578 nd_table_reply(uhp, count)
579 netipc_udpip_header_t uhp;
580 unsigned long count;
581 {
582 struct nd_reply *ndrp = (struct nd_reply *) (uhp + 1);
583 int i;
584
585 _node_self = NTOHS(ndrp->ndrp_node_self);
586 node_table_size = NTOHS(ndrp->ndrp_table_size);
587 if (node_table_size < 0 || node_table_size > MAX_NODE_TABLE_SIZE) {
588 panic("nd_table_reply: bad table size %d\n", node_table_size);
589 }
590 for (i = 0; i < node_table_size; i++) {
591 struct nd *nd = &ndrp->ndrp_table[i];
592 struct node_addr *na = &node_table[i];
593
594 if (! nd->nd_valid) {
595 node_table[i].node_ip_addr = 0;
596 bzero(node_table[i].node_ether_addr, 6);
597 continue;
598 } else {
599 na->node_ip_addr = nd->nd_iaddr;
600 BCOPY(nd->nd_eaddr, na->node_ether_addr, 6);
601 }
602 }
603 node_self_addr = &node_table[_node_self];
604 thread_wakeup((vm_offset_t) &node_self_addr);
605 }
606
607 nd_reply(uhp, count)
608 netipc_udpip_header_t uhp;
609 unsigned long count;
610 {
611 struct nd_reply *ndrp = (struct nd_reply *) (uhp + 1);
612
613 if (node_self_addr) {
614 /*
615 * Table and config info already initialized.
616 */
617 return;
618 }
619 if (ndrp->ndrp_magic == HTONL(NDRP_MAGIC)) {
620 nd_table_reply(uhp, count);
621 } else if (ndrp->ndrp_magic == HTONL(NDRC_MAGIC)) {
622 nd_config_reply(uhp, count);
623 } else {
624 printf("nd_reply: bad magic\n");
625 }
626 }
627
628 char netipc_swap_device[3] = "hd";
629 int netipc_swap_node_1 = 1;
630 int netipc_swap_node_2 = 1;
631 int netipc_swap_xor = 1;
632
633 char *
634 dev_forward_name(name, namebuf, namelen)
635 char *name;
636 char *namebuf;
637 int namelen;
638 {
639 if (netipc_swap_node_1 == netipc_swap_node_2) {
640 return name;
641 }
642 if (name[0] == netipc_swap_device[0] &&
643 name[1] == netipc_swap_device[1]) {
644 namebuf[0] = '<';
645 if (node_self() == netipc_swap_node_1) {
646 namebuf[1] = '' + netipc_swap_node_2;
647 } else {
648 namebuf[1] = '' + netipc_swap_node_1;
649 }
650 namebuf[2] = '>';
651 namebuf[3] = name[0]; /* e.g. 'h' */
652 namebuf[4] = name[1]; /* e.g. 'd' */
653 namebuf[5] = name[2] ^ netipc_swap_xor; /* major */
654 namebuf[6] = name[3]; /* minor */
655 namebuf[7] = '\0';
656 printf("[ %s -> %s ]\n", name, namebuf);
657 return namebuf;
658 }
659 return name;
660 }
661
662 int c_netipc_frag_drop0 = 0;
663 int c_netipc_frag_drop1 = 0;
664 int c_netipc_frag_drop2 = 0;
665 int c_netipc_frag_drop3 = 0;
666 int c_netipc_frag_drop4 = 0;
667
668 netipc_net_packet(kmsg, count)
669 ipc_kmsg_t kmsg;
670 unsigned long count;
671 {
672 register struct netipc_ether_header *ehp;
673 register struct netipc_udpip_header *uhp;
674
675 ehp = (netipc_ether_header_t) &net_kmsg(kmsg)->header[0];
676 uhp = (netipc_udpip_header_t) &net_kmsg(kmsg)->packet[sizeof(char *)];
677 count = count - sizeof(struct packet_header);
678
679 /*
680 * Only consider udp packets
681 */
682 if (ehp->e_ptype != HTONS(ETHERTYPE_IP) ||
683 /* node_ip_id(uhp->ip_src) == -1 || ignore broadcasts? */
684 uhp->ip_protocol != UDP_PROTOCOL) {
685 return FALSE;
686 }
687
688 /*
689 * Ignore packets whose length (as claimed by driver) differs from
690 * length as recorded in udp header.
691 */
692 if (count != NTOHS(uhp->udp_length) + IP_OVERHEAD) {
693 c_netipc_frag_drop0++;
694 return FALSE;
695 }
696
697 /*
698 * Steal the kmsg iff we recognize the udp port.
699 */
700 if (uhp->udp_dest_port == NETIPC_UDPPORT) {
701 if (NoiseEther) {
702 netipc_fragment_header_t fhp =
703 (netipc_fragment_header_t) (uhp + 1);
704 printf("R s=%d.%x, d=%d.%x f=%04d/%d/%d len=%d\n",
705 node_ip_id(uhp->ip_src),
706 NTOHL(uhp->ip_src),
707 node_ip_id(uhp->ip_dst),
708 NTOHL(uhp->ip_dst),
709 NTOHS(fhp->f_offset),
710 fhp->f_id,
711 fhp->f_last,
712 NTOHS(uhp->udp_length) + EHLEN + IP_OVERHEAD);
713 }
714 netipc_recv_copy(kmsg);
715 return TRUE;
716 } else if (NTOHS(uhp->udp_dest_port) == IPPORT_NDREPLY) {
717 nd_reply(uhp, count);
718 net_kmsg_put(kmsg);
719 return TRUE;
720 } else {
721 return FALSE;
722 }
723 }
724
725 netipc_recv_copy(kmsg)
726 ipc_kmsg_t kmsg;
727 {
728 netipc_udpip_header_t uhp;
729 netipc_fragment_header_t fhp;
730 char *buf;
731 unsigned long count;
732 int i, offset;
733
734 uhp = (netipc_udpip_header_t) &net_kmsg(kmsg)->packet[sizeof(char *)];
735 fhp = (netipc_fragment_header_t) (uhp + 1);
736 count = NTOHL(fhp->f_length);
737 buf = (char *) (fhp + 1);
738 offset = NTOHS(fhp->f_offset);
739
740 if (recv_netvec == 0) {
741 c_netipc_frag_drop1++;
742 net_kmsg_put(kmsg);
743 return;
744 }
745
746 if (netipc_recv_fragment_ip_src) {
747 if (netipc_recv_fragment_ip_src != uhp->ip_src) {
748 /*
749 * Someone has a frag in progress. Drop this packet.
750 */
751 c_netipc_frag_drop2++;
752 net_kmsg_put(kmsg);
753 return;
754 }
755 if (fhp->f_last == 0) {
756 /*
757 * New nonfragged message replaces old frag.
758 * XXX clearly suboptimal, see discussion above
759 * XXX assumes only one fragged message in transit
760 */
761 c_netipc_frag_drop3++;
762 netipc_recv_fragment_ip_src = 0;
763 }
764 }
765
766 /*
767 * First check for non fragmented packets.
768 */
769 if (fhp->f_last == 0) {
770 for (i = 0; i < recv_netvec_count; i++) {
771 if (count <= recv_netvec[i].size) {
772 BCOPY(buf, recv_netvec[i].addr, count);
773 recv_netvec[i].size = count;
774 for (i++; i < recv_netvec_count; i++) {
775 recv_netvec[i].size = 0;
776 }
777 break;
778 }
779 BCOPY(buf, recv_netvec[i].addr, recv_netvec[i].size);
780 buf += recv_netvec[i].size;
781 count -= recv_netvec[i].size;
782 }
783 recv_netvec = 0;
784 netipc_recv_intr();
785 net_kmsg_put(kmsg);
786 return;
787 }
788
789 /*
790 * The packet was fragmented.
791 * If this is the first frag of a message, set up frag info.
792 */
793 if (netipc_recv_fragment_ip_src == 0) {
794 netipc_recv_fragment_ip_src = uhp->ip_src;
795 netipc_recv_fragment_f_id = 0;
796 }
797
798 /*
799 * If we missed a frag, drop the whole thing!
800 */
801 if (netipc_recv_fragment_f_id != fhp->f_id) {
802 netipc_recv_fragment_ip_src = 0;
803 c_netipc_frag_drop4++;
804 net_kmsg_put(kmsg);
805 return;
806 }
807
808 /*
809 * Skip to the right offset in the receive buffer,
810 * and copy it into the the appropriate vectors.
811 *
812 * First skip past all elements that we won't touch.
813 */
814 for (i = 0; offset >= recv_netvec[i].size; i++) {
815 offset -= recv_netvec[i].size;
816 }
817 assert(offset >= 0);
818 assert(i < recv_netvec_count);
819
820 /*
821 * A non-zero offset will affect at most one element.
822 * Deal with it now so that we can stop worrying about offset.
823 */
824 if (offset > 0) {
825 /*
826 * If this is the last element, and the last fragment,
827 * then set size.
828 */
829 if (count <= recv_netvec[i].size - offset) {
830 BCOPY(buf, recv_netvec[i].addr + offset, count);
831 if (fhp->f_id == fhp->f_last) {
832 recv_netvec[i].size = count + offset;
833 }
834 goto did_copy;
835 }
836 /*
837 * This is not the last element. Copy and continue.
838 */
839 BCOPY(buf, recv_netvec[i].addr + offset,
840 recv_netvec[i].size - offset);
841 buf += recv_netvec[i].size - offset;
842 count -= recv_netvec[i].size - offset;
843 i++;
844 }
845
846 /*
847 * Fill all the middle elements.
848 */
849 for (; count > recv_netvec[i].size; i++) {
850 BCOPY(buf, recv_netvec[i].addr, recv_netvec[i].size);
851 buf += recv_netvec[i].size;
852 count -= recv_netvec[i].size;
853 }
854
855 /*
856 * Fill the last element; if it's the last fragment, set size.
857 */
858 BCOPY(buf, recv_netvec[i].addr, count);
859 if (fhp->f_id == fhp->f_last) {
860 recv_netvec[i].size = count;
861 }
862
863 did_copy:
864 /*
865 * If this is the last frag, hand it up, after setting the
866 * size for all remaining elements to zero.
867 * Otherwise, simply note that we received this frag.
868 */
869 if (fhp->f_id == fhp->f_last) {
870 for (i++; i < recv_netvec_count; i++) {
871 recv_netvec[i].size = 0;
872 }
873 netipc_recv_fragment_ip_src = 0;
874 recv_netvec = 0;
875 netipc_recv_intr();
876 } else {
877 netipc_recv_fragment_f_id++;
878 }
879 net_kmsg_put(kmsg);
880 }
881
882 netipc_recv(vec, count)
883 register struct netvec *vec;
884 int count;
885 {
886 recv_netvec = vec;
887 recv_netvec_count = count;
888 }
889
890 /* (net as in usable, not as in network) */
891 #define NETMTU (ETHERMTU - EHLEN - IP_OVERHEAD - UDP_OVERHEAD - FHP_OVERHEAD)
892
893 int netipc_fragment_last_uncompleted = 0;
894
895 netipc_ether_send_complete(ior)
896 register io_req_t ior;
897 {
898 register netipc_udpip_header_t uhp;
899 register netipc_fragment_header_t fhp;
900
901 uhp = (netipc_udpip_header_t) (((char *) ior->io_data) + EHLEN);
902 fhp = (netipc_fragment_header_t) (uhp + 1);
903 if (fhp->f_id != netipc_fragment_last_uncompleted) {
904 panic("netipc_ether_send_complete: f_id %d != %d!\n",
905 fhp->f_id, netipc_fragment_last_uncompleted);
906 }
907 netipc_fragment_last_uncompleted++;
908 if (fhp->f_id == fhp->f_last) {
909 netipc_send_intr();
910 }
911 }
912
913 /*
914 * This routine is not reentrant and is not expected to be.
915 * norma/ipc_net.c uses netipc_sending to prevent multiple entrances.
916 * If we have a reentrant form, we can upcall on netipc_send_intr
917 * to indicate that we can accept another netipc_send call.
918 */
919 netipc_send(remote, vec, count)
920 unsigned long remote;
921 register struct netvec *vec;
922 unsigned int count;
923 {
924 int i, f, frag_count, data_len;
925 extern struct node_addr *node_self_addr, *node_addr_by_node();
926 struct node_addr *node_dest_addr;
927 char *buf;
928 netipc_ether_header_t ehp;
929 netipc_udpip_header_t uhp;
930 netipc_fragment_header_t fhp;
931 int total_length, udp_length;
932
933 /*
934 * Silently drop packets destined for invalid nodes.
935 * Sender should previously have called netipc_node_valid.
936 * XXX
937 * We should have sender check our return value.
938 * If this were done, we wouldn't have to call netipc_send_intr.
939 */
940 if (! netipc_node_valid(remote)) {
941 netipc_send_intr();
942 return;
943 }
944
945 /*
946 * Compute total size and number of fragments
947 */
948 data_len = 0;
949 for (i = 0; i < count; i++) {
950 data_len += vec[i].size;
951 }
952 frag_count = (data_len + NETMTU - 1) / NETMTU;
953 if (frag_count > MAXFRAG) {
954 panic("netipc_send: size %d: too many (%d) fragments\n",
955 data_len, frag_count);
956 }
957
958 /*
959 * Get destination address
960 */
961 node_dest_addr = node_addr_by_node(remote);
962
963 /*
964 * Construct headers for each fragment; copy data into a contiguous
965 * chunk (yuck). Use loaned ior's.
966 */
967 netipc_fragment_last_uncompleted = 0;
968 for (f = 0; f < frag_count; f++) {
969 ehp = (netipc_ether_header_t) &netipc_ether_buf[f * ETHERMTU];
970 uhp = (netipc_udpip_header_t) (((char *) ehp) + EHLEN);
971 fhp = (netipc_fragment_header_t) (uhp + 1);
972
973 if (data_len > NETMTU) {
974 udp_length = ETHERMTU - EHLEN - IP_OVERHEAD;
975 fhp->f_length = HTONL(udp_length - UDP_OVERHEAD -
976 FHP_OVERHEAD);
977 total_length = ETHERMTU;
978 data_len -= NETMTU;
979 } else {
980 udp_length = UDP_OVERHEAD + FHP_OVERHEAD + data_len;
981 fhp->f_length = HTONL(data_len);
982 if (udp_length < ETHERMIN - IP_OVERHEAD) {
983 udp_length = ETHERMIN - IP_OVERHEAD;
984 }
985 total_length = EHLEN + IP_OVERHEAD + udp_length;
986 data_len = 0;
987 }
988
989 netipc_ior[f].io_count = total_length;
990 netipc_ior[f].io_data = (char *) ehp;
991 netipc_ior[f].io_done = netipc_ether_send_complete;
992 netipc_ior[f].io_op = IO_LOANED;
993
994 ehp->e_ptype = HTONS(ETHERTYPE_IP);
995 ehp->e_src[0] = node_self_addr->node_ether_addr[0];
996 ehp->e_src[1] = node_self_addr->node_ether_addr[1];
997 ehp->e_src[2] = node_self_addr->node_ether_addr[2];
998 ehp->e_dest[0] = node_dest_addr->node_ether_addr[0];
999 ehp->e_dest[1] = node_dest_addr->node_ether_addr[1];
1000 ehp->e_dest[2] = node_dest_addr->node_ether_addr[2];
1001
1002 uhp->ip_version = IPVERSION;
1003 uhp->ip_header_length = 5;
1004 uhp->ip_type_of_service = 0;
1005 uhp->ip_total_length = HTONS(total_length);
1006 uhp->ip_id = HTONS(netipc_ip_id++);
1007 uhp->ip_fragment_offset = HTONS(0);
1008 uhp->ip_time_to_live = 0xff;
1009 uhp->ip_protocol = UDP_PROTOCOL;
1010 uhp->ip_checksum = -1;
1011 #if 0
1012 uhp->ip_src = node_self_addr->node_ip_addr;
1013 uhp->ip_dst = node_dest_addr->node_ip_addr;
1014 #else
1015 XLA(uhp->ip_src, node_self_addr->node_ip_addr);
1016 XLA(uhp->ip_dst, node_dest_addr->node_ip_addr);
1017 #endif
1018 uhp->udp_source_port = HTONS(NETIPC_UDPPORT);
1019 uhp->udp_dest_port = HTONS(NETIPC_UDPPORT);
1020 uhp->udp_length = HTONS(udp_length);
1021 uhp->udp_checksum = -1;
1022
1023 buf = (char *) (fhp + 1);
1024
1025 if (frag_count == 0) {
1026 fhp->f_offset = 0;
1027 fhp->f_id = 0;
1028 fhp->f_last = 0;
1029
1030 /*
1031 * Everything will fit into one fragment,
1032 * so just copy everything into it.
1033 */
1034 for (i = 0; i < count; i++) {
1035 BCOPY(vec[i].addr, buf, vec[i].size);
1036 buf += vec[i].size;
1037 }
1038 } else {
1039 unsigned short offset = f * NETMTU;
1040 unsigned short remain = NETMTU;
1041
1042 fhp->f_offset = HTONS(offset);
1043 fhp->f_id = f;
1044 fhp->f_last = frag_count - 1;
1045
1046 /*
1047 * First skip all elements which have
1048 * already been completely sent.
1049 */
1050 for (i = 0; offset >= vec[i].size; i++) {
1051 assert(i < count);
1052 offset -= vec[i].size;
1053 }
1054 assert((long) offset >= 0);
1055 assert((long) offset < vec[i].size);
1056
1057 /*
1058 * Offset is now the offset into the current
1059 * element at which we begin copying.
1060 * If this element is all we need, then copy
1061 * as much of this element as will fit.
1062 */
1063 assert(i < count);
1064 if (vec[i].size - offset >= remain) {
1065 BCOPY(vec[i].addr + offset, buf, remain);
1066 goto done_copying_into_fragments;
1067 }
1068
1069 /*
1070 * Copy all of this element, starting at offset.
1071 * Move to the next element.
1072 */
1073 BCOPY(vec[i].addr + offset, buf, vec[i].size - offset);
1074 buf += (vec[i].size - offset);
1075 remain -= (vec[i].size - offset);
1076 i++;
1077
1078 /*
1079 * For each remaining element: if it's all we need,
1080 * then copy all that will fit and stop. Otherwise,
1081 * copy all of it, and continue.
1082 */
1083 for (; i < count; i++) {
1084 if (vec[i].size >= remain) {
1085 BCOPY(vec[i].addr, buf, remain);
1086 break;
1087 }
1088 BCOPY(vec[i].addr, buf, vec[i].size);
1089 buf += vec[i].size;
1090 remain -= vec[i].size;
1091 }
1092 done_copying_into_fragments:
1093 ;
1094 }
1095
1096 if (NoiseEther) {
1097 printf("S s=%d.%x, d=%d.%x f=%04d/%d/%d len=%d\n",
1098 node_ip_id(uhp->ip_src),
1099 NTOHL(node_self_addr->node_ip_addr),
1100 node_ip_id(uhp->ip_dst),
1101 NTOHL(node_dest_addr->node_ip_addr),
1102 NTOHS(fhp->f_offset),
1103 fhp->f_id,
1104 fhp->f_last,
1105 udp_length + EHLEN + IP_OVERHEAD);
1106 }
1107
1108 /*
1109 * Send the packet.
1110 */
1111 (*netipc_device->d_write)(netipc_device_unit, &netipc_ior[f]);
1112 }
1113 }
Cache object: c4f9e51c973d4d5dd8b1496dcf5d4348
|