source: trunk/minix/servers/inet/generic/udp.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 36.0 KB
Line 
1/*
2udp.c
3
4Copyright 1995 Philip Homburg
5*/
6
7#include "inet.h"
8#include "type.h"
9
10#include "assert.h"
11#include "buf.h"
12#include "clock.h"
13#include "icmp_lib.h"
14#include "io.h"
15#include "ip.h"
16#include "sr.h"
17#include "udp.h"
18#include "udp_int.h"
19
20THIS_FILE
21
22FORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));
23FORWARD void udp_buffree ARGS(( int priority ));
24#ifdef BUF_CONSISTENCY_CHECK
25FORWARD void udp_bufcheck ARGS(( void ));
26#endif
27FORWARD void udp_main ARGS(( udp_port_t *udp_port ));
28FORWARD int udp_select ARGS(( int fd, unsigned operations ));
29FORWARD acc_t *udp_get_data ARGS(( int fd, size_t offset, size_t count,
30 int for_ioctl ));
31FORWARD int udp_put_data ARGS(( int fd, size_t offset, acc_t *data,
32 int for_ioctl ));
33FORWARD int udp_peek ARGS(( udp_fd_t * ));
34FORWARD int udp_sel_read ARGS(( udp_fd_t * ));
35FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));
36FORWARD void udp_ip_arrived ARGS(( int port, acc_t *pack, size_t pack_size ));
37FORWARD void reply_thr_put ARGS(( udp_fd_t *udp_fd, int reply,
38 int for_ioctl ));
39FORWARD void reply_thr_get ARGS(( udp_fd_t *udp_fd, int reply,
40 int for_ioctl ));
41FORWARD int udp_setopt ARGS(( udp_fd_t *udp_fd ));
42FORWARD udpport_t find_unused_port ARGS(( int fd ));
43FORWARD int is_unused_port ARGS(( Udpport_t port ));
44FORWARD int udp_packet2user ARGS(( udp_fd_t *udp_fd ));
45FORWARD void restart_write_fd ARGS(( udp_fd_t *udp_fd ));
46FORWARD u16_t pack_oneCsum ARGS(( acc_t *pack ));
47FORWARD void udp_rd_enqueue ARGS(( udp_fd_t *udp_fd, acc_t *pack,
48 clock_t exp_tim ));
49FORWARD void hash_fd ARGS(( udp_fd_t *udp_fd ));
50FORWARD void unhash_fd ARGS(( udp_fd_t *udp_fd ));
51
52PUBLIC udp_port_t *udp_port_table;
53PUBLIC udp_fd_t udp_fd_table[UDP_FD_NR];
54
55PUBLIC void udp_prep()
56{
57 udp_port_table= alloc(udp_conf_nr * sizeof(udp_port_table[0]));
58}
59
60PUBLIC void udp_init()
61{
62 udp_fd_t *udp_fd;
63 udp_port_t *udp_port;
64 int i, j, ifno;
65
66 assert (BUF_S >= sizeof(struct nwio_ipopt));
67 assert (BUF_S >= sizeof(struct nwio_ipconf));
68 assert (BUF_S >= sizeof(struct nwio_udpopt));
69 assert (BUF_S >= sizeof(struct udp_io_hdr));
70 assert (UDP_HDR_SIZE == sizeof(udp_hdr_t));
71 assert (UDP_IO_HDR_SIZE == sizeof(udp_io_hdr_t));
72
73 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
74 {
75 udp_fd->uf_flags= UFF_EMPTY;
76 udp_fd->uf_rdbuf_head= NULL;
77 }
78
79#ifndef BUF_CONSISTENCY_CHECK
80 bf_logon(udp_buffree);
81#else
82 bf_logon(udp_buffree, udp_bufcheck);
83#endif
84
85 for (i= 0, udp_port= udp_port_table; i<udp_conf_nr; i++, udp_port++)
86 {
87 udp_port->up_ipdev= udp_conf[i].uc_port;
88
89 udp_port->up_flags= UPF_EMPTY;
90 udp_port->up_state= UPS_EMPTY;
91 udp_port->up_next_fd= udp_fd_table;
92 udp_port->up_write_fd= NULL;
93 udp_port->up_wr_pack= NULL;
94 udp_port->up_port_any= NULL;
95 for (j= 0; j<UDP_PORT_HASH_NR; j++)
96 udp_port->up_port_hash[j]= NULL;
97
98 ifno= ip_conf[udp_port->up_ipdev].ic_ifno;
99 sr_add_minor(if2minor(ifno, UDP_DEV_OFF),
100 i, udp_open, udp_close, udp_read,
101 udp_write, udp_ioctl, udp_cancel, udp_select);
102
103 udp_main(udp_port);
104 }
105}
106
107PUBLIC int udp_open (port, srfd, get_userdata, put_userdata, put_pkt,
108 select_res)
109int port;
110int srfd;
111get_userdata_t get_userdata;
112put_userdata_t put_userdata;
113put_pkt_t put_pkt;
114select_res_t select_res;
115{
116 int i;
117 udp_fd_t *udp_fd;
118
119 for (i= 0; i<UDP_FD_NR && (udp_fd_table[i].uf_flags & UFF_INUSE);
120 i++);
121
122 if (i>= UDP_FD_NR)
123 {
124 DBLOCK(1, printf("out of fds\n"));
125 return EAGAIN;
126 }
127
128 udp_fd= &udp_fd_table[i];
129
130 udp_fd->uf_flags= UFF_INUSE;
131 udp_fd->uf_port= &udp_port_table[port];
132 udp_fd->uf_srfd= srfd;
133 udp_fd->uf_udpopt.nwuo_flags= UDP_DEF_OPT;
134 udp_fd->uf_get_userdata= get_userdata;
135 udp_fd->uf_put_userdata= put_userdata;
136 udp_fd->uf_select_res= select_res;
137 assert(udp_fd->uf_rdbuf_head == NULL);
138 udp_fd->uf_port_next= NULL;
139
140 return i;
141
142}
143
144PUBLIC int udp_ioctl (fd, req)
145int fd;
146ioreq_t req;
147{
148 udp_fd_t *udp_fd;
149 udp_port_t *udp_port;
150 nwio_udpopt_t *udp_opt;
151 acc_t *opt_acc;
152 int result;
153
154 udp_fd= &udp_fd_table[fd];
155
156assert (udp_fd->uf_flags & UFF_INUSE);
157
158 udp_port= udp_fd->uf_port;
159 udp_fd->uf_flags |= UFF_IOCTL_IP;
160 udp_fd->uf_ioreq= req;
161
162 if (udp_port->up_state != UPS_MAIN)
163 return NW_SUSPEND;
164
165 switch(req)
166 {
167 case NWIOSUDPOPT:
168 result= udp_setopt(udp_fd);
169 break;
170 case NWIOGUDPOPT:
171 opt_acc= bf_memreq(sizeof(*udp_opt));
172assert (opt_acc->acc_length == sizeof(*udp_opt));
173 udp_opt= (nwio_udpopt_t *)ptr2acc_data(opt_acc);
174
175 *udp_opt= udp_fd->uf_udpopt;
176 udp_opt->nwuo_locaddr= udp_fd->uf_port->up_ipaddr;
177 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, 0, opt_acc,
178 TRUE);
179 if (result == NW_OK)
180 reply_thr_put(udp_fd, NW_OK, TRUE);
181 break;
182 case NWIOUDPPEEK:
183 result= udp_peek(udp_fd);
184 break;
185 default:
186 reply_thr_get(udp_fd, EBADIOCTL, TRUE);
187 result= NW_OK;
188 break;
189 }
190 if (result != NW_SUSPEND)
191 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
192 return result;
193}
194
195PUBLIC int udp_read (fd, count)
196int fd;
197size_t count;
198{
199 udp_fd_t *udp_fd;
200 acc_t *tmp_acc, *next_acc;
201
202 udp_fd= &udp_fd_table[fd];
203 if (!(udp_fd->uf_flags & UFF_OPTSET))
204 {
205 reply_thr_put(udp_fd, EBADMODE, FALSE);
206 return NW_OK;
207 }
208
209 udp_fd->uf_rd_count= count;
210
211 if (udp_fd->uf_rdbuf_head)
212 {
213 if (get_time() <= udp_fd->uf_exp_tim)
214 return udp_packet2user (udp_fd);
215 tmp_acc= udp_fd->uf_rdbuf_head;
216 while (tmp_acc)
217 {
218 next_acc= tmp_acc->acc_ext_link;
219 bf_afree(tmp_acc);
220 tmp_acc= next_acc;
221 }
222 udp_fd->uf_rdbuf_head= NULL;
223 }
224 udp_fd->uf_flags |= UFF_READ_IP;
225 return NW_SUSPEND;
226}
227
228PRIVATE void udp_main(udp_port)
229udp_port_t *udp_port;
230{
231 udp_fd_t *udp_fd;
232 int result, i;
233
234 switch (udp_port->up_state)
235 {
236 case UPS_EMPTY:
237 udp_port->up_state= UPS_SETPROTO;
238
239 udp_port->up_ipfd= ip_open(udp_port->up_ipdev,
240 udp_port->up_ipdev, udp_get_data, udp_put_data,
241 udp_ip_arrived, 0 /* no select_res */);
242 if (udp_port->up_ipfd < 0)
243 {
244 udp_port->up_state= UPS_ERROR;
245 DBLOCK(1, printf("%s, %d: unable to open ip port\n",
246 __FILE__, __LINE__));
247 return;
248 }
249
250 result= ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT);
251 if (result == NW_SUSPEND)
252 udp_port->up_flags |= UPF_SUSPEND;
253 if (result<0)
254 {
255 return;
256 }
257 if (udp_port->up_state != UPS_GETCONF)
258 return;
259 /* drops through */
260 case UPS_GETCONF:
261 udp_port->up_flags &= ~UPF_SUSPEND;
262
263 result= ip_ioctl(udp_port->up_ipfd, NWIOGIPCONF);
264 if (result == NW_SUSPEND)
265 udp_port->up_flags |= UPF_SUSPEND;
266 if (result<0)
267 {
268 return;
269 }
270 if (udp_port->up_state != UPS_MAIN)
271 return;
272 /* drops through */
273 case UPS_MAIN:
274 udp_port->up_flags &= ~UPF_SUSPEND;
275
276 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
277 {
278 if (!(udp_fd->uf_flags & UFF_INUSE))
279 continue;
280 if (udp_fd->uf_port != udp_port)
281 continue;
282 if (udp_fd->uf_flags & UFF_IOCTL_IP)
283 udp_ioctl(i, udp_fd->uf_ioreq);
284 }
285 read_ip_packets(udp_port);
286 return;
287 default:
288 DBLOCK(1, printf("udp_port_table[%d].up_state= %d\n",
289 udp_port->up_ipdev, udp_port->up_state));
290 ip_panic(( "unknown state" ));
291 break;
292 }
293}
294
295PRIVATE int udp_select(fd, operations)
296int fd;
297unsigned operations;
298{
299 int i;
300 unsigned resops;
301 udp_fd_t *udp_fd;
302
303 udp_fd= &udp_fd_table[fd];
304 assert (udp_fd->uf_flags & UFF_INUSE);
305
306 resops= 0;
307
308 if (operations & SR_SELECT_READ)
309 {
310 if (udp_sel_read(udp_fd))
311 resops |= SR_SELECT_READ;
312 else if (!(operations & SR_SELECT_POLL))
313 udp_fd->uf_flags |= UFF_SEL_READ;
314 }
315 if (operations & SR_SELECT_WRITE)
316 {
317 /* Should handle special case when the interface is down */
318 resops |= SR_SELECT_WRITE;
319 }
320 if (operations & SR_SELECT_EXCEPTION)
321 {
322 printf("udp_select: not implemented for exceptions\n");
323 }
324 return resops;
325}
326
327PRIVATE acc_t *udp_get_data (port, offset, count, for_ioctl)
328int port;
329size_t offset;
330size_t count;
331int for_ioctl;
332{
333 udp_port_t *udp_port;
334 udp_fd_t *udp_fd;
335 int result;
336
337 udp_port= &udp_port_table[port];
338
339 switch(udp_port->up_state)
340 {
341 case UPS_SETPROTO:
342assert (for_ioctl);
343 if (!count)
344 {
345 result= (int)offset;
346 if (result<0)
347 {
348 udp_port->up_state= UPS_ERROR;
349 break;
350 }
351 udp_port->up_state= UPS_GETCONF;
352 if (udp_port->up_flags & UPF_SUSPEND)
353 udp_main(udp_port);
354 return NULL;
355 }
356 else
357 {
358 struct nwio_ipopt *ipopt;
359 acc_t *acc;
360
361assert (!offset);
362assert (count == sizeof(*ipopt));
363
364 acc= bf_memreq(sizeof(*ipopt));
365 ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
366 ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC |
367 NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC |
368 NWIO_HDR_O_ANY | NWIO_RWDATALL;
369 ipopt->nwio_proto= IPPROTO_UDP;
370 return acc;
371 }
372 case UPS_MAIN:
373assert (!for_ioctl);
374assert (udp_port->up_flags & UPF_WRITE_IP);
375 if (!count)
376 {
377 result= (int)offset;
378assert (udp_port->up_wr_pack);
379 bf_afree(udp_port->up_wr_pack);
380 udp_port->up_wr_pack= 0;
381 if (udp_port->up_flags & UPF_WRITE_SP)
382 {
383 if (udp_port->up_write_fd)
384 {
385 udp_fd= udp_port->up_write_fd;
386 udp_port->up_write_fd= NULL;
387 udp_fd->uf_flags &= ~UFF_WRITE_IP;
388 reply_thr_get(udp_fd, result, FALSE);
389 }
390 udp_port->up_flags &= ~(UPF_WRITE_SP |
391 UPF_WRITE_IP);
392 if (udp_port->up_flags & UPF_MORE2WRITE)
393 {
394 udp_restart_write_port(udp_port);
395 }
396 }
397 else
398 udp_port->up_flags &= ~UPF_WRITE_IP;
399 }
400 else
401 {
402 return bf_cut (udp_port->up_wr_pack, offset, count);
403 }
404 break;
405 default:
406 printf("udp_get_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
407 port, offset, count, udp_port->up_state);
408 break;
409 }
410 return NULL;
411}
412
413PRIVATE int udp_put_data (fd, offset, data, for_ioctl)
414int fd;
415size_t offset;
416acc_t *data;
417int for_ioctl;
418{
419 udp_port_t *udp_port;
420 int result;
421
422 udp_port= &udp_port_table[fd];
423
424 switch (udp_port->up_state)
425 {
426 case UPS_GETCONF:
427 if (!data)
428 {
429 result= (int)offset;
430 if (result<0)
431 {
432 udp_port->up_state= UPS_ERROR;
433 return NW_OK;
434 }
435 udp_port->up_state= UPS_MAIN;
436 if (udp_port->up_flags & UPF_SUSPEND)
437 udp_main(udp_port);
438 }
439 else
440 {
441 struct nwio_ipconf *ipconf;
442
443 data= bf_packIffLess(data, sizeof(*ipconf));
444 ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
445assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
446 udp_port->up_ipaddr= ipconf->nwic_ipaddr;
447 bf_afree(data);
448 }
449 break;
450 case UPS_MAIN:
451 assert(0);
452
453 assert (udp_port->up_flags & UPF_READ_IP);
454 if (!data)
455 {
456 result= (int)offset;
457 compare (result, >=, 0);
458 if (udp_port->up_flags & UPF_READ_SP)
459 {
460 udp_port->up_flags &= ~(UPF_READ_SP|
461 UPF_READ_IP);
462 read_ip_packets(udp_port);
463 }
464 else
465 udp_port->up_flags &= ~UPF_READ_IP;
466 }
467 else
468 {
469assert (!offset); /* This isn't a valid assertion but ip sends only
470 * whole datagrams up */
471 udp_ip_arrived(fd, data, bf_bufsize(data));
472 }
473 break;
474 default:
475 ip_panic((
476 "udp_put_data(%d, 0x%x, %p) called but up_state= 0x%x\n",
477 fd, offset, data, udp_port->up_state ));
478 }
479 return NW_OK;
480}
481
482PRIVATE int udp_setopt(udp_fd)
483udp_fd_t *udp_fd;
484{
485 udp_fd_t *fd_ptr;
486 nwio_udpopt_t oldopt, newopt;
487 acc_t *data;
488 unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags,
489 all_flags, flags;
490 unsigned long new_flags;
491 int i;
492
493 data= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
494 sizeof(nwio_udpopt_t), TRUE);
495
496 if (!data)
497 return EFAULT;
498
499 data= bf_packIffLess(data, sizeof(nwio_udpopt_t));
500assert (data->acc_length == sizeof(nwio_udpopt_t));
501
502 newopt= *(nwio_udpopt_t *)ptr2acc_data(data);
503 bf_afree(data);
504 oldopt= udp_fd->uf_udpopt;
505
506 old_en_flags= oldopt.nwuo_flags & 0xffff;
507 old_di_flags= (oldopt.nwuo_flags >> 16) & 0xffff;
508
509 new_en_flags= newopt.nwuo_flags & 0xffff;
510 new_di_flags= (newopt.nwuo_flags >> 16) & 0xffff;
511
512 if (new_en_flags & new_di_flags)
513 {
514 DBLOCK(1, printf("returning EBADMODE\n"));
515
516 reply_thr_get(udp_fd, EBADMODE, TRUE);
517 return NW_OK;
518 }
519
520 /* NWUO_ACC_MASK */
521 if (new_di_flags & NWUO_ACC_MASK)
522 {
523 DBLOCK(1, printf("returning EBADMODE\n"));
524
525 reply_thr_get(udp_fd, EBADMODE, TRUE);
526 return NW_OK;
527 /* access modes can't be disabled */
528 }
529
530 if (!(new_en_flags & NWUO_ACC_MASK))
531 new_en_flags |= (old_en_flags & NWUO_ACC_MASK);
532
533 /* NWUO_LOCPORT_MASK */
534 if (new_di_flags & NWUO_LOCPORT_MASK)
535 {
536 DBLOCK(1, printf("returning EBADMODE\n"));
537
538 reply_thr_get(udp_fd, EBADMODE, TRUE);
539 return NW_OK;
540 /* the loc ports can't be disabled */
541 }
542 if (!(new_en_flags & NWUO_LOCPORT_MASK))
543 {
544 new_en_flags |= (old_en_flags & NWUO_LOCPORT_MASK);
545 newopt.nwuo_locport= oldopt.nwuo_locport;
546 }
547 else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL)
548 {
549 newopt.nwuo_locport= find_unused_port(udp_fd-udp_fd_table);
550 }
551 else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
552 {
553 if (!newopt.nwuo_locport)
554 {
555 DBLOCK(1, printf("returning EBADMODE\n"));
556
557 reply_thr_get(udp_fd, EBADMODE, TRUE);
558 return NW_OK;
559 }
560 }
561
562 /* NWUO_LOCADDR_MASK */
563 if (!((new_en_flags | new_di_flags) & NWUO_LOCADDR_MASK))
564 {
565 new_en_flags |= (old_en_flags & NWUO_LOCADDR_MASK);
566 new_di_flags |= (old_di_flags & NWUO_LOCADDR_MASK);
567 }
568
569 /* NWUO_BROAD_MASK */
570 if (!((new_en_flags | new_di_flags) & NWUO_BROAD_MASK))
571 {
572 new_en_flags |= (old_en_flags & NWUO_BROAD_MASK);
573 new_di_flags |= (old_di_flags & NWUO_BROAD_MASK);
574 }
575
576 /* NWUO_REMPORT_MASK */
577 if (!((new_en_flags | new_di_flags) & NWUO_REMPORT_MASK))
578 {
579 new_en_flags |= (old_en_flags & NWUO_REMPORT_MASK);
580 new_di_flags |= (old_di_flags & NWUO_REMPORT_MASK);
581 newopt.nwuo_remport= oldopt.nwuo_remport;
582 }
583
584 /* NWUO_REMADDR_MASK */
585 if (!((new_en_flags | new_di_flags) & NWUO_REMADDR_MASK))
586 {
587 new_en_flags |= (old_en_flags & NWUO_REMADDR_MASK);
588 new_di_flags |= (old_di_flags & NWUO_REMADDR_MASK);
589 newopt.nwuo_remaddr= oldopt.nwuo_remaddr;
590 }
591
592 /* NWUO_RW_MASK */
593 if (!((new_en_flags | new_di_flags) & NWUO_RW_MASK))
594 {
595 new_en_flags |= (old_en_flags & NWUO_RW_MASK);
596 new_di_flags |= (old_di_flags & NWUO_RW_MASK);
597 }
598
599 /* NWUO_IPOPT_MASK */
600 if (!((new_en_flags | new_di_flags) & NWUO_IPOPT_MASK))
601 {
602 new_en_flags |= (old_en_flags & NWUO_IPOPT_MASK);
603 new_di_flags |= (old_di_flags & NWUO_IPOPT_MASK);
604 }
605
606 new_flags= ((unsigned long)new_di_flags << 16) | new_en_flags;
607 if ((new_flags & NWUO_RWDATONLY) &&
608 ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_ANY ||
609 (new_flags & (NWUO_RP_ANY|NWUO_RA_ANY|NWUO_EN_IPOPT))))
610 {
611 DBLOCK(1, printf("returning EBADMODE\n"));
612
613 reply_thr_get(udp_fd, EBADMODE, TRUE);
614 return NW_OK;
615 }
616
617 /* Check the access modes */
618 if ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL ||
619 (new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
620 {
621 for (i= 0, fd_ptr= udp_fd_table; i<UDP_FD_NR; i++, fd_ptr++)
622 {
623 if (fd_ptr == udp_fd)
624 continue;
625 if (!(fd_ptr->uf_flags & UFF_INUSE))
626 continue;
627 if (fd_ptr->uf_port != udp_fd->uf_port)
628 continue;
629 flags= fd_ptr->uf_udpopt.nwuo_flags;
630 if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_SEL &&
631 (flags & NWUO_LOCPORT_MASK) != NWUO_LP_SET)
632 continue;
633 if (fd_ptr->uf_udpopt.nwuo_locport !=
634 newopt.nwuo_locport)
635 {
636 continue;
637 }
638 if ((flags & NWUO_ACC_MASK) !=
639 (new_flags & NWUO_ACC_MASK))
640 {
641 DBLOCK(1, printf(
642 "address inuse: new fd= %d, old_fd= %d, port= %u\n",
643 udp_fd-udp_fd_table,
644 fd_ptr-udp_fd_table,
645 newopt.nwuo_locport));
646
647 reply_thr_get(udp_fd, EADDRINUSE, TRUE);
648 return NW_OK;
649 }
650 }
651 }
652
653 if (udp_fd->uf_flags & UFF_OPTSET)
654 unhash_fd(udp_fd);
655
656 newopt.nwuo_flags= new_flags;
657 udp_fd->uf_udpopt= newopt;
658
659 all_flags= new_en_flags | new_di_flags;
660 if ((all_flags & NWUO_ACC_MASK) && (all_flags & NWUO_LOCPORT_MASK) &&
661 (all_flags & NWUO_LOCADDR_MASK) &&
662 (all_flags & NWUO_BROAD_MASK) &&
663 (all_flags & NWUO_REMPORT_MASK) &&
664 (all_flags & NWUO_REMADDR_MASK) &&
665 (all_flags & NWUO_RW_MASK) &&
666 (all_flags & NWUO_IPOPT_MASK))
667 udp_fd->uf_flags |= UFF_OPTSET;
668 else
669 {
670 udp_fd->uf_flags &= ~UFF_OPTSET;
671 }
672
673 if (udp_fd->uf_flags & UFF_OPTSET)
674 hash_fd(udp_fd);
675
676 reply_thr_get(udp_fd, NW_OK, TRUE);
677 return NW_OK;
678}
679
680PRIVATE udpport_t find_unused_port(fd)
681int fd;
682{
683 udpport_t port, nw_port;
684
685 for (port= 0x8000+fd; port < 0xffff-UDP_FD_NR; port+= UDP_FD_NR)
686 {
687 nw_port= htons(port);
688 if (is_unused_port(nw_port))
689 return nw_port;
690 }
691 for (port= 0x8000; port < 0xffff; port++)
692 {
693 nw_port= htons(port);
694 if (is_unused_port(nw_port))
695 return nw_port;
696 }
697 ip_panic(( "unable to find unused port (shouldn't occur)" ));
698 return 0;
699}
700
701/*
702reply_thr_put
703*/
704
705PRIVATE void reply_thr_put(udp_fd, reply, for_ioctl)
706udp_fd_t *udp_fd;
707int reply;
708int for_ioctl;
709{
710 int result;
711
712 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, reply,
713 (acc_t *)0, for_ioctl);
714 assert(result == NW_OK);
715}
716
717/*
718reply_thr_get
719*/
720
721PRIVATE void reply_thr_get(udp_fd, reply, for_ioctl)
722udp_fd_t *udp_fd;
723int reply;
724int for_ioctl;
725{
726 acc_t *result;
727 result= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, reply,
728 (size_t)0, for_ioctl);
729 assert (!result);
730}
731
732PRIVATE int is_unused_port(port)
733udpport_t port;
734{
735 int i;
736 udp_fd_t *udp_fd;
737
738 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++,
739 udp_fd++)
740 {
741 if (!(udp_fd->uf_flags & UFF_OPTSET))
742 continue;
743 if (udp_fd->uf_udpopt.nwuo_locport == port)
744 return FALSE;
745 }
746 return TRUE;
747}
748
749PRIVATE void read_ip_packets(udp_port)
750udp_port_t *udp_port;
751{
752 int result;
753
754 do
755 {
756 udp_port->up_flags |= UPF_READ_IP;
757 result= ip_read(udp_port->up_ipfd, UDP_MAX_DATAGRAM);
758 if (result == NW_SUSPEND)
759 {
760 udp_port->up_flags |= UPF_READ_SP;
761 return;
762 }
763assert(result == NW_OK);
764 udp_port->up_flags &= ~UPF_READ_IP;
765 } while(!(udp_port->up_flags & UPF_READ_IP));
766}
767
768
769PRIVATE int udp_peek (udp_fd)
770udp_fd_t *udp_fd;
771{
772 acc_t *pack, *tmp_acc, *next_acc;
773 int result;
774
775 if (!(udp_fd->uf_flags & UFF_OPTSET))
776 {
777 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
778 reply_thr_put(udp_fd, EBADMODE, TRUE);
779 return NW_OK;
780 }
781
782 if (udp_fd->uf_rdbuf_head)
783 {
784 if (get_time() <= udp_fd->uf_exp_tim)
785 {
786 pack= bf_cut(udp_fd->uf_rdbuf_head, 0,
787 sizeof(udp_io_hdr_t));
788 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
789 (size_t)0, pack, TRUE);
790
791 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
792 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
793 result, (acc_t *)0, TRUE);
794 assert (result == 0);
795 return result;
796 }
797 tmp_acc= udp_fd->uf_rdbuf_head;
798 while (tmp_acc)
799 {
800 next_acc= tmp_acc->acc_ext_link;
801 bf_afree(tmp_acc);
802 tmp_acc= next_acc;
803 }
804 udp_fd->uf_rdbuf_head= NULL;
805 }
806 udp_fd->uf_flags |= UFF_PEEK_IP;
807 return NW_SUSPEND;
808}
809
810PRIVATE int udp_sel_read (udp_fd)
811udp_fd_t *udp_fd;
812{
813 acc_t *pack, *tmp_acc, *next_acc;
814 int result;
815
816 if (!(udp_fd->uf_flags & UFF_OPTSET))
817 return 1; /* Read will not block */
818
819 if (udp_fd->uf_rdbuf_head)
820 {
821 if (get_time() <= udp_fd->uf_exp_tim)
822 return 1;
823
824 tmp_acc= udp_fd->uf_rdbuf_head;
825 while (tmp_acc)
826 {
827 next_acc= tmp_acc->acc_ext_link;
828 bf_afree(tmp_acc);
829 tmp_acc= next_acc;
830 }
831 udp_fd->uf_rdbuf_head= NULL;
832 }
833 return 0;
834}
835
836PRIVATE int udp_packet2user (udp_fd)
837udp_fd_t *udp_fd;
838{
839 acc_t *pack, *tmp_pack;
840 udp_io_hdr_t *hdr;
841 int result, hdr_len;
842 size_t size, transf_size;
843
844 pack= udp_fd->uf_rdbuf_head;
845 udp_fd->uf_rdbuf_head= pack->acc_ext_link;
846
847 size= bf_bufsize (pack);
848
849 if (udp_fd->uf_udpopt.nwuo_flags & NWUO_RWDATONLY)
850 {
851
852 pack= bf_packIffLess (pack, UDP_IO_HDR_SIZE);
853 assert (pack->acc_length >= UDP_IO_HDR_SIZE);
854
855 hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
856#if CONF_UDP_IO_NW_BYTE_ORDER
857 hdr_len= UDP_IO_HDR_SIZE+NTOHS(hdr->uih_ip_opt_len);
858#else
859 hdr_len= UDP_IO_HDR_SIZE+hdr->uih_ip_opt_len;
860#endif
861
862 assert (size>= hdr_len);
863 size -= hdr_len;
864 tmp_pack= bf_cut(pack, hdr_len, size);
865 bf_afree(pack);
866 pack= tmp_pack;
867 }
868
869 if (size>udp_fd->uf_rd_count)
870 {
871 tmp_pack= bf_cut (pack, 0, udp_fd->uf_rd_count);
872 bf_afree(pack);
873 pack= tmp_pack;
874 transf_size= udp_fd->uf_rd_count;
875 }
876 else
877 transf_size= size;
878
879 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
880 (size_t)0, pack, FALSE);
881
882 if (result >= 0)
883 if (size > transf_size)
884 result= EPACKSIZE;
885 else
886 result= transf_size;
887
888 udp_fd->uf_flags &= ~UFF_READ_IP;
889 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, result,
890 (acc_t *)0, FALSE);
891 assert (result == 0);
892
893 return result;
894}
895
896PRIVATE void udp_ip_arrived(port, pack, pack_size)
897int port;
898acc_t *pack;
899size_t pack_size;
900{
901 udp_port_t *udp_port;
902 udp_fd_t *udp_fd, *share_fd;
903 acc_t *ip_hdr_acc, *udp_acc, *ipopt_pack, *no_ipopt_pack, *tmp_acc;
904 ip_hdr_t *ip_hdr;
905 udp_hdr_t *udp_hdr;
906 udp_io_hdr_t *udp_io_hdr;
907 size_t ip_hdr_size, udp_size, data_size, opt_size;
908 ipaddr_t src_addr, dst_addr, ipaddr;
909 udpport_t src_port, dst_port;
910 u8_t u16[2];
911 u16_t chksum;
912 unsigned long dst_type, flags;
913 clock_t exp_tim;
914 int i, delivered, hash;
915
916 udp_port= &udp_port_table[port];
917
918 ip_hdr_acc= bf_cut(pack, 0, IP_MIN_HDR_SIZE);
919 ip_hdr_acc= bf_packIffLess(ip_hdr_acc, IP_MIN_HDR_SIZE);
920 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
921 ip_hdr_size= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
922 if (ip_hdr_size != IP_MIN_HDR_SIZE)
923 {
924 bf_afree(ip_hdr_acc);
925 ip_hdr_acc= bf_cut(pack, 0, ip_hdr_size);
926 ip_hdr_acc= bf_packIffLess(ip_hdr_acc, ip_hdr_size);
927 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
928 }
929
930 pack_size -= ip_hdr_size;
931 if (pack_size < UDP_HDR_SIZE)
932 {
933 if (pack_size == 0 && ip_hdr->ih_proto == 0)
934 {
935 /* IP layer reports new IP address */
936 ipaddr= ip_hdr->ih_src;
937 udp_port->up_ipaddr= ipaddr;
938 DBLOCK(1, printf("udp_ip_arrived: using address ");
939 writeIpAddr(ipaddr); printf("\n"));
940 }
941 else
942 DBLOCK(1, printf("packet too small\n"));
943
944 bf_afree(ip_hdr_acc);
945 bf_afree(pack);
946 return;
947 }
948
949 udp_acc= bf_delhead(pack, ip_hdr_size);
950 pack= NULL;
951
952
953 udp_acc= bf_packIffLess(udp_acc, UDP_HDR_SIZE);
954 udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_acc);
955 udp_size= ntohs(udp_hdr->uh_length);
956 if (udp_size > pack_size)
957 {
958 DBLOCK(1, printf("packet too large\n"));
959
960 bf_afree(ip_hdr_acc);
961 bf_afree(udp_acc);
962 return;
963 }
964
965 src_addr= ip_hdr->ih_src;
966 dst_addr= ip_hdr->ih_dst;
967
968 if (udp_hdr->uh_chksum)
969 {
970 u16[0]= 0;
971 u16[1]= ip_hdr->ih_proto;
972 chksum= pack_oneCsum(udp_acc);
973 chksum= oneC_sum(chksum, (u16_t *)&src_addr, sizeof(ipaddr_t));
974 chksum= oneC_sum(chksum, (u16_t *)&dst_addr, sizeof(ipaddr_t));
975 chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
976 chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length,
977 sizeof(udp_hdr->uh_length));
978 if (~chksum & 0xffff)
979 {
980 DBLOCK(1, printf("checksum error in udp packet\n");
981 printf("src ip_addr= ");
982 writeIpAddr(src_addr);
983 printf(" dst ip_addr= ");
984 writeIpAddr(dst_addr);
985 printf("\n");
986 printf("packet chksum= 0x%x, sum= 0x%x\n",
987 udp_hdr->uh_chksum, chksum));
988
989 bf_afree(ip_hdr_acc);
990 bf_afree(udp_acc);
991 return;
992 }
993 }
994
995 exp_tim= get_time() + UDP_READ_EXP_TIME;
996 src_port= udp_hdr->uh_src_port;
997 dst_port= udp_hdr->uh_dst_port;
998
999 /* Send an ICMP port unreachable if the packet could not be
1000 * delivered.
1001 */
1002 delivered= 0;
1003
1004 if (dst_addr == udp_port->up_ipaddr)
1005 dst_type= NWUO_EN_LOC;
1006 else
1007 {
1008 dst_type= NWUO_EN_BROAD;
1009
1010 /* Don't send ICMP error packets for broadcast packets */
1011 delivered= 1;
1012 }
1013
1014 DBLOCK(0x20, printf("udp: got packet from ");
1015 writeIpAddr(src_addr);
1016 printf(".%u to ", ntohs(src_port));
1017 writeIpAddr(dst_addr);
1018 printf(".%u\n", ntohs(dst_port)));
1019
1020 no_ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
1021 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(no_ipopt_pack);
1022 udp_io_hdr->uih_src_addr= src_addr;
1023 udp_io_hdr->uih_dst_addr= dst_addr;
1024 udp_io_hdr->uih_src_port= src_port;
1025 udp_io_hdr->uih_dst_port= dst_port;
1026 data_size = udp_size-UDP_HDR_SIZE;
1027#if CONF_UDP_IO_NW_BYTE_ORDER
1028 udp_io_hdr->uih_ip_opt_len= HTONS(0);
1029 udp_io_hdr->uih_data_len= htons(data_size);
1030#else
1031 udp_io_hdr->uih_ip_opt_len= 0;
1032 udp_io_hdr->uih_data_len= data_size;
1033#endif
1034 no_ipopt_pack->acc_next= bf_cut(udp_acc, UDP_HDR_SIZE, data_size);
1035
1036 if (ip_hdr_size == IP_MIN_HDR_SIZE)
1037 {
1038 ipopt_pack= no_ipopt_pack;
1039 ipopt_pack->acc_linkC++;
1040 }
1041 else
1042 {
1043 ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
1044 *(udp_io_hdr_t *)ptr2acc_data(ipopt_pack)= *udp_io_hdr;
1045 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(ipopt_pack);
1046 opt_size = ip_hdr_size-IP_MIN_HDR_SIZE;
1047#if CONF_UDP_IO_NW_BYTE_ORDER
1048 udp_io_hdr->uih_ip_opt_len= htons(opt_size);
1049#else
1050 udp_io_hdr->uih_ip_opt_len= opt_size;
1051#endif
1052 tmp_acc= bf_cut(ip_hdr_acc, (size_t)IP_MIN_HDR_SIZE, opt_size);
1053 assert(tmp_acc->acc_linkC == 1);
1054 assert(tmp_acc->acc_next == NULL);
1055 ipopt_pack->acc_next= tmp_acc;
1056
1057 tmp_acc->acc_next= no_ipopt_pack->acc_next;
1058 if (tmp_acc->acc_next)
1059 tmp_acc->acc_next->acc_linkC++;
1060 }
1061
1062 hash= dst_port;
1063 hash ^= (hash >> 8);
1064 hash &= (UDP_PORT_HASH_NR-1);
1065
1066 for (i= 0; i<2; i++)
1067 {
1068 share_fd= NULL;
1069
1070 udp_fd= (i == 0) ? udp_port->up_port_any :
1071 udp_port->up_port_hash[hash];
1072 for (; udp_fd; udp_fd= udp_fd->uf_port_next)
1073 {
1074 if (i && udp_fd->uf_udpopt.nwuo_locport != dst_port)
1075 continue;
1076
1077 assert(udp_fd->uf_flags & UFF_INUSE);
1078 assert(udp_fd->uf_flags & UFF_OPTSET);
1079
1080 if (udp_fd->uf_port != udp_port)
1081 continue;
1082
1083 flags= udp_fd->uf_udpopt.nwuo_flags;
1084 if (!(flags & dst_type))
1085 continue;
1086
1087 if ((flags & NWUO_RP_SET) &&
1088 udp_fd->uf_udpopt.nwuo_remport != src_port)
1089 {
1090 continue;
1091 }
1092
1093 if ((flags & NWUO_RA_SET) &&
1094 udp_fd->uf_udpopt.nwuo_remaddr != src_addr)
1095 {
1096 continue;
1097 }
1098
1099 if (i)
1100 {
1101 /* Packet is considdered to be delivered */
1102 delivered= 1;
1103 }
1104
1105 if ((flags & NWUO_ACC_MASK) == NWUO_SHARED &&
1106 (!share_fd || !udp_fd->uf_rdbuf_head))
1107 {
1108 share_fd= udp_fd;
1109 continue;
1110 }
1111
1112 if (flags & NWUO_EN_IPOPT)
1113 pack= ipopt_pack;
1114 else
1115 pack= no_ipopt_pack;
1116
1117 pack->acc_linkC++;
1118 udp_rd_enqueue(udp_fd, pack, exp_tim);
1119 if (udp_fd->uf_flags & UFF_READ_IP)
1120 udp_packet2user(udp_fd);
1121 }
1122
1123 if (share_fd)
1124 {
1125 flags= share_fd->uf_udpopt.nwuo_flags;
1126 if (flags & NWUO_EN_IPOPT)
1127 pack= ipopt_pack;
1128 else
1129 pack= no_ipopt_pack;
1130
1131 pack->acc_linkC++;
1132 udp_rd_enqueue(share_fd, pack, exp_tim);
1133 if (share_fd->uf_flags & UFF_READ_IP)
1134 udp_packet2user(share_fd);
1135 }
1136 }
1137
1138 if (ipopt_pack)
1139 bf_afree(ipopt_pack);
1140 if (no_ipopt_pack)
1141 bf_afree(no_ipopt_pack);
1142
1143 if (!delivered)
1144 {
1145 DBLOCK(0x2, printf("udp: could not deliver packet from ");
1146 writeIpAddr(src_addr);
1147 printf(".%u to ", ntohs(src_port));
1148 writeIpAddr(dst_addr);
1149 printf(".%u\n", ntohs(dst_port)));
1150
1151 pack= bf_append(ip_hdr_acc, udp_acc);
1152 ip_hdr_acc= NULL;
1153 udp_acc= NULL;
1154 icmp_snd_unreachable(udp_port->up_ipdev, pack,
1155 ICMP_PORT_UNRCH);
1156 return;
1157 }
1158
1159 assert (ip_hdr_acc);
1160 bf_afree(ip_hdr_acc);
1161 assert (udp_acc);
1162 bf_afree(udp_acc);
1163}
1164
1165PUBLIC void udp_close(fd)
1166int fd;
1167{
1168 udp_fd_t *udp_fd;
1169 acc_t *tmp_acc, *next_acc;
1170
1171 udp_fd= &udp_fd_table[fd];
1172
1173 assert (udp_fd->uf_flags & UFF_INUSE);
1174
1175 if (udp_fd->uf_flags & UFF_OPTSET)
1176 unhash_fd(udp_fd);
1177
1178 udp_fd->uf_flags= UFF_EMPTY;
1179 tmp_acc= udp_fd->uf_rdbuf_head;
1180 while (tmp_acc)
1181 {
1182 next_acc= tmp_acc->acc_ext_link;
1183 bf_afree(tmp_acc);
1184 tmp_acc= next_acc;
1185 }
1186 udp_fd->uf_rdbuf_head= NULL;
1187}
1188
1189PUBLIC int udp_write(fd, count)
1190int fd;
1191size_t count;
1192{
1193 udp_fd_t *udp_fd;
1194 udp_port_t *udp_port;
1195
1196 udp_fd= &udp_fd_table[fd];
1197 udp_port= udp_fd->uf_port;
1198
1199 if (!(udp_fd->uf_flags & UFF_OPTSET))
1200 {
1201 reply_thr_get (udp_fd, EBADMODE, FALSE);
1202 return NW_OK;
1203 }
1204
1205assert (!(udp_fd->uf_flags & UFF_WRITE_IP));
1206
1207 udp_fd->uf_wr_count= count;
1208
1209 udp_fd->uf_flags |= UFF_WRITE_IP;
1210
1211 restart_write_fd(udp_fd);
1212
1213 if (udp_fd->uf_flags & UFF_WRITE_IP)
1214 {
1215 DBLOCK(1, printf("replying NW_SUSPEND\n"));
1216
1217 return NW_SUSPEND;
1218 }
1219 else
1220 {
1221 return NW_OK;
1222 }
1223}
1224
1225PRIVATE void restart_write_fd(udp_fd)
1226udp_fd_t *udp_fd;
1227{
1228 udp_port_t *udp_port;
1229 acc_t *pack, *ip_hdr_pack, *udp_hdr_pack, *ip_opt_pack, *user_data;
1230 udp_hdr_t *udp_hdr;
1231 udp_io_hdr_t *udp_io_hdr;
1232 ip_hdr_t *ip_hdr;
1233 size_t ip_opt_size, user_data_size;
1234 unsigned long flags;
1235 u16_t chksum;
1236 u8_t u16[2];
1237 int result;
1238
1239 udp_port= udp_fd->uf_port;
1240
1241 if (udp_port->up_flags & UPF_WRITE_IP)
1242 {
1243 udp_port->up_flags |= UPF_MORE2WRITE;
1244 return;
1245 }
1246
1247assert (udp_fd->uf_flags & UFF_WRITE_IP);
1248 udp_fd->uf_flags &= ~UFF_WRITE_IP;
1249
1250assert (!udp_port->up_wr_pack);
1251
1252 pack= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
1253 udp_fd->uf_wr_count, FALSE);
1254 if (!pack)
1255 {
1256 udp_fd->uf_flags &= ~UFF_WRITE_IP;
1257 reply_thr_get (udp_fd, EFAULT, FALSE);
1258 return;
1259 }
1260
1261 flags= udp_fd->uf_udpopt.nwuo_flags;
1262
1263 ip_hdr_pack= bf_memreq(IP_MIN_HDR_SIZE);
1264 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_pack);
1265
1266 udp_hdr_pack= bf_memreq(UDP_HDR_SIZE);
1267 udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_hdr_pack);
1268
1269 if (flags & NWUO_RWDATALL)
1270 {
1271 pack= bf_packIffLess(pack, UDP_IO_HDR_SIZE);
1272 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
1273#if CONF_UDP_IO_NW_BYTE_ORDER
1274 ip_opt_size= ntohs(udp_io_hdr->uih_ip_opt_len);
1275#else
1276 ip_opt_size= udp_io_hdr->uih_ip_opt_len;
1277#endif
1278 if (UDP_IO_HDR_SIZE+ip_opt_size>udp_fd->uf_wr_count)
1279 {
1280 bf_afree(ip_hdr_pack);
1281 bf_afree(udp_hdr_pack);
1282 bf_afree(pack);
1283 reply_thr_get (udp_fd, EINVAL, FALSE);
1284 return;
1285 }
1286 if (ip_opt_size & 3)
1287 {
1288 bf_afree(ip_hdr_pack);
1289 bf_afree(udp_hdr_pack);
1290 bf_afree(pack);
1291 reply_thr_get (udp_fd, EFAULT, FALSE);
1292 return;
1293 }
1294 if (ip_opt_size)
1295 ip_opt_pack= bf_cut(pack, UDP_IO_HDR_SIZE, ip_opt_size);
1296 else
1297 ip_opt_pack= 0;
1298 user_data_size= udp_fd->uf_wr_count-UDP_IO_HDR_SIZE-
1299 ip_opt_size;
1300 user_data= bf_cut(pack, UDP_IO_HDR_SIZE+ip_opt_size,
1301 user_data_size);
1302 bf_afree(pack);
1303 }
1304 else
1305 {
1306 udp_io_hdr= 0;
1307 ip_opt_size= 0;
1308 user_data_size= udp_fd->uf_wr_count;
1309 ip_opt_pack= 0;
1310 user_data= pack;
1311 }
1312
1313 ip_hdr->ih_vers_ihl= (IP_MIN_HDR_SIZE+ip_opt_size) >> 2;
1314 ip_hdr->ih_tos= UDP_TOS;
1315 ip_hdr->ih_flags_fragoff= HTONS(UDP_IP_FLAGS);
1316 ip_hdr->ih_ttl= IP_DEF_TTL;
1317 ip_hdr->ih_proto= IPPROTO_UDP;
1318 if (flags & NWUO_RA_SET)
1319 {
1320 ip_hdr->ih_dst= udp_fd->uf_udpopt.nwuo_remaddr;
1321 }
1322 else
1323 {
1324assert (udp_io_hdr);
1325 ip_hdr->ih_dst= udp_io_hdr->uih_dst_addr;
1326 }
1327
1328 if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_ANY)
1329 udp_hdr->uh_src_port= udp_fd->uf_udpopt.nwuo_locport;
1330 else
1331 {
1332assert (udp_io_hdr);
1333 udp_hdr->uh_src_port= udp_io_hdr->uih_src_port;
1334 }
1335
1336 if (flags & NWUO_RP_SET)
1337 udp_hdr->uh_dst_port= udp_fd->uf_udpopt.nwuo_remport;
1338 else
1339 {
1340assert (udp_io_hdr);
1341 udp_hdr->uh_dst_port= udp_io_hdr->uih_dst_port;
1342 }
1343
1344 udp_hdr->uh_length= htons(UDP_HDR_SIZE+user_data_size);
1345 udp_hdr->uh_chksum= 0;
1346
1347 udp_hdr_pack->acc_next= user_data;
1348 chksum= pack_oneCsum(udp_hdr_pack);
1349 chksum= oneC_sum(chksum, (u16_t *)&udp_fd->uf_port->up_ipaddr,
1350 sizeof(ipaddr_t));
1351 chksum= oneC_sum(chksum, (u16_t *)&ip_hdr->ih_dst, sizeof(ipaddr_t));
1352 u16[0]= 0;
1353 u16[1]= IPPROTO_UDP;
1354 chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
1355 chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length, sizeof(u16_t));
1356 if (~chksum)
1357 chksum= ~chksum;
1358 udp_hdr->uh_chksum= chksum;
1359
1360 if (ip_opt_pack)
1361 {
1362 ip_opt_pack= bf_packIffLess(ip_opt_pack, ip_opt_size);
1363 ip_opt_pack->acc_next= udp_hdr_pack;
1364 udp_hdr_pack= ip_opt_pack;
1365 }
1366 ip_hdr_pack->acc_next= udp_hdr_pack;
1367
1368assert (!udp_port->up_wr_pack);
1369assert (!(udp_port->up_flags & UPF_WRITE_IP));
1370
1371 udp_port->up_wr_pack= ip_hdr_pack;
1372 udp_port->up_flags |= UPF_WRITE_IP;
1373 result= ip_write(udp_port->up_ipfd, bf_bufsize(ip_hdr_pack));
1374 if (result == NW_SUSPEND)
1375 {
1376 udp_port->up_flags |= UPF_WRITE_SP;
1377 udp_fd->uf_flags |= UFF_WRITE_IP;
1378 udp_port->up_write_fd= udp_fd;
1379 }
1380 else if (result<0)
1381 reply_thr_get(udp_fd, result, FALSE);
1382 else
1383 reply_thr_get (udp_fd, udp_fd->uf_wr_count, FALSE);
1384}
1385
1386PRIVATE u16_t pack_oneCsum(pack)
1387acc_t *pack;
1388{
1389 u16_t prev;
1390 int odd_byte;
1391 char *data_ptr;
1392 int length;
1393 char byte_buf[2];
1394
1395 assert (pack);
1396
1397 prev= 0;
1398
1399 odd_byte= FALSE;
1400 for (; pack; pack= pack->acc_next)
1401 {
1402
1403 data_ptr= ptr2acc_data(pack);
1404 length= pack->acc_length;
1405
1406 if (!length)
1407 continue;
1408 if (odd_byte)
1409 {
1410 byte_buf[1]= *data_ptr;
1411 prev= oneC_sum(prev, (u16_t *)byte_buf, 2);
1412 data_ptr++;
1413 length--;
1414 odd_byte= FALSE;
1415 }
1416 if (length & 1)
1417 {
1418 odd_byte= TRUE;
1419 length--;
1420 byte_buf[0]= data_ptr[length];
1421 }
1422 if (!length)
1423 continue;
1424 prev= oneC_sum (prev, (u16_t *)data_ptr, length);
1425 }
1426 if (odd_byte)
1427 {
1428 byte_buf[1]= 0;
1429 prev= oneC_sum (prev, (u16_t *)byte_buf, 1);
1430 }
1431 return prev;
1432}
1433
1434PRIVATE void udp_restart_write_port(udp_port )
1435udp_port_t *udp_port;
1436{
1437 udp_fd_t *udp_fd;
1438 int i;
1439
1440assert (!udp_port->up_wr_pack);
1441assert (!(udp_port->up_flags & (UPF_WRITE_IP|UPF_WRITE_SP)));
1442
1443 while (udp_port->up_flags & UPF_MORE2WRITE)
1444 {
1445 udp_port->up_flags &= ~UPF_MORE2WRITE;
1446
1447 for (i= 0, udp_fd= udp_port->up_next_fd; i<UDP_FD_NR;
1448 i++, udp_fd++)
1449 {
1450 if (udp_fd == &udp_fd_table[UDP_FD_NR])
1451 udp_fd= udp_fd_table;
1452
1453 if (!(udp_fd->uf_flags & UFF_INUSE))
1454 continue;
1455 if (!(udp_fd->uf_flags & UFF_WRITE_IP))
1456 continue;
1457 if (udp_fd->uf_port != udp_port)
1458 continue;
1459 restart_write_fd(udp_fd);
1460 if (udp_port->up_flags & UPF_WRITE_IP)
1461 {
1462 udp_port->up_next_fd= udp_fd+1;
1463 udp_port->up_flags |= UPF_MORE2WRITE;
1464 return;
1465 }
1466 }
1467 }
1468}
1469
1470PUBLIC int udp_cancel(fd, which_operation)
1471int fd;
1472int which_operation;
1473{
1474 udp_fd_t *udp_fd;
1475
1476 DBLOCK(0x10, printf("udp_cancel(%d, %d)\n", fd, which_operation));
1477
1478 udp_fd= &udp_fd_table[fd];
1479
1480 switch (which_operation)
1481 {
1482 case SR_CANCEL_READ:
1483assert (udp_fd->uf_flags & UFF_READ_IP);
1484 udp_fd->uf_flags &= ~UFF_READ_IP;
1485 reply_thr_put(udp_fd, EINTR, FALSE);
1486 break;
1487 case SR_CANCEL_WRITE:
1488assert (udp_fd->uf_flags & UFF_WRITE_IP);
1489 udp_fd->uf_flags &= ~UFF_WRITE_IP;
1490 if (udp_fd->uf_port->up_write_fd == udp_fd)
1491 udp_fd->uf_port->up_write_fd= NULL;
1492 reply_thr_get(udp_fd, EINTR, FALSE);
1493 break;
1494 case SR_CANCEL_IOCTL:
1495assert (udp_fd->uf_flags & UFF_IOCTL_IP);
1496 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
1497 udp_fd->uf_flags &= ~UFF_PEEK_IP;
1498 reply_thr_get(udp_fd, EINTR, TRUE);
1499 break;
1500 default:
1501 ip_panic(( "got unknown cancel request" ));
1502 }
1503 return NW_OK;
1504}
1505
1506PRIVATE void udp_buffree (priority)
1507int priority;
1508{
1509 int i;
1510 udp_fd_t *udp_fd;
1511 acc_t *tmp_acc;
1512
1513 if (priority == UDP_PRI_FDBUFS_EXTRA)
1514 {
1515 for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
1516 {
1517 while (udp_fd->uf_rdbuf_head &&
1518 udp_fd->uf_rdbuf_head->acc_ext_link)
1519 {
1520 tmp_acc= udp_fd->uf_rdbuf_head;
1521 udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
1522 bf_afree(tmp_acc);
1523 }
1524 }
1525 }
1526
1527 if (priority == UDP_PRI_FDBUFS)
1528 {
1529 for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
1530 {
1531 while (udp_fd->uf_rdbuf_head)
1532 {
1533 tmp_acc= udp_fd->uf_rdbuf_head;
1534 udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
1535 bf_afree(tmp_acc);
1536 }
1537 }
1538 }
1539}
1540
1541PRIVATE void udp_rd_enqueue(udp_fd, pack, exp_tim)
1542udp_fd_t *udp_fd;
1543acc_t *pack;
1544clock_t exp_tim;
1545{
1546 acc_t *tmp_acc;
1547 int result;
1548
1549 if (pack->acc_linkC != 1)
1550 {
1551 tmp_acc= bf_dupacc(pack);
1552 bf_afree(pack);
1553 pack= tmp_acc;
1554 }
1555 pack->acc_ext_link= NULL;
1556 if (udp_fd->uf_rdbuf_head == NULL)
1557 {
1558 udp_fd->uf_exp_tim= exp_tim;
1559 udp_fd->uf_rdbuf_head= pack;
1560 }
1561 else
1562 udp_fd->uf_rdbuf_tail->acc_ext_link= pack;
1563 udp_fd->uf_rdbuf_tail= pack;
1564
1565 if (udp_fd->uf_flags & UFF_PEEK_IP)
1566 {
1567 pack= bf_cut(udp_fd->uf_rdbuf_head, 0,
1568 sizeof(udp_io_hdr_t));
1569 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
1570 (size_t)0, pack, TRUE);
1571
1572 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
1573 udp_fd->uf_flags &= ~UFF_PEEK_IP;
1574 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
1575 result, (acc_t *)0, TRUE);
1576 assert (result == 0);
1577 }
1578
1579 if (udp_fd->uf_flags & UFF_SEL_READ)
1580 {
1581 udp_fd->uf_flags &= ~UFF_SEL_READ;
1582 if (udp_fd->uf_select_res)
1583 udp_fd->uf_select_res(udp_fd->uf_srfd, SR_SELECT_READ);
1584 else
1585 printf("udp_rd_enqueue: no select_res\n");
1586 }
1587}
1588
1589PRIVATE void hash_fd(udp_fd)
1590udp_fd_t *udp_fd;
1591{
1592 udp_port_t *udp_port;
1593 int hash;
1594
1595 udp_port= udp_fd->uf_port;
1596 if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
1597 NWUO_LP_ANY)
1598 {
1599 udp_fd->uf_port_next= udp_port->up_port_any;
1600 udp_port->up_port_any= udp_fd;
1601 }
1602 else
1603 {
1604 hash= udp_fd->uf_udpopt.nwuo_locport;
1605 hash ^= (hash >> 8);
1606 hash &= (UDP_PORT_HASH_NR-1);
1607
1608 udp_fd->uf_port_next= udp_port->up_port_hash[hash];
1609 udp_port->up_port_hash[hash]= udp_fd;
1610 }
1611}
1612
1613PRIVATE void unhash_fd(udp_fd)
1614udp_fd_t *udp_fd;
1615{
1616 udp_port_t *udp_port;
1617 udp_fd_t *prev, *curr, **udp_fd_p;
1618 int hash;
1619
1620 udp_port= udp_fd->uf_port;
1621 if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
1622 NWUO_LP_ANY)
1623 {
1624 udp_fd_p= &udp_port->up_port_any;
1625 }
1626 else
1627 {
1628 hash= udp_fd->uf_udpopt.nwuo_locport;
1629 hash ^= (hash >> 8);
1630 hash &= (UDP_PORT_HASH_NR-1);
1631
1632 udp_fd_p= &udp_port->up_port_hash[hash];
1633 }
1634 for (prev= NULL, curr= *udp_fd_p; curr;
1635 prev= curr, curr= curr->uf_port_next)
1636 {
1637 if (curr == udp_fd)
1638 break;
1639 }
1640 assert(curr);
1641 if (prev)
1642 prev->uf_port_next= curr->uf_port_next;
1643 else
1644 *udp_fd_p= curr->uf_port_next;
1645}
1646
1647#ifdef BUF_CONSISTENCY_CHECK
1648PRIVATE void udp_bufcheck()
1649{
1650 int i;
1651 udp_port_t *udp_port;
1652 udp_fd_t *udp_fd;
1653 acc_t *tmp_acc;
1654
1655 for (i= 0, udp_port= udp_port_table; i<udp_conf_nr; i++, udp_port++)
1656 {
1657 if (udp_port->up_wr_pack)
1658 bf_check_acc(udp_port->up_wr_pack);
1659 }
1660
1661 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
1662 {
1663 for (tmp_acc= udp_fd->uf_rdbuf_head; tmp_acc;
1664 tmp_acc= tmp_acc->acc_ext_link)
1665 {
1666 bf_check_acc(tmp_acc);
1667 }
1668 }
1669}
1670#endif
1671
1672/*
1673 * $PchId: udp.c,v 1.25 2005/06/28 14:14:44 philip Exp $
1674 */
Note: See TracBrowser for help on using the repository browser.