4 Copyright 1995 Philip Homburg
22 FORWARD
int ip_checkopt
ARGS(( ip_fd_t
*ip_fd
));
23 FORWARD
void reply_thr_get
ARGS(( ip_fd_t
*ip_fd
, size_t
24 reply
, int for_ioctl
));
25 FORWARD
void report_addr
ARGS(( ip_port_t
*ip_port
));
27 PUBLIC
int ip_ioctl (fd
, req
)
34 nwio_ipopt_t oldopt
, newopt
;
35 nwio_ipconf2_t
*ipconf2
;
36 nwio_ipconf_t
*ipconf
;
37 nwio_route_t
*route_ent
;
40 unsigned int new_en_flags
, new_di_flags
,
41 old_en_flags
, old_di_flags
;
42 unsigned long new_flags
;
44 nwio_ipconf_t ipconf_var
;
46 assert (fd
>=0 && fd
<=IP_FD_NR
);
47 ip_fd
= &ip_fd_table
[fd
];
49 assert (ip_fd
->if_flags
& IFF_INUSE
);
54 ip_port
= ip_fd
->if_port
;
56 if (!(ip_port
->ip_flags
& IPF_IPADDRSET
))
58 ip_fd
->if_ioctl
= NWIOSIPOPT
;
59 ip_fd
->if_flags
|= IFF_IOCTL_IP
;
62 ip_fd
->if_flags
&= ~IFF_IOCTL_IP
;
64 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, 0,
65 sizeof(nwio_ipopt_t
), TRUE
);
67 data
= bf_packIffLess (data
, sizeof(nwio_ipopt_t
));
68 assert (data
->acc_length
== sizeof(nwio_ipopt_t
));
70 ipopt
= (nwio_ipopt_t
*)ptr2acc_data(data
);
71 oldopt
= ip_fd
->if_ipopt
;
74 old_en_flags
= oldopt
.nwio_flags
& 0xffff;
75 old_di_flags
= (oldopt
.nwio_flags
>> 16) & 0xffff;
76 new_en_flags
= newopt
.nwio_flags
& 0xffff;
77 new_di_flags
= (newopt
.nwio_flags
>> 16) & 0xffff;
78 if (new_en_flags
& new_di_flags
)
81 reply_thr_get (ip_fd
, EBADMODE
, TRUE
);
86 if (new_di_flags
& NWIO_ACC_MASK
)
89 reply_thr_get (ip_fd
, EBADMODE
, TRUE
);
91 /* access modes can't be disable */
94 if (!(new_en_flags
& NWIO_ACC_MASK
))
95 new_en_flags
|= (old_en_flags
& NWIO_ACC_MASK
);
98 if (!((new_en_flags
|new_di_flags
) & NWIO_LOC_MASK
))
100 new_en_flags
|= (old_en_flags
& NWIO_LOC_MASK
);
101 new_di_flags
|= (old_di_flags
& NWIO_LOC_MASK
);
104 /* NWIO_BROAD_MASK */
105 if (!((new_en_flags
|new_di_flags
) & NWIO_BROAD_MASK
))
107 new_en_flags
|= (old_en_flags
& NWIO_BROAD_MASK
);
108 new_di_flags
|= (old_di_flags
& NWIO_BROAD_MASK
);
112 if (!((new_en_flags
|new_di_flags
) & NWIO_REM_MASK
))
114 new_en_flags
|= (old_en_flags
& NWIO_REM_MASK
);
115 new_di_flags
|= (old_di_flags
& NWIO_REM_MASK
);
116 newopt
.nwio_rem
= oldopt
.nwio_rem
;
119 /* NWIO_PROTO_MASK */
120 if (!((new_en_flags
|new_di_flags
) & NWIO_PROTO_MASK
))
122 new_en_flags
|= (old_en_flags
& NWIO_PROTO_MASK
);
123 new_di_flags
|= (old_di_flags
& NWIO_PROTO_MASK
);
124 newopt
.nwio_proto
= oldopt
.nwio_proto
;
127 /* NWIO_HDR_O_MASK */
128 if (!((new_en_flags
|new_di_flags
) & NWIO_HDR_O_MASK
))
130 new_en_flags
|= (old_en_flags
& NWIO_HDR_O_MASK
);
131 new_di_flags
|= (old_di_flags
& NWIO_HDR_O_MASK
);
132 newopt
.nwio_tos
= oldopt
.nwio_tos
;
133 newopt
.nwio_ttl
= oldopt
.nwio_ttl
;
134 newopt
.nwio_df
= oldopt
.nwio_df
;
135 newopt
.nwio_hdropt
= oldopt
.nwio_hdropt
;
139 if (!((new_en_flags
|new_di_flags
) & NWIO_RW_MASK
))
141 new_en_flags
|= (old_en_flags
& NWIO_RW_MASK
);
142 new_di_flags
|= (old_di_flags
& NWIO_RW_MASK
);
145 new_flags
= ((unsigned long)new_di_flags
<< 16) | new_en_flags
;
147 if ((new_flags
& NWIO_RWDATONLY
) && (new_flags
&
148 (NWIO_REMANY
|NWIO_PROTOANY
|NWIO_HDR_O_ANY
)))
151 reply_thr_get(ip_fd
, EBADMODE
, TRUE
);
155 if (ip_fd
->if_flags
& IFF_OPTSET
)
156 ip_unhash_proto(ip_fd
);
158 newopt
.nwio_flags
= new_flags
;
159 ip_fd
->if_ipopt
= newopt
;
161 result
= ip_checkopt(ip_fd
);
164 ip_fd
->if_ipopt
= oldopt
;
167 reply_thr_get (ip_fd
, result
, TRUE
);
171 data
= bf_memreq(sizeof(nwio_ipopt_t
));
173 ipopt
= (nwio_ipopt_t
*)ptr2acc_data(data
);
175 *ipopt
= ip_fd
->if_ipopt
;
177 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, 0, data
,
179 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, result
,
184 ip_port
= ip_fd
->if_port
;
186 if (req
== NWIOSIPCONF2
)
188 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, 0,
189 sizeof(*ipconf2
), TRUE
);
190 data
= bf_packIffLess (data
, sizeof(*ipconf2
));
191 assert (data
->acc_length
== sizeof(*ipconf2
));
193 ipconf2
= (nwio_ipconf2_t
*)ptr2acc_data(data
);
196 ipconf
->nwic_flags
= ipconf2
->nwic_flags
;
197 ipconf
->nwic_ipaddr
= ipconf2
->nwic_ipaddr
;
198 ipconf
->nwic_netmask
= ipconf2
->nwic_netmask
;
199 ipconf
->nwic_flags
&= ~NWIC_MTU_SET
;
203 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, 0,
204 sizeof(*ipconf
), TRUE
);
205 data
= bf_packIffLess (data
, sizeof(*ipconf
));
206 assert (data
->acc_length
== sizeof(*ipconf
));
208 ipconf
= (nwio_ipconf_t
*)ptr2acc_data(data
);
210 r
= ip_setconf(ip_port
-ip_port_table
, ipconf
);
212 return (*ip_fd
->if_put_userdata
)(ip_fd
-> if_srfd
, r
,
216 ip_port
= ip_fd
->if_port
;
218 if (!(ip_port
->ip_flags
& IPF_IPADDRSET
))
220 ip_fd
->if_ioctl
= NWIOGIPCONF2
;
221 ip_fd
->if_flags
|= IFF_IOCTL_IP
;
224 ip_fd
->if_flags
&= ~IFF_IOCTL_IP
;
225 data
= bf_memreq(sizeof(nwio_ipconf_t
));
226 ipconf2
= (nwio_ipconf2_t
*)ptr2acc_data(data
);
227 ipconf2
->nwic_flags
= NWIC_IPADDR_SET
;
228 ipconf2
->nwic_ipaddr
= ip_port
->ip_ipaddr
;
229 ipconf2
->nwic_netmask
= ip_port
->ip_subnetmask
;
230 if (ip_port
->ip_flags
& IPF_NETMASKSET
)
231 ipconf2
->nwic_flags
|= NWIC_NETMASK_SET
;
233 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, 0, data
,
235 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, result
,
239 ip_port
= ip_fd
->if_port
;
241 if (!(ip_port
->ip_flags
& IPF_IPADDRSET
))
243 ip_fd
->if_ioctl
= NWIOGIPCONF
;
244 ip_fd
->if_flags
|= IFF_IOCTL_IP
;
247 ip_fd
->if_flags
&= ~IFF_IOCTL_IP
;
248 data
= bf_memreq(sizeof(*ipconf
));
249 ipconf
= (nwio_ipconf_t
*)ptr2acc_data(data
);
250 ipconf
->nwic_flags
= NWIC_IPADDR_SET
;
251 ipconf
->nwic_ipaddr
= ip_port
->ip_ipaddr
;
252 ipconf
->nwic_netmask
= ip_port
->ip_subnetmask
;
253 if (ip_port
->ip_flags
& IPF_NETMASKSET
)
254 ipconf
->nwic_flags
|= NWIC_NETMASK_SET
;
255 ipconf
->nwic_mtu
= ip_port
->ip_mtu
;
257 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, 0, data
,
259 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, result
,
263 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
,
264 0, sizeof(nwio_route_t
), TRUE
);
267 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
271 data
= bf_packIffLess (data
, sizeof(nwio_route_t
) );
272 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
273 ent_no
= route_ent
->nwr_ent_no
;
276 data
= bf_memreq(sizeof(nwio_route_t
));
277 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
278 result
= ipr_get_oroute(ent_no
, route_ent
);
283 assert(result
== NW_OK
);
284 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, 0,
287 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
288 result
, (acc_t
*)0, TRUE
);
291 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
,
292 0, sizeof(nwio_route_t
), TRUE
);
295 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
298 if (!(ip_fd
->if_port
->ip_flags
& IPF_IPADDRSET
))
300 /* Interface is down, no changes allowed */
301 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
305 data
= bf_packIffLess (data
, sizeof(nwio_route_t
) );
306 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
307 result
= ipr_add_oroute(ip_fd
->if_port
-ip_port_table
,
308 route_ent
->nwr_dest
, route_ent
->nwr_netmask
,
309 route_ent
->nwr_gateway
, (time_t)0,
310 route_ent
->nwr_dist
, route_ent
->nwr_mtu
,
311 !!(route_ent
->nwr_flags
& NWRF_STATIC
),
312 route_ent
->nwr_pref
, NULL
);
315 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
316 result
, (acc_t
*)0, TRUE
);
319 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
,
320 0, sizeof(nwio_route_t
), TRUE
);
323 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
327 data
= bf_packIffLess (data
, sizeof(nwio_route_t
) );
328 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
329 result
= ipr_del_oroute(ip_fd
->if_port
-ip_port_table
,
330 route_ent
->nwr_dest
, route_ent
->nwr_netmask
,
331 route_ent
->nwr_gateway
,
332 !!(route_ent
->nwr_flags
& NWRF_STATIC
));
335 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
336 result
, (acc_t
*)0, TRUE
);
339 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
,
340 0, sizeof(nwio_route_t
), TRUE
);
343 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
347 data
= bf_packIffLess (data
, sizeof(nwio_route_t
) );
348 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
349 ent_no
= route_ent
->nwr_ent_no
;
352 data
= bf_memreq(sizeof(nwio_route_t
));
353 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
354 result
= ipr_get_iroute(ent_no
, route_ent
);
359 assert(result
== NW_OK
);
360 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, 0,
363 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
364 result
, (acc_t
*)0, TRUE
);
367 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
,
368 0, sizeof(nwio_route_t
), TRUE
);
371 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
374 if (!(ip_fd
->if_port
->ip_flags
& IPF_IPADDRSET
))
376 /* Interface is down, no changes allowed */
377 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
381 data
= bf_packIffLess (data
, sizeof(nwio_route_t
) );
382 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
383 result
= ipr_add_iroute(ip_fd
->if_port
-ip_port_table
,
384 route_ent
->nwr_dest
, route_ent
->nwr_netmask
,
385 route_ent
->nwr_gateway
,
386 (route_ent
->nwr_flags
& NWRF_UNREACHABLE
) ?
387 IRTD_UNREACHABLE
: route_ent
->nwr_dist
,
389 !!(route_ent
->nwr_flags
& NWRF_STATIC
), NULL
);
392 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
393 result
, (acc_t
*)0, TRUE
);
396 data
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
,
397 0, sizeof(nwio_route_t
), TRUE
);
400 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
404 data
= bf_packIffLess (data
, sizeof(nwio_route_t
) );
405 route_ent
= (nwio_route_t
*)ptr2acc_data(data
);
406 result
= ipr_del_iroute(ip_fd
->if_port
-ip_port_table
,
407 route_ent
->nwr_dest
, route_ent
->nwr_netmask
,
408 route_ent
->nwr_gateway
,
409 !!(route_ent
->nwr_flags
& NWRF_STATIC
));
412 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
413 result
, (acc_t
*)0, TRUE
);
415 /* The following ARP ioctls are only valid if the
416 * underlying device is an ethernet.
422 ip_port
= ip_fd
->if_port
;
424 if (ip_port
->ip_dl_type
!= IPDL_ETH
)
426 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
427 EBADIOCTL
, (acc_t
*)0, TRUE
);
429 result
= arp_ioctl(ip_port
->ip_dl
.dl_eth
.de_port
,
430 ip_fd
->if_srfd
, req
, ip_fd
->if_get_userdata
,
431 ip_fd
->if_put_userdata
);
432 assert (result
!= SUSPEND
);
433 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, result
,
439 DBLOCK(1, printf("replying EBADIOCTL: 0x%x\n", req
));
440 return (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, EBADIOCTL
,
444 PUBLIC
void ip_hash_proto(ip_fd
)
450 ip_port
= ip_fd
->if_port
;
451 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_PROTOANY
)
453 ip_fd
->if_proto_next
= ip_port
->ip_proto_any
;
454 ip_port
->ip_proto_any
= ip_fd
;
458 hash
= ip_fd
->if_ipopt
.nwio_proto
& (IP_PROTO_HASH_NR
-1);
459 ip_fd
->if_proto_next
= ip_port
->ip_proto
[hash
];
460 ip_port
->ip_proto
[hash
]= ip_fd
;
464 PUBLIC
void ip_unhash_proto(ip_fd
)
468 ip_fd_t
*prev
, *curr
, **ip_fd_p
;
471 ip_port
= ip_fd
->if_port
;
472 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_PROTOANY
)
474 ip_fd_p
= &ip_port
->ip_proto_any
;
478 hash
= ip_fd
->if_ipopt
.nwio_proto
& (IP_PROTO_HASH_NR
-1);
479 ip_fd_p
= &ip_port
->ip_proto
[hash
];
481 for (prev
= NULL
, curr
= *ip_fd_p
; curr
;
482 prev
= curr
, curr
= curr
->if_proto_next
)
489 prev
->if_proto_next
= curr
->if_proto_next
;
491 *ip_fd_p
= curr
->if_proto_next
;
494 PUBLIC
int ip_setconf(ip_port_nr
, ipconf
)
496 nwio_ipconf_t
*ipconf
;
498 int i
, old_ip_flags
, do_report
;
504 ip_port
= &ip_port_table
[ip_port_nr
];
506 old_ip_flags
= ip_port
->ip_flags
;
508 if (ipconf
->nwic_flags
& ~NWIC_FLAGS
)
512 if (ipconf
->nwic_flags
& NWIC_MTU_SET
)
514 mtu
= ipconf
->nwic_mtu
;
515 if (mtu
< IP_MIN_MTU
|| mtu
> ip_port
->ip_mtu_max
)
517 ip_port
->ip_mtu
= mtu
;
521 if (ipconf
->nwic_flags
& NWIC_NETMASK_SET
)
523 ip_port
->ip_subnetmask
= ipconf
->nwic_netmask
;
524 ip_port
->ip_flags
|= IPF_NETMASKSET
|IPF_SUBNET_BCAST
;
525 if (ntohl(ip_port
->ip_subnetmask
) >= 0xfffffffe)
526 ip_port
->ip_flags
&= ~IPF_SUBNET_BCAST
;
529 if (ipconf
->nwic_flags
& NWIC_IPADDR_SET
)
531 ipaddr
= ipconf
->nwic_ipaddr
;
532 ip_port
->ip_ipaddr
= ipaddr
;
533 ip_port
->ip_flags
|= IPF_IPADDRSET
;
534 ip_port
->ip_classfulmask
=
535 ip_netmask(ip_nettype(ipaddr
));
536 if (!(ip_port
->ip_flags
& IPF_NETMASKSET
))
538 ip_port
->ip_subnetmask
= ip_port
->ip_classfulmask
;
540 if (ipaddr
== HTONL(0x00000000))
542 /* Special case. Use 0.0.0.0 to shutdown interface. */
543 ip_port
->ip_flags
&= ~(IPF_IPADDRSET
|IPF_NETMASKSET
);
544 ip_port
->ip_subnetmask
= HTONL(0x00000000);
546 (*ip_port
->ip_dev_set_ipaddr
)(ip_port
);
548 /* revive calls waiting for an ip addresses */
549 for (i
=0, ip_fd
= ip_fd_table
; i
<IP_FD_NR
; i
++, ip_fd
++)
551 if (!(ip_fd
->if_flags
& IFF_INUSE
))
553 if (ip_fd
->if_port
!= ip_port
)
555 if (ip_fd
->if_flags
& IFF_IOCTL_IP
)
556 ip_ioctl (i
, ip_fd
->if_ioctl
);
562 ipr_chk_itab(ip_port
-ip_port_table
, ip_port
->ip_ipaddr
,
563 ip_port
->ip_subnetmask
);
564 ipr_chk_otab(ip_port
-ip_port_table
, ip_port
->ip_ipaddr
,
565 ip_port
->ip_subnetmask
);
567 report_addr(ip_port
);
572 PRIVATE
int ip_checkopt (ip_fd
)
575 /* bug: we don't check access modes yet */
578 unsigned int en_di_flags
;
582 flags
= ip_fd
->if_ipopt
.nwio_flags
;
583 en_di_flags
= (flags
>>16) | (flags
& 0xffff);
585 if (flags
& NWIO_HDR_O_SPEC
)
587 result
= ip_chk_hdropt (ip_fd
->if_ipopt
.nwio_hdropt
.iho_data
,
588 ip_fd
->if_ipopt
.nwio_hdropt
.iho_opt_siz
);
592 if ((en_di_flags
& NWIO_ACC_MASK
) &&
593 (en_di_flags
& NWIO_LOC_MASK
) &&
594 (en_di_flags
& NWIO_BROAD_MASK
) &&
595 (en_di_flags
& NWIO_REM_MASK
) &&
596 (en_di_flags
& NWIO_PROTO_MASK
) &&
597 (en_di_flags
& NWIO_HDR_O_MASK
) &&
598 (en_di_flags
& NWIO_RW_MASK
))
600 ip_fd
->if_flags
|= IFF_OPTSET
;
602 ip_hash_proto(ip_fd
);
606 ip_fd
->if_flags
&= ~IFF_OPTSET
;
608 while (ip_fd
->if_rdbuf_head
)
610 pack
= ip_fd
->if_rdbuf_head
;
611 ip_fd
->if_rdbuf_head
= pack
->acc_ext_link
;
617 PRIVATE
void reply_thr_get(ip_fd
, reply
, for_ioctl
)
623 result
= (ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, reply
,
624 (size_t)0, for_ioctl
);
628 PRIVATE
void report_addr(ip_port
)
636 pack
= bf_memreq(IP_MIN_HDR_SIZE
);
637 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
639 hdr_len
= IP_MIN_HDR_SIZE
;
640 ip_hdr
->ih_vers_ihl
= (IP_VERSION
<< 4) | (hdr_len
/4);
642 ip_hdr
->ih_length
= htons(ip_port
->ip_mtu
);
644 ip_hdr
->ih_flags_fragoff
= 0;
647 ip_hdr
->ih_src
= ip_port
->ip_ipaddr
;
648 ip_hdr
->ih_dst
= ip_port
->ip_subnetmask
;
649 ip_hdr_chksum(ip_hdr
, hdr_len
);
651 for (i
=0, ip_fd
= ip_fd_table
; i
<IP_FD_NR
; i
++, ip_fd
++)
653 if (!(ip_fd
->if_flags
& IFF_INUSE
))
657 if (ip_fd
->if_port
!= ip_port
)
662 /* Deliver packet to user */
664 ip_packet2user(ip_fd
, pack
, 255, IP_MIN_HDR_SIZE
);
666 bf_afree(pack
); pack
= NULL
;
670 * $PchId: ip_ioctl.c,v 1.22 2004/08/03 11:10:08 philip Exp $