4 Implementation of a pseudo IP device.
6 Created: Apr 22, 1993 by Philip Homburg
8 Copyright 1995 Philip Homburg
22 typedef struct psip_port
27 struct psip_fd
*pp_rd_head
;
28 struct psip_fd
*pp_rd_tail
;
29 acc_t
*pp_promisc_head
;
30 acc_t
*pp_promisc_tail
;
34 #define PPF_CONFIGURED 1
38 #define PSIP_FD_NR (1*IP_PORT_MAX)
40 typedef struct psip_fd
45 get_userdata_t pf_get_userdata
;
46 put_userdata_t pf_put_userdata
;
47 struct psip_fd
*pf_rd_next
;
49 nwio_psipopt_t pf_psipopt
;
58 static psip_port_t
*psip_port_table
;
59 static psip_fd_t psip_fd_table
[PSIP_FD_NR
];
61 static int psip_open
ARGS(( int port
, int srfd
,
62 get_userdata_t get_userdata
, put_userdata_t put_userdata
,
63 put_pkt_t pkt_pkt
, select_res_t select_res
));
64 static int psip_ioctl
ARGS(( int fd
, ioreq_t req
));
65 static int psip_read
ARGS(( int fd
, size_t count
));
66 static int psip_write
ARGS(( int fd
, size_t count
));
67 static int psip_select
ARGS(( int port_nr
, unsigned operations
));
68 static void psip_close
ARGS(( int fd
));
69 static int psip_cancel
ARGS(( int fd
, int which_operation
));
70 static void promisc_restart_read
ARGS(( psip_port_t
*psip_port
));
71 static int psip_setopt
ARGS(( psip_fd_t
*psip_fd
, nwio_psipopt_t
*newoptp
));
72 static void psip_buffree
ARGS(( int priority
));
73 static void check_promisc
ARGS(( psip_port_t
*psip_port
));
74 #ifdef BUF_CONSISTENCY_CHECK
75 static void psip_bufcheck
ARGS(( void ));
77 static void reply_thr_put
ARGS(( psip_fd_t
*psip_fd
, int reply
,
79 static void reply_thr_get
ARGS(( psip_fd_t
*psip_fd
, int reply
,
84 psip_port_table
= alloc(psip_conf_nr
* sizeof(psip_port_table
[0]));
90 psip_port_t
*psip_port
;
93 for (i
=0, psip_port
= psip_port_table
; i
<psip_conf_nr
; i
++, psip_port
++)
94 psip_port
->pp_flags
= PPF_EMPTY
;
96 for (i
=0, psip_fd
= psip_fd_table
; i
<PSIP_FD_NR
; i
++, psip_fd
++)
97 psip_fd
->pf_flags
= PFF_EMPTY
;
99 for (i
=0, psip_port
= psip_port_table
; i
<psip_conf_nr
; i
++, psip_port
++)
101 psip_port
->pp_flags
|= PPF_CONFIGURED
;
102 psip_port
->pp_opencnt
= 0;
103 psip_port
->pp_rd_head
= NULL
;
104 psip_port
->pp_promisc_head
= NULL
;
107 #ifndef BUF_CONSISTENCY_CHECK
108 bf_logon(psip_buffree
);
110 bf_logon(psip_buffree
, psip_bufcheck
);
114 int psip_enable(port_nr
, ip_port_nr
)
118 psip_port_t
*psip_port
;
120 assert(port_nr
>= 0);
121 if (port_nr
>= psip_conf_nr
)
124 psip_port
= &psip_port_table
[port_nr
];
125 if (!(psip_port
->pp_flags
&PPF_CONFIGURED
))
128 psip_port
->pp_ipdev
= ip_port_nr
;
129 psip_port
->pp_flags
|= PPF_ENABLED
;
131 sr_add_minor(if2minor(psip_conf
[port_nr
].pc_ifno
, PSIP_DEV_OFF
),
132 port_nr
, psip_open
, psip_close
, psip_read
,
133 psip_write
, psip_ioctl
, psip_cancel
, psip_select
);
138 int psip_send(port_nr
, dest
, pack
)
143 psip_port_t
*psip_port
;
144 psip_fd_t
*psip_fd
, *mark_fd
;
145 int i
, result
, result1
;
146 size_t buf_size
, extrasize
;
147 acc_t
*hdr_pack
, *acc
;
150 assert(port_nr
>= 0 && port_nr
< psip_conf_nr
);
151 psip_port
= &psip_port_table
[port_nr
];
153 if (psip_port
->pp_opencnt
== 0)
161 mark_fd
= psip_port
->pp_rd_tail
;
163 for(i
= 0; i
<PSIP_FD_NR
; i
++)
165 psip_fd
= psip_port
->pp_rd_head
;
168 psip_port
->pp_rd_head
= psip_fd
->pf_rd_next
;
169 if (!(psip_fd
->pf_flags
& PFF_PROMISC
))
171 psip_fd
->pf_rd_next
= NULL
;
172 if (psip_port
->pp_rd_head
== NULL
)
173 psip_port
->pp_rd_head
= psip_fd
;
175 psip_port
->pp_rd_tail
->pf_rd_next
= psip_fd
;
176 psip_port
->pp_rd_tail
= psip_fd
;
177 if (psip_fd
== mark_fd
)
181 ip_panic(( "psip_send: loop" ));
183 assert(psip_fd
->pf_flags
& PFF_READ_IP
);
184 psip_fd
->pf_flags
&= ~PFF_READ_IP
;
186 if (psip_fd
->pf_flags
& PFF_NEXTHOP
)
187 extrasize
= sizeof(dest
);
191 buf_size
= bf_bufsize(pack
);
192 if (buf_size
+extrasize
<= psip_fd
->pf_rd_count
)
194 if (psip_port
->pp_flags
& PPF_PROMISC
)
196 /* Deal with promiscuous mode. */
197 hdr_pack
= bf_memreq(sizeof(*hdr
));
198 hdr
= (psip_io_hdr_t
*)ptr2acc_data(hdr_pack
);
199 memset(hdr
, '\0', sizeof(*hdr
));
200 hdr
->pih_flags
|= PF_LOC2REM
;
201 hdr
->pih_nexthop
= dest
;
204 hdr_pack
->acc_next
= pack
;
205 hdr_pack
->acc_ext_link
= NULL
;
206 if (psip_port
->pp_promisc_head
)
208 /* Append at the end. */
209 psip_port
->pp_promisc_tail
->
210 acc_ext_link
= hdr_pack
;
211 psip_port
->pp_promisc_tail
= hdr_pack
;
216 psip_port
->pp_promisc_head
= hdr_pack
;
217 psip_port
->pp_promisc_tail
= hdr_pack
;
218 if (psip_port
->pp_rd_head
)
219 promisc_restart_read(psip_port
);
225 /* Prepend nexthop address */
226 acc
= bf_memreq(sizeof(dest
));
227 *(ipaddr_t
*)(ptr2acc_data(acc
))= dest
;
229 pack
= acc
; acc
= NULL
;
230 buf_size
+= extrasize
;
233 result
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
234 (size_t)0, pack
, FALSE
);
241 result1
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
242 (size_t)result
, NULL
, FALSE
);
243 assert(result1
== NW_OK
);
244 if (result
== EPACKSIZE
)
251 static int psip_open(port
, srfd
, get_userdata
, put_userdata
, put_pkt
,
255 get_userdata_t get_userdata
;
256 put_userdata_t put_userdata
;
258 select_res_t select_res
;
260 psip_port_t
*psip_port
;
264 assert(port
>= 0 && port
< psip_conf_nr
);
265 psip_port
= &psip_port_table
[port
];
267 if (!(psip_port
->pp_flags
& PPF_ENABLED
))
270 for (i
= 0, psip_fd
= psip_fd_table
; i
<PSIP_FD_NR
; i
++, psip_fd
++)
272 if (psip_fd
->pf_flags
& PFF_INUSE
)
278 psip_fd
->pf_flags
|= PFF_INUSE
;
279 psip_fd
->pf_srfd
= srfd
;
280 psip_fd
->pf_port
= psip_port
;
281 psip_fd
->pf_get_userdata
= get_userdata
;
282 psip_fd
->pf_put_userdata
= put_userdata
;
283 psip_port
->pp_opencnt
++;
288 static int psip_ioctl(fd
, req
)
295 nwio_ipconf_t
*ipconfp
;
296 nwio_psipopt_t
*psip_opt
, *newoptp
;
298 assert(fd
>= 0 && fd
< PSIP_FD_NR
);
299 psip_fd
= &psip_fd_table
[fd
];
304 data
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
, 0,
305 sizeof(*ipconfp
), TRUE
);
311 data
= bf_packIffLess(data
, sizeof(*ipconfp
));
312 assert (data
->acc_length
== sizeof(*ipconfp
));
314 ipconfp
= (nwio_ipconf_t
*)ptr2acc_data(data
);
315 result
= ip_setconf(psip_fd
->pf_port
->pp_ipdev
, ipconfp
);
317 reply_thr_get(psip_fd
, result
, TRUE
);
320 data
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
, 0,
321 sizeof(*psip_opt
), TRUE
);
327 data
= bf_packIffLess(data
, sizeof(*psip_opt
));
328 assert (data
->acc_length
== sizeof(*psip_opt
));
330 newoptp
= (nwio_psipopt_t
*)ptr2acc_data(data
);
331 result
= psip_setopt(psip_fd
, newoptp
);
335 if (psip_fd
->pf_psipopt
.nwpo_flags
& NWPO_EN_PROMISC
)
337 psip_fd
->pf_flags
|= PFF_PROMISC
;
338 psip_fd
->pf_port
->pp_flags
|= PPF_PROMISC
;
342 psip_fd
->pf_flags
&= ~PFF_PROMISC
;
343 check_promisc(psip_fd
->pf_port
);
345 if (psip_fd
->pf_psipopt
.nwpo_flags
& NWPO_EN_NEXTHOP
)
347 psip_fd
->pf_flags
|= PFF_NEXTHOP
;
351 psip_fd
->pf_flags
&= ~PFF_NEXTHOP
;
354 reply_thr_get(psip_fd
, result
, TRUE
);
357 data
= bf_memreq(sizeof(*psip_opt
));
358 psip_opt
= (nwio_psipopt_t
*)ptr2acc_data(data
);
360 *psip_opt
= psip_fd
->pf_psipopt
;
361 result
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
, 0,
364 reply_thr_put(psip_fd
, NW_OK
, TRUE
);
367 reply_thr_put(psip_fd
, ENOTTY
, TRUE
);
373 static int psip_read(fd
, count
)
377 psip_port_t
*psip_port
;
383 assert(fd
>= 0 && fd
< PSIP_FD_NR
);
384 psip_fd
= &psip_fd_table
[fd
];
385 psip_port
= psip_fd
->pf_port
;
387 if ((psip_fd
->pf_flags
& PFF_PROMISC
) && psip_port
->pp_promisc_head
)
389 /* Deliver a queued packet. */
390 pack
= psip_port
->pp_promisc_head
;
391 buf_size
= bf_bufsize(pack
);
392 if (buf_size
<= count
)
394 psip_port
->pp_promisc_head
= pack
->acc_ext_link
;
395 result
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
396 (size_t)0, pack
, FALSE
);
403 result1
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
404 (size_t)result
, NULL
, FALSE
);
405 assert(result1
== NW_OK
);
409 psip_fd
->pf_rd_count
= count
;
410 if (psip_port
->pp_rd_head
== NULL
)
411 psip_port
->pp_rd_head
= psip_fd
;
413 psip_port
->pp_rd_tail
->pf_rd_next
= psip_fd
;
414 psip_fd
->pf_rd_next
= NULL
;
415 psip_port
->pp_rd_tail
= psip_fd
;
417 psip_fd
->pf_flags
|= PFF_READ_IP
;
418 if (!(psip_fd
->pf_flags
& PFF_PROMISC
))
419 ipps_get(psip_port
->pp_ipdev
);
420 if (psip_fd
->pf_flags
& PFF_READ_IP
)
425 static int psip_write(fd
, count
)
429 psip_port_t
*psip_port
;
431 acc_t
*pack
, *hdr_pack
;
436 assert(fd
>= 0 && fd
< PSIP_FD_NR
);
437 psip_fd
= &psip_fd_table
[fd
];
438 psip_port
= psip_fd
->pf_port
;
440 pack
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
, (size_t)0,
444 pack
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
,
445 (size_t)EFAULT
, (size_t)0, FALSE
);
446 assert(pack
== NULL
);
450 if (psip_fd
->pf_flags
& PFF_NEXTHOP
)
452 pack_len
= bf_bufsize(pack
);
453 if (pack_len
<= sizeof(nexthop
))
455 /* Something strange */
456 bf_afree(pack
); pack
= NULL
;
457 pack
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
,
458 (size_t)EPACKSIZE
, (size_t)0, FALSE
);
459 assert(pack
== NULL
);
462 pack
= bf_packIffLess(pack
, sizeof(nexthop
));
463 nexthop
= *(ipaddr_t
*)ptr2acc_data(pack
);
464 pack
= bf_delhead(pack
, sizeof(nexthop
));
466 /* Map multicast to broadcast */
467 if ((nexthop
& HTONL(0xE0000000)) == HTONL(0xE0000000))
468 nexthop
= HTONL(0xffffffff);
472 /* Assume point to point */
473 nexthop
= HTONL(0x00000000);
476 if (psip_port
->pp_flags
& PPF_PROMISC
)
478 /* Deal with promiscuous mode. */
479 hdr_pack
= bf_memreq(sizeof(*hdr
));
480 hdr
= (psip_io_hdr_t
*)ptr2acc_data(hdr_pack
);
481 memset(hdr
, '\0', sizeof(*hdr
));
482 hdr
->pih_flags
|= PF_REM2LOC
;
483 hdr
->pih_nexthop
= nexthop
;
486 hdr_pack
->acc_next
= pack
;
487 hdr_pack
->acc_ext_link
= NULL
;
488 if (psip_port
->pp_promisc_head
)
490 /* Append at the end. */
491 psip_port
->pp_promisc_tail
->acc_ext_link
= hdr_pack
;
492 psip_port
->pp_promisc_tail
= hdr_pack
;
497 psip_port
->pp_promisc_head
= hdr_pack
;
498 psip_port
->pp_promisc_tail
= hdr_pack
;
499 if (psip_port
->pp_rd_head
)
500 promisc_restart_read(psip_port
);
503 ipps_put(psip_port
->pp_ipdev
, nexthop
, pack
);
504 pack
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
, (size_t)count
,
506 assert(pack
== NULL
);
510 static int psip_select(fd
, operations
)
514 printf("psip_select: not implemented\n");
518 static void psip_close(fd
)
521 psip_port_t
*psip_port
;
524 assert(fd
>= 0 && fd
< PSIP_FD_NR
);
525 psip_fd
= &psip_fd_table
[fd
];
526 psip_port
= psip_fd
->pf_port
;
528 if (psip_fd
->pf_flags
& PFF_PROMISC
)
530 /* Check if the port should still be in promiscuous mode.
532 psip_fd
->pf_flags
&= ~PFF_PROMISC
;
533 check_promisc(psip_fd
->pf_port
);
536 assert(psip_port
->pp_opencnt
>0);
537 psip_port
->pp_opencnt
--;
538 psip_fd
->pf_flags
= PFF_EMPTY
;
539 ipps_get(psip_port
->pp_ipdev
);
543 static int psip_cancel(fd
, which_operation
)
547 psip_port_t
*psip_port
;
548 psip_fd_t
*psip_fd
, *prev_fd
, *tmp_fd
;
551 DBLOCK(1, printf("psip_cancel(%d, %d)\n", fd
, which_operation
));
553 assert(fd
>= 0 && fd
< PSIP_FD_NR
);
554 psip_fd
= &psip_fd_table
[fd
];
555 psip_port
= psip_fd
->pf_port
;
557 switch(which_operation
)
559 case SR_CANCEL_IOCTL
:
560 ip_panic(( "should not be here" ));
562 assert(psip_fd
->pf_flags
& PFF_READ_IP
);
563 for (prev_fd
= NULL
, tmp_fd
= psip_port
->pp_rd_head
; tmp_fd
;
564 prev_fd
= tmp_fd
, tmp_fd
= tmp_fd
->pf_rd_next
)
566 if (tmp_fd
== psip_fd
)
570 ip_panic(( "unable to find to request to cancel" ));
572 psip_port
->pp_rd_head
= psip_fd
->pf_rd_next
;
574 prev_fd
->pf_rd_next
= psip_fd
->pf_rd_next
;
575 if (psip_fd
->pf_rd_next
== NULL
)
576 psip_port
->pp_rd_tail
= prev_fd
;
577 psip_fd
->pf_flags
&= ~PFF_READ_IP
;
578 result
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
579 (size_t)EINTR
, NULL
, FALSE
);
580 assert(result
== NW_OK
);
582 case SR_CANCEL_WRITE
:
583 ip_panic(( "should not be here" ));
585 ip_panic(( "invalid operation for cancel" ));
590 static void promisc_restart_read(psip_port
)
591 psip_port_t
*psip_port
;
593 psip_fd_t
*psip_fd
, *prev
, *next
;
598 /* Overkill at the moment: just one reader in promiscious mode is
601 pack
= psip_port
->pp_promisc_head
;
604 assert(pack
->acc_ext_link
== NULL
);
606 for(psip_fd
= psip_port
->pp_rd_head
, prev
= NULL
; psip_fd
;
607 prev
= psip_fd
, psip_fd
= psip_fd
->pf_rd_next
)
610 if (!(psip_fd
->pf_flags
& PFF_PROMISC
))
612 next
= psip_fd
->pf_rd_next
;
614 prev
->pf_rd_next
= next
;
616 psip_port
->pp_rd_head
= next
;
618 psip_port
->pp_rd_tail
= prev
;
620 assert(psip_fd
->pf_flags
& PFF_READ_IP
);
621 psip_fd
->pf_flags
&= ~PFF_READ_IP
;
623 buf_size
= bf_bufsize(pack
);
624 if (buf_size
<= psip_fd
->pf_rd_count
)
626 psip_port
->pp_promisc_head
= pack
->acc_ext_link
;
627 result
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
628 (size_t)0, pack
, FALSE
);
635 result1
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
,
636 (size_t)result
, NULL
, FALSE
);
637 assert(result1
== NW_OK
);
639 if (psip_port
->pp_promisc_head
)
641 /* Restart from the beginning */
642 assert(result
== EPACKSIZE
);
643 psip_fd
= psip_port
->pp_rd_head
;
651 static int psip_setopt(psip_fd
, newoptp
)
653 nwio_psipopt_t
*newoptp
;
655 nwio_psipopt_t oldopt
;
656 unsigned int new_en_flags
, new_di_flags
, old_en_flags
, old_di_flags
;
657 unsigned long new_flags
;
659 oldopt
= psip_fd
->pf_psipopt
;
661 old_en_flags
= oldopt
.nwpo_flags
& 0xffff;
662 old_di_flags
= (oldopt
.nwpo_flags
>> 16) & 0xffff;
664 new_en_flags
= newoptp
->nwpo_flags
& 0xffff;
665 new_di_flags
= (newoptp
->nwpo_flags
>> 16) & 0xffff;
667 if (new_en_flags
& new_di_flags
)
670 /* NWUO_LOCADDR_MASK */
671 if (!((new_en_flags
| new_di_flags
) & NWPO_PROMISC_MASK
))
673 new_en_flags
|= (old_en_flags
& NWPO_PROMISC_MASK
);
674 new_di_flags
|= (old_di_flags
& NWPO_PROMISC_MASK
);
677 new_flags
= ((unsigned long)new_di_flags
<< 16) | new_en_flags
;
678 if ((new_flags
& NWPO_EN_PROMISC
) &&
679 (psip_fd
->pf_port
->pp_flags
& PPF_PROMISC
))
681 printf("psip_setopt: EBUSY for port %d, flags 0x%x\n",
682 psip_fd
->pf_port
- psip_port_table
,
683 psip_fd
->pf_port
->pp_flags
);
684 /* We can support only one at a time. */
688 psip_fd
->pf_psipopt
= *newoptp
;
689 psip_fd
->pf_psipopt
.nwpo_flags
= new_flags
;
694 static void check_promisc(psip_port
)
695 psip_port_t
*psip_port
;
699 acc_t
*acc
, *acc_next
;
701 /* Check if the port should still be in promiscuous mode. Overkill
704 if (!(psip_port
->pp_flags
& PPF_PROMISC
))
707 psip_port
->pp_flags
&= ~PPF_PROMISC
;
708 for (i
= 0, psip_fd
= psip_fd_table
; i
<PSIP_FD_NR
; i
++, psip_fd
++)
710 if ((psip_fd
->pf_flags
& (PFF_INUSE
|PFF_PROMISC
)) !=
711 (PFF_INUSE
|PFF_PROMISC
))
715 if (psip_fd
->pf_port
!= psip_port
)
717 printf("check_promisc: setting PROMISC for port %d\n",
718 psip_port
-psip_port_table
);
719 psip_port
->pp_flags
|= PPF_PROMISC
;
722 if (!(psip_port
->pp_flags
& PPF_PROMISC
))
724 /* Delete queued packets. */
725 acc
= psip_port
->pp_promisc_head
;
726 psip_port
->pp_promisc_head
= NULL
;
729 acc_next
= acc
->acc_ext_link
;
736 static void psip_buffree (priority
)
740 psip_port_t
*psip_port
;
741 acc_t
*tmp_acc
, *next_acc
;
743 if (priority
== PSIP_PRI_EXP_PROMISC
)
745 for (i
=0, psip_port
= psip_port_table
; i
<psip_conf_nr
;
748 if (!(psip_port
->pp_flags
& PPF_CONFIGURED
) )
750 if (psip_port
->pp_promisc_head
)
752 tmp_acc
= psip_port
->pp_promisc_head
;
755 next_acc
= tmp_acc
->acc_ext_link
;
759 psip_port
->pp_promisc_head
= NULL
;
765 #ifdef BUF_CONSISTENCY_CHECK
766 static void psip_bufcheck()
769 psip_port_t
*psip_port
;
772 for (i
= 0, psip_port
= psip_port_table
; i
<psip_conf_nr
;
775 for (tmp_acc
= psip_port
->pp_promisc_head
; tmp_acc
;
776 tmp_acc
= tmp_acc
->acc_ext_link
)
778 bf_check_acc(tmp_acc
);
788 static void reply_thr_put(psip_fd
, reply
, for_ioctl
)
795 result
= (*psip_fd
->pf_put_userdata
)(psip_fd
->pf_srfd
, reply
,
796 (acc_t
*)0, for_ioctl
);
797 assert(result
== NW_OK
);
804 static void reply_thr_get(psip_fd
, reply
, for_ioctl
)
810 result
= (*psip_fd
->pf_get_userdata
)(psip_fd
->pf_srfd
, reply
,
811 (size_t)0, for_ioctl
);
817 * $PchId: psip.c,v 1.15 2005/06/28 14:19:29 philip Exp $