From 5adca30a18617cc25bc50a9a12e2fe6539412ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 8 Aug 2006 12:33:33 +0000 Subject: [PATCH] Merge of branches/team/network/new_stack - not yet complete as SVN does only support replacing files when merging when you don't have deleted them manually (for some reason, it only works as part of the merge operation, and we didn't copy the whole tree to have "a fresh start" - next time we know better, at least if SVN still suffers from that same limitation). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18456 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 40 +- headers/posix/arpa/inet.h | 80 +- headers/posix/arpa/nameser.h | 236 +- headers/posix/net/if.h | 346 +-- headers/posix/net/if_arp.h | 92 - headers/posix/net/if_dl.h | 46 +- headers/posix/net/if_ppp.h | 129 - headers/posix/net/if_types.h | 32 +- headers/posix/net/radix.h | 165 - headers/posix/net/raw_cb.h | 17 - headers/posix/net/route.h | 232 +- headers/posix/netdb.h | 12 +- headers/posix/netinet/icmp_var.h | 59 - headers/posix/netinet/if_ether.h | 198 -- headers/posix/netinet/in.h | 33 +- headers/posix/netinet/in_pcb.h | 71 - headers/posix/netinet/in_systm.h | 62 - headers/posix/netinet/in_var.h | 66 - headers/posix/netinet/ip.h | 5 +- headers/posix/netinet/ip_icmp.h | 16 +- headers/posix/netinet/tcp_debug.h | 63 - headers/posix/netinet/tcp_fsm.h | 86 - headers/posix/netinet/tcp_seq.h | 67 - headers/posix/netinet/tcp_timer.h | 137 - headers/posix/netinet/tcp_var.h | 282 -- headers/posix/netinet/tcpip.h | 66 - headers/posix/netinet/udp_var.h | 51 - headers/posix/netinet6/in6.h | 30 + headers/posix/resolv.h | 2 +- headers/posix/sys/bitypes.h | 3 - headers/posix/sys/file.h | 6 - headers/posix/sys/filio.h | 40 - headers/posix/sys/ioccom.h | 80 - headers/posix/sys/ioctl.h | 41 +- headers/posix/sys/select.h | 7 +- headers/posix/sys/socket.h | 312 +- headers/posix/sys/sockio.h | 56 + headers/posix/sys/uio.h | 7 +- headers/private/net/core_funcs.h | 110 - headers/private/net/core_module.h | 167 - headers/private/net/ether_driver.h | 71 - headers/private/net/ethernet_module.h | 23 - headers/private/net/icmp_module.h | 19 - headers/private/net/ipv4_module.h | 32 - headers/private/net/lock.h | 128 - headers/private/net/mbuf.h | 311 -- headers/private/net/net_malloc.h | 37 - headers/private/net/net_misc.h | 98 - headers/private/net/net_module.h | 41 - headers/private/net/net_socket.h | 79 - headers/private/net/net_stack_driver.h | 169 - headers/private/net/net_timer.h | 26 - headers/private/net/netconfig.h | 81 - headers/private/net/netdebug.h | 72 - headers/private/net/netgroup.h | 24 - headers/private/net/nhash.h | 40 - headers/private/net/pools.h | 55 - headers/private/net/protocols.h | 48 - headers/private/net/raw_module.h | 20 - headers/private/net/sys/domain.h | 35 - headers/private/net/sys/protosw.h | 156 - headers/private/net/sys/socketvar.h | 155 - headers/private/net/sys/sockio.h | 45 - headers/private/net/userland_ipc.h | 65 - .../kernel/drivers/network/stack/Jamfile | 26 +- .../drivers/network/stack/kernel_stack.cpp | 778 +++++ .../drivers/network/stack/net_stack_driver.c | 709 ----- ...et_server_driver.c => userland_server.cpp} | 177 +- src/add-ons/kernel/network/Jamfile | 6 +- src/add-ons/kernel/network/core/Jamfile | 40 - src/add-ons/kernel/network/core/cksum.c | 123 - src/add-ons/kernel/network/core/core.c | 1117 ------- .../kernel/network/core/core_private.h | 40 - src/add-ons/kernel/network/core/if.c | 499 --- src/add-ons/kernel/network/core/ifq.c | 55 - src/add-ons/kernel/network/core/in.c | 537 ---- src/add-ons/kernel/network/core/inpcb.c | 469 --- src/add-ons/kernel/network/core/mbuf.c | 530 ---- src/add-ons/kernel/network/core/misc.c | 60 - src/add-ons/kernel/network/core/net_timer.c | 224 -- src/add-ons/kernel/network/core/nhash.c | 157 - src/add-ons/kernel/network/core/pools.c | 324 -- src/add-ons/kernel/network/core/radix.c | 1092 ------- src/add-ons/kernel/network/core/route.c | 430 --- src/add-ons/kernel/network/core/sockbuf.c | 308 -- src/add-ons/kernel/network/core/socket.c | 1589 ---------- src/add-ons/kernel/network/interfaces/Jamfile | 5 - .../network/interfaces/ethernet/Jamfile | 24 - .../network/interfaces/ethernet/ethernet.c | 1054 ------- .../network/interfaces/loopback/Jamfile | 24 - .../network/interfaces/loopback/loopback.c | 176 -- .../kernel/network/interfaces/ppp/Jamfile | 39 - .../network/interfaces/ppp/PPPManager.cpp | 862 ------ .../network/interfaces/ppp/PPPManager.h | 85 - .../kernel/network/interfaces/ppp/ppp.cpp | 268 -- src/add-ons/kernel/network/protocols/Jamfile | 9 - .../kernel/network/protocols/icmp/Jamfile | 24 - .../kernel/network/protocols/icmp/icmp.c | 466 --- .../kernel/network/protocols/ipv4/Jamfile | 24 - .../kernel/network/protocols/ipv4/ipv4.c | 1249 -------- .../kernel/network/protocols/raw/Jamfile | 24 - .../kernel/network/protocols/raw/raw.c | 346 --- .../kernel/network/protocols/route/Jamfile | 24 - .../kernel/network/protocols/route/route.c | 786 ----- .../kernel/network/protocols/tcp/Jamfile | 29 - .../kernel/network/protocols/tcp/arc4random.c | 151 - .../kernel/network/protocols/tcp/tcp.c | 585 ---- .../kernel/network/protocols/tcp/tcp_debug.c | 210 -- .../kernel/network/protocols/tcp/tcp_input.c | 1739 ----------- .../kernel/network/protocols/tcp/tcp_output.c | 454 --- .../kernel/network/protocols/tcp/tcp_timer.c | 185 -- .../kernel/network/protocols/udp/Jamfile | 24 - .../kernel/network/protocols/udp/udp.c | 425 --- src/bin/Jamfile | 10 +- src/bin/arp/arp.c | 633 ---- src/bin/ifconfig/ifconfig.c | 628 ---- src/bin/network/Jamfile | 10 + src/bin/{ => network}/arp/Jamfile | 8 +- src/bin/network/arp/arp.cpp | 461 +++ src/bin/network/ftp/Jamfile | 41 + src/bin/network/ftp/Makefile | 28 + src/bin/network/ftp/Makefile.in | 43 + src/bin/network/ftp/cmds.c | 2746 +++++++++++++++++ src/bin/network/ftp/cmdtab.c | 302 ++ src/bin/network/ftp/complete.c | 432 +++ src/bin/network/ftp/config.h | 276 ++ src/bin/network/ftp/domacro.c | 136 + src/bin/network/ftp/extern.h | 259 ++ src/bin/network/ftp/fetch.c | 1831 +++++++++++ src/bin/network/ftp/ftp.1 | 2357 ++++++++++++++ src/bin/network/ftp/ftp.c | 2163 +++++++++++++ src/bin/network/ftp/ftp_var.h | 342 ++ src/bin/network/ftp/main.c | 1039 +++++++ src/bin/network/ftp/progressbar.c | 461 +++ src/bin/network/ftp/progressbar.h | 99 + src/bin/network/ftp/ruserpass.c | 286 ++ src/bin/network/ftp/util.c | 1397 +++++++++ src/bin/network/ftp/version.h | 44 + src/bin/{ => network}/ifconfig/Jamfile | 8 +- src/bin/network/ifconfig/ifconfig.cpp | 672 ++++ src/bin/{ => network}/ping/Jamfile | 4 +- src/bin/{ => network}/ping/ping.c | 10 +- .../{ => network}/ppp_up/ConnectionView.cpp | 0 src/bin/{ => network}/ppp_up/ConnectionView.h | 0 .../{ => network}/ppp_up/ConnectionWindow.cpp | 0 .../{ => network}/ppp_up/ConnectionWindow.h | 0 src/bin/{ => network}/ppp_up/Jamfile | 0 .../ppp_up/PPPDeskbarReplicant.cpp | 0 .../ppp_up/PPPDeskbarReplicant.h | 0 .../{ => network}/ppp_up/PPPStatusView.cpp | 0 src/bin/{ => network}/ppp_up/PPPStatusView.h | 0 .../{ => network}/ppp_up/PPPStatusWindow.cpp | 0 .../{ => network}/ppp_up/PPPStatusWindow.h | 0 .../{ => network}/ppp_up/PPPUpApplication.cpp | 0 .../{ => network}/ppp_up/PPPUpApplication.h | 0 src/bin/{ => network}/ppp_up/ppp_up.rdef | 0 src/bin/{ => network}/pppconfig/Jamfile | 0 src/bin/{ => network}/pppconfig/pppconfig.cpp | 0 src/bin/network/route/Jamfile | 30 + src/bin/network/route/route.cpp | 471 +++ src/bin/{ => network}/traceroute/Jamfile | 7 +- .../network/traceroute}/arc4random.c | 9 +- src/bin/{ => network}/traceroute/traceroute.c | 32 +- src/bin/route/Jamfile | 34 - src/bin/route/keywords.c | 58 - src/bin/route/keywords.h | 57 - src/bin/route/route.c | 1512 --------- src/bin/route/show.c | 381 --- .../network/{libnetwork => }/dns/DEVNOTES | 0 src/kits/network/{libnetwork => }/dns/Jamfile | 13 +- .../network/{compat/libbind => dns}/config.h | 0 .../{libnetwork => }/dns/dst/dst_api.c | 6 +- .../{libnetwork => }/dns/dst/dst_internal.h | 6 +- .../{libnetwork => }/dns/dst/hmac_link.c | 6 +- .../network/{libnetwork => }/dns/dst/md5.h | 0 .../{libnetwork => }/dns/dst/md5_dgst.c | 0 .../{libnetwork => }/dns/dst/md5_locl.h | 0 .../{libnetwork => }/dns/dst/support.c | 5 +- .../libbind => dns}/headers/fd_setsize.h | 0 .../kits/network/dns/headers}/hesiod.h | 0 .../{compat/libbind => dns}/headers/irp.h | 0 .../{compat/libbind => dns}/headers/irs.h | 0 .../libbind => dns}/headers/isc/assertions.h | 0 .../{compat/libbind => dns}/headers/isc/ctl.h | 0 .../{compat/libbind => dns}/headers/isc/dst.h | 0 .../libbind => dns}/headers/isc/eventlib.h | 0 .../libbind => dns}/headers/isc/heap.h | 0 .../libbind => dns}/headers/isc/irpmarshall.h | 0 .../libbind => dns}/headers/isc/list.h | 0 .../libbind => dns}/headers/isc/logging.h | 0 .../libbind => dns}/headers/isc/memcluster.h | 0 .../libbind => dns}/headers/isc/misc.h | 0 .../libbind => dns}/headers/isc/tree.h | 0 .../network/dns/headers}/nameser_compat.h | 0 .../dns/headers/pthread_emu.h | 0 .../libbind => dns}/headers/res_update.h | 0 .../{compat/libbind => dns}/headers/sys/un.h | 0 .../{compat/libbind => dns}/headers/utmp.h | 0 .../{libnetwork => }/dns/inet/inet_addr.c | 0 .../dns/inet/inet_cidr_ntop.c | 0 .../dns/inet/inet_cidr_pton.c | 0 .../{libnetwork => }/dns/inet/inet_data.c | 0 .../{libnetwork => }/dns/inet/inet_lnaof.c | 0 .../{libnetwork => }/dns/inet/inet_makeaddr.c | 0 .../{libnetwork => }/dns/inet/inet_net_ntop.c | 0 .../{libnetwork => }/dns/inet/inet_net_pton.c | 0 .../{libnetwork => }/dns/inet/inet_neta.c | 0 .../{libnetwork => }/dns/inet/inet_netof.c | 0 .../{libnetwork => }/dns/inet/inet_network.c | 0 .../{libnetwork => }/dns/inet/inet_ntoa.c | 0 .../{libnetwork => }/dns/inet/inet_ntop.c | 0 .../{libnetwork => }/dns/inet/inet_pton.c | 0 .../{libnetwork => }/dns/inet/nsap_addr.c | 0 .../network/{libnetwork => }/dns/irs/dns.c | 0 .../network/{libnetwork => }/dns/irs/dns_ho.c | 0 .../network/{libnetwork => }/dns/irs/dns_nw.c | 0 .../network/{libnetwork => }/dns/irs/dns_p.h | 0 .../network/{libnetwork => }/dns/irs/dns_pr.c | 0 .../network/{libnetwork => }/dns/irs/dns_sv.c | 0 .../{libnetwork => }/dns/irs/gai_strerror.c | 5 +- .../network/{libnetwork => }/dns/irs/gen.c | 0 .../network/{libnetwork => }/dns/irs/gen_ho.c | 0 .../network/{libnetwork => }/dns/irs/gen_ng.c | 0 .../network/{libnetwork => }/dns/irs/gen_nw.c | 0 .../network/{libnetwork => }/dns/irs/gen_p.h | 0 .../network/{libnetwork => }/dns/irs/gen_pr.c | 0 .../network/{libnetwork => }/dns/irs/gen_sv.c | 0 .../{libnetwork => }/dns/irs/getaddrinfo.c | 0 .../{libnetwork => }/dns/irs/gethostent.c | 0 .../{libnetwork => }/dns/irs/gethostent_r.c | 0 .../{libnetwork => }/dns/irs/getnameinfo.c | 4 +- .../{libnetwork => }/dns/irs/getnetent.c | 0 .../{libnetwork => }/dns/irs/getnetent_r.c | 0 .../{libnetwork => }/dns/irs/getnetgrent.c | 0 .../{libnetwork => }/dns/irs/getnetgrent_r.c | 0 .../{libnetwork => }/dns/irs/getprotoent.c | 0 .../{libnetwork => }/dns/irs/getprotoent_r.c | 0 .../{libnetwork => }/dns/irs/getservent.c | 0 .../{libnetwork => }/dns/irs/getservent_r.c | 0 .../network/{libnetwork => }/dns/irs/hesiod.c | 0 .../{libnetwork => }/dns/irs/hesiod_p.h | 0 .../network/{libnetwork => }/dns/irs/irp.c | 0 .../network/{libnetwork => }/dns/irs/irp_ho.c | 0 .../network/{libnetwork => }/dns/irs/irp_ng.c | 0 .../network/{libnetwork => }/dns/irs/irp_nw.c | 0 .../network/{libnetwork => }/dns/irs/irp_p.h | 0 .../network/{libnetwork => }/dns/irs/irp_pr.c | 0 .../network/{libnetwork => }/dns/irs/irp_sv.c | 0 .../{libnetwork => }/dns/irs/irpmarshall.c | 0 .../{libnetwork => }/dns/irs/irs_data.c | 3 +- .../{libnetwork => }/dns/irs/irs_data.h | 0 .../network/{libnetwork => }/dns/irs/irs_p.h | 0 .../network/{libnetwork => }/dns/irs/lcl.c | 0 .../network/{libnetwork => }/dns/irs/lcl_ho.c | 0 .../network/{libnetwork => }/dns/irs/lcl_ng.c | 0 .../network/{libnetwork => }/dns/irs/lcl_nw.c | 0 .../network/{libnetwork => }/dns/irs/lcl_p.h | 0 .../network/{libnetwork => }/dns/irs/lcl_pr.c | 291 +- .../network/{libnetwork => }/dns/irs/lcl_sv.c | 0 .../network/{libnetwork => }/dns/irs/nis.c | 0 .../network/{libnetwork => }/dns/irs/nis_p.h | 0 .../network/{libnetwork => }/dns/irs/nul_ng.c | 0 .../{libnetwork => }/dns/irs/pathnames.h | 0 .../network/{libnetwork => }/dns/irs/util.c | 0 .../{libnetwork => }/dns/isc/assertions.c | 0 .../network/{libnetwork => }/dns/isc/base64.c | 0 .../{libnetwork => }/dns/isc/bitncmp.c | 0 .../{libnetwork => }/dns/isc/ctl_clnt.c | 5 - .../network/{libnetwork => }/dns/isc/ctl_p.c | 5 - .../network/{libnetwork => }/dns/isc/ctl_p.h | 0 .../{libnetwork => }/dns/isc/ctl_srvr.c | 5 - .../{libnetwork => }/dns/isc/ev_connects.c | 0 .../{libnetwork => }/dns/isc/ev_files.c | 0 .../{libnetwork => }/dns/isc/ev_streams.c | 0 .../{libnetwork => }/dns/isc/ev_timers.c | 0 .../{libnetwork => }/dns/isc/ev_waits.c | 0 .../{libnetwork => }/dns/isc/eventlib.c | 0 .../{libnetwork => }/dns/isc/eventlib_p.h | 0 .../network/{libnetwork => }/dns/isc/heap.c | 0 .../network/{libnetwork => }/dns/isc/hex.c | 0 .../{libnetwork => }/dns/isc/logging.c | 0 .../{libnetwork => }/dns/isc/logging_p.h | 0 .../{libnetwork => }/dns/isc/memcluster.c | 0 .../{libnetwork => }/dns/isc/movefile.c | 0 .../network/{libnetwork => }/dns/isc/tree.c | 0 .../{libnetwork => }/dns/nameser/ns_date.c | 0 .../{libnetwork => }/dns/nameser/ns_name.c | 0 .../{libnetwork => }/dns/nameser/ns_netint.c | 0 .../{libnetwork => }/dns/nameser/ns_parse.c | 0 .../{libnetwork => }/dns/nameser/ns_print.c | 0 .../dns/nameser/ns_samedomain.c | 0 .../{libnetwork => }/dns/nameser/ns_sign.c | 0 .../{libnetwork => }/dns/nameser/ns_ttl.c | 0 .../{libnetwork => }/dns/nameser/ns_verify.c | 0 .../network/{libnetwork => }/dns/port_after.h | 21 +- .../{libnetwork => }/dns/port_before.h | 0 .../{libnetwork => }/dns/resolv/herror.c | 0 .../{libnetwork => }/dns/resolv/res_comp.c | 0 .../{libnetwork => }/dns/resolv/res_data.c | 0 .../{libnetwork => }/dns/resolv/res_debug.c | 4 +- .../{libnetwork => }/dns/resolv/res_debug.h | 0 .../dns/resolv/res_findzonecut.c | 0 .../{libnetwork => }/dns/resolv/res_init.c | 0 .../{libnetwork => }/dns/resolv/res_mkquery.c | 0 .../dns/resolv/res_mkupdate.c | 0 .../dns/resolv/res_mkupdate.h | 0 .../{libnetwork => }/dns/resolv/res_private.h | 0 .../{libnetwork => }/dns/resolv/res_query.c | 0 .../{libnetwork => }/dns/resolv/res_send.c | 0 .../dns/resolv/res_sendsigned.c | 0 .../{libnetwork => }/dns/resolv/res_update.c | 0 .../{libnetwork => }/dns/src/TLSInit.cpp | 0 .../{compat/libnet => dns/src}/ethers.c | 0 .../{libnetwork => }/dns/src/gettimeofday.c | 0 .../{libnetwork => }/dns/src/linkaddr.c | 0 .../dns/src/res_resultcodes.c | 0 .../network/{libnetwork => }/dns/src/strsep.c | 0 src/kits/network/interfaces.cpp | 126 + src/kits/network/libnetwork/Jamfile | 37 - src/kits/network/libnetwork/socket/DEVNOTES | 3 - src/kits/network/libnetwork/socket/Jamfile | 10 - src/kits/network/libnetwork/socket/socket.c | 371 --- src/kits/network/{ => old}/Jamfile | 0 src/kits/network/{ => old}/README.html | 0 src/kits/network/{ => old}/compat/Jamfile | 0 .../network/{ => old}/compat/libbind/DEVNOTES | 0 .../network/{ => old}/compat/libbind/Jamfile | 0 .../dns => old/compat/libbind}/config.h | 0 .../compat/libbind}/headers/fd_setsize.h | 0 .../dns => old/compat/libbind}/headers/irp.h | 0 .../dns => old/compat/libbind}/headers/irs.h | 0 .../compat/libbind}/headers/isc/assertions.h | 0 .../compat/libbind}/headers/isc/ctl.h | 0 .../compat/libbind}/headers/isc/dst.h | 0 .../compat/libbind}/headers/isc/eventlib.h | 0 .../compat/libbind}/headers/isc/heap.h | 0 .../compat/libbind}/headers/isc/irpmarshall.h | 0 .../compat/libbind}/headers/isc/list.h | 0 .../compat/libbind}/headers/isc/logging.h | 0 .../compat/libbind}/headers/isc/memcluster.h | 0 .../compat/libbind}/headers/isc/misc.h | 0 .../compat/libbind}/headers/isc/tree.h | 0 .../compat/libbind}/headers/res_update.h | 0 .../compat/libbind}/headers/sys/un.h | 0 .../dns => old/compat/libbind}/headers/utmp.h | 0 .../{ => old}/compat/libbind/port_after.h | 0 .../{ => old}/compat/libbind/port_before.h | 0 .../network/{ => old}/compat/libnet/Jamfile | 0 .../{ => old}/compat/libnet/arc4random.c | 0 .../network/{ => old}/compat/libnet/base64.c | 0 .../network/{ => old}/compat/libnet/compat.c | 0 .../dns/src => old/compat/libnet}/ethers.c | 0 .../{ => old}/compat/libnet/freeaddrinfo.c | 0 .../{ => old}/compat/libnet/getaddrinfo.c | 0 .../{ => old}/compat/libnet/gethostnamadr.c | 0 .../{ => old}/compat/libnet/getnameinfo.c | 0 .../{ => old}/compat/libnet/getnetbyaddr.c | 0 .../{ => old}/compat/libnet/getnetbyname.c | 0 .../{ => old}/compat/libnet/getnetent.c | 0 .../{ => old}/compat/libnet/getnetnamadr.c | 0 .../{ => old}/compat/libnet/getproto.c | 0 .../{ => old}/compat/libnet/getprotoent.c | 0 .../{ => old}/compat/libnet/getprotoname.c | 0 .../{ => old}/compat/libnet/getservbyname.c | 0 .../{ => old}/compat/libnet/getservbyport.c | 0 .../{ => old}/compat/libnet/getservent.c | 0 .../compat/libnet/headers/arpa/inet.h | 0 .../compat/libnet/headers/arpa/nameser.h | 0 .../{ => old}/compat/libnet/headers/netdb.h | 0 .../{ => old}/compat/libnet/headers/resolv.h | 0 .../{ => old}/compat/libnet/inet_addr.c | 0 .../{ => old}/compat/libnet/inet_lnaof.c | 0 .../{ => old}/compat/libnet/inet_neta.c | 0 .../{ => old}/compat/libnet/inet_netof.c | 0 .../{ => old}/compat/libnet/inet_network.c | 0 .../{ => old}/compat/libnet/inet_ntoa.c | 0 .../{ => old}/compat/libnet/inet_ntop.c | 0 .../{ => old}/compat/libnet/inet_pton.c | 0 .../{ => old}/compat/libnet/linkaddr.c | 0 .../{ => old}/compat/libnet/netconfig.c | 0 .../{ => old}/compat/libnet/netdebug.c | 0 .../network/{ => old}/compat/libnet/networks | 0 .../network/{ => old}/compat/libnet/poll.c | 0 .../network/{ => old}/compat/libnet/protocols | 0 .../{ => old}/compat/libnet/res_comp.c | 0 .../{ => old}/compat/libnet/res_data.c | 0 .../{ => old}/compat/libnet/res_debug.c | 0 .../{ => old}/compat/libnet/res_init.c | 0 .../{ => old}/compat/libnet/res_mkquery.c | 0 .../{ => old}/compat/libnet/res_query.c | 0 .../{ => old}/compat/libnet/res_random.c | 0 .../{ => old}/compat/libnet/res_send.c | 0 .../{ => old}/compat/libnet/resolv.conf | 0 .../network/{ => old}/compat/libnet/select.c | 0 .../network/{ => old}/compat/libnet/services | 0 .../{ => old}/compat/libnet/sethostent.c | 0 .../network/{ => old}/compat/libnet/socket.c | 0 .../{ => old}/compat/libnetapi/Jamfile | 0 .../{ => old}/compat/libnetapi/NetAddress.cpp | 0 .../{ => old}/compat/libnetapi/NetBuffer.cpp | 0 .../{ => old}/compat/libnetapi/NetDebug.cpp | 0 .../compat/libnetapi/NetEndpoint.cpp | 0 .../{ => old}/compat/libsocket/Jamfile | 0 .../{ => old}/compat/libsocket/socket.c | 0 src/kits/network/{ => old}/install.sh | 0 src/kits/network/socket.cpp | 310 ++ 406 files changed, 17948 insertions(+), 26566 deletions(-) delete mode 100644 headers/posix/net/if_arp.h delete mode 100644 headers/posix/net/if_ppp.h delete mode 100644 headers/posix/net/radix.h delete mode 100644 headers/posix/net/raw_cb.h delete mode 100644 headers/posix/netinet/icmp_var.h delete mode 100644 headers/posix/netinet/if_ether.h delete mode 100644 headers/posix/netinet/in_pcb.h delete mode 100644 headers/posix/netinet/in_systm.h delete mode 100644 headers/posix/netinet/in_var.h delete mode 100644 headers/posix/netinet/tcp_debug.h delete mode 100644 headers/posix/netinet/tcp_fsm.h delete mode 100644 headers/posix/netinet/tcp_seq.h delete mode 100644 headers/posix/netinet/tcp_timer.h delete mode 100644 headers/posix/netinet/tcp_var.h delete mode 100644 headers/posix/netinet/tcpip.h delete mode 100644 headers/posix/netinet/udp_var.h create mode 100644 headers/posix/netinet6/in6.h delete mode 100644 headers/posix/sys/bitypes.h delete mode 100644 headers/posix/sys/file.h delete mode 100644 headers/posix/sys/filio.h delete mode 100644 headers/posix/sys/ioccom.h create mode 100644 headers/posix/sys/sockio.h delete mode 100644 headers/private/net/core_funcs.h delete mode 100644 headers/private/net/core_module.h delete mode 100644 headers/private/net/ether_driver.h delete mode 100644 headers/private/net/ethernet_module.h delete mode 100644 headers/private/net/icmp_module.h delete mode 100644 headers/private/net/ipv4_module.h delete mode 100644 headers/private/net/lock.h delete mode 100644 headers/private/net/mbuf.h delete mode 100644 headers/private/net/net_malloc.h delete mode 100644 headers/private/net/net_misc.h delete mode 100644 headers/private/net/net_module.h delete mode 100644 headers/private/net/net_socket.h delete mode 100644 headers/private/net/net_stack_driver.h delete mode 100644 headers/private/net/net_timer.h delete mode 100644 headers/private/net/netconfig.h delete mode 100644 headers/private/net/netdebug.h delete mode 100644 headers/private/net/netgroup.h delete mode 100644 headers/private/net/nhash.h delete mode 100644 headers/private/net/pools.h delete mode 100644 headers/private/net/protocols.h delete mode 100644 headers/private/net/raw_module.h delete mode 100644 headers/private/net/sys/domain.h delete mode 100644 headers/private/net/sys/protosw.h delete mode 100644 headers/private/net/sys/socketvar.h delete mode 100644 headers/private/net/sys/sockio.h delete mode 100644 headers/private/net/userland_ipc.h create mode 100644 src/add-ons/kernel/drivers/network/stack/kernel_stack.cpp delete mode 100644 src/add-ons/kernel/drivers/network/stack/net_stack_driver.c rename src/add-ons/kernel/drivers/network/stack/{net_server_driver.c => userland_server.cpp} (85%) delete mode 100644 src/add-ons/kernel/network/core/Jamfile delete mode 100644 src/add-ons/kernel/network/core/cksum.c delete mode 100644 src/add-ons/kernel/network/core/core.c delete mode 100644 src/add-ons/kernel/network/core/core_private.h delete mode 100644 src/add-ons/kernel/network/core/if.c delete mode 100644 src/add-ons/kernel/network/core/ifq.c delete mode 100644 src/add-ons/kernel/network/core/in.c delete mode 100644 src/add-ons/kernel/network/core/inpcb.c delete mode 100644 src/add-ons/kernel/network/core/mbuf.c delete mode 100644 src/add-ons/kernel/network/core/misc.c delete mode 100644 src/add-ons/kernel/network/core/net_timer.c delete mode 100644 src/add-ons/kernel/network/core/nhash.c delete mode 100644 src/add-ons/kernel/network/core/pools.c delete mode 100644 src/add-ons/kernel/network/core/radix.c delete mode 100644 src/add-ons/kernel/network/core/route.c delete mode 100644 src/add-ons/kernel/network/core/sockbuf.c delete mode 100644 src/add-ons/kernel/network/core/socket.c delete mode 100644 src/add-ons/kernel/network/interfaces/Jamfile delete mode 100644 src/add-ons/kernel/network/interfaces/ethernet/Jamfile delete mode 100644 src/add-ons/kernel/network/interfaces/ethernet/ethernet.c delete mode 100644 src/add-ons/kernel/network/interfaces/loopback/Jamfile delete mode 100644 src/add-ons/kernel/network/interfaces/loopback/loopback.c delete mode 100644 src/add-ons/kernel/network/interfaces/ppp/Jamfile delete mode 100644 src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp delete mode 100644 src/add-ons/kernel/network/interfaces/ppp/PPPManager.h delete mode 100644 src/add-ons/kernel/network/interfaces/ppp/ppp.cpp delete mode 100644 src/add-ons/kernel/network/protocols/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/icmp/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/icmp/icmp.c delete mode 100644 src/add-ons/kernel/network/protocols/ipv4/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/ipv4/ipv4.c delete mode 100644 src/add-ons/kernel/network/protocols/raw/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/raw/raw.c delete mode 100644 src/add-ons/kernel/network/protocols/route/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/route/route.c delete mode 100644 src/add-ons/kernel/network/protocols/tcp/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/tcp/arc4random.c delete mode 100644 src/add-ons/kernel/network/protocols/tcp/tcp.c delete mode 100644 src/add-ons/kernel/network/protocols/tcp/tcp_debug.c delete mode 100644 src/add-ons/kernel/network/protocols/tcp/tcp_input.c delete mode 100644 src/add-ons/kernel/network/protocols/tcp/tcp_output.c delete mode 100644 src/add-ons/kernel/network/protocols/tcp/tcp_timer.c delete mode 100644 src/add-ons/kernel/network/protocols/udp/Jamfile delete mode 100644 src/add-ons/kernel/network/protocols/udp/udp.c delete mode 100644 src/bin/arp/arp.c delete mode 100644 src/bin/ifconfig/ifconfig.c create mode 100644 src/bin/network/Jamfile rename src/bin/{ => network}/arp/Jamfile (83%) create mode 100644 src/bin/network/arp/arp.cpp create mode 100644 src/bin/network/ftp/Jamfile create mode 100644 src/bin/network/ftp/Makefile create mode 100644 src/bin/network/ftp/Makefile.in create mode 100644 src/bin/network/ftp/cmds.c create mode 100644 src/bin/network/ftp/cmdtab.c create mode 100644 src/bin/network/ftp/complete.c create mode 100644 src/bin/network/ftp/config.h create mode 100644 src/bin/network/ftp/domacro.c create mode 100644 src/bin/network/ftp/extern.h create mode 100644 src/bin/network/ftp/fetch.c create mode 100644 src/bin/network/ftp/ftp.1 create mode 100644 src/bin/network/ftp/ftp.c create mode 100644 src/bin/network/ftp/ftp_var.h create mode 100644 src/bin/network/ftp/main.c create mode 100644 src/bin/network/ftp/progressbar.c create mode 100644 src/bin/network/ftp/progressbar.h create mode 100644 src/bin/network/ftp/ruserpass.c create mode 100644 src/bin/network/ftp/util.c create mode 100644 src/bin/network/ftp/version.h rename src/bin/{ => network}/ifconfig/Jamfile (83%) create mode 100644 src/bin/network/ifconfig/ifconfig.cpp rename src/bin/{ => network}/ping/Jamfile (93%) rename src/bin/{ => network}/ping/ping.c (99%) rename src/bin/{ => network}/ppp_up/ConnectionView.cpp (100%) rename src/bin/{ => network}/ppp_up/ConnectionView.h (100%) rename src/bin/{ => network}/ppp_up/ConnectionWindow.cpp (100%) rename src/bin/{ => network}/ppp_up/ConnectionWindow.h (100%) rename src/bin/{ => network}/ppp_up/Jamfile (100%) rename src/bin/{ => network}/ppp_up/PPPDeskbarReplicant.cpp (100%) rename src/bin/{ => network}/ppp_up/PPPDeskbarReplicant.h (100%) rename src/bin/{ => network}/ppp_up/PPPStatusView.cpp (100%) rename src/bin/{ => network}/ppp_up/PPPStatusView.h (100%) rename src/bin/{ => network}/ppp_up/PPPStatusWindow.cpp (100%) rename src/bin/{ => network}/ppp_up/PPPStatusWindow.h (100%) rename src/bin/{ => network}/ppp_up/PPPUpApplication.cpp (100%) rename src/bin/{ => network}/ppp_up/PPPUpApplication.h (100%) rename src/bin/{ => network}/ppp_up/ppp_up.rdef (100%) rename src/bin/{ => network}/pppconfig/Jamfile (100%) rename src/bin/{ => network}/pppconfig/pppconfig.cpp (100%) create mode 100644 src/bin/network/route/Jamfile create mode 100644 src/bin/network/route/route.cpp rename src/bin/{ => network}/traceroute/Jamfile (87%) rename src/{kits/network/libnetwork/dns/src => bin/network/traceroute}/arc4random.c (96%) rename src/bin/{ => network}/traceroute/traceroute.c (97%) delete mode 100644 src/bin/route/Jamfile delete mode 100644 src/bin/route/keywords.c delete mode 100644 src/bin/route/keywords.h delete mode 100644 src/bin/route/route.c delete mode 100644 src/bin/route/show.c rename src/kits/network/{libnetwork => }/dns/DEVNOTES (100%) rename src/kits/network/{libnetwork => }/dns/Jamfile (91%) rename src/kits/network/{compat/libbind => dns}/config.h (100%) rename src/kits/network/{libnetwork => }/dns/dst/dst_api.c (99%) rename src/kits/network/{libnetwork => }/dns/dst/dst_internal.h (97%) rename src/kits/network/{libnetwork => }/dns/dst/hmac_link.c (99%) rename src/kits/network/{libnetwork => }/dns/dst/md5.h (100%) rename src/kits/network/{libnetwork => }/dns/dst/md5_dgst.c (100%) rename src/kits/network/{libnetwork => }/dns/dst/md5_locl.h (100%) rename src/kits/network/{libnetwork => }/dns/dst/support.c (97%) rename src/kits/network/{compat/libbind => dns}/headers/fd_setsize.h (100%) rename {headers/private/net => src/kits/network/dns/headers}/hesiod.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/irp.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/irs.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/assertions.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/ctl.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/dst.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/eventlib.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/heap.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/irpmarshall.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/list.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/logging.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/memcluster.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/misc.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/isc/tree.h (100%) rename {headers/posix/arpa => src/kits/network/dns/headers}/nameser_compat.h (100%) rename src/kits/network/{libnetwork => }/dns/headers/pthread_emu.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/res_update.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/sys/un.h (100%) rename src/kits/network/{compat/libbind => dns}/headers/utmp.h (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_addr.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_cidr_ntop.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_cidr_pton.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_data.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_lnaof.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_makeaddr.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_net_ntop.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_net_pton.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_neta.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_netof.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_network.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_ntoa.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_ntop.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/inet_pton.c (100%) rename src/kits/network/{libnetwork => }/dns/inet/nsap_addr.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/dns.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/dns_ho.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/dns_nw.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/dns_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/dns_pr.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/dns_sv.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gai_strerror.c (97%) rename src/kits/network/{libnetwork => }/dns/irs/gen.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gen_ho.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gen_ng.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gen_nw.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gen_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/gen_pr.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gen_sv.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getaddrinfo.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gethostent.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/gethostent_r.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getnameinfo.c (98%) rename src/kits/network/{libnetwork => }/dns/irs/getnetent.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getnetent_r.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getnetgrent.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getnetgrent_r.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getprotoent.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getprotoent_r.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getservent.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/getservent_r.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/hesiod.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/hesiod_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp_ho.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp_ng.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp_nw.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp_pr.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irp_sv.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irpmarshall.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/irs_data.c (99%) rename src/kits/network/{libnetwork => }/dns/irs/irs_data.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/irs_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/lcl.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/lcl_ho.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/lcl_ng.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/lcl_nw.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/lcl_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/lcl_pr.c (53%) rename src/kits/network/{libnetwork => }/dns/irs/lcl_sv.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/nis.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/nis_p.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/nul_ng.c (100%) rename src/kits/network/{libnetwork => }/dns/irs/pathnames.h (100%) rename src/kits/network/{libnetwork => }/dns/irs/util.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/assertions.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/base64.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/bitncmp.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/ctl_clnt.c (99%) rename src/kits/network/{libnetwork => }/dns/isc/ctl_p.c (97%) rename src/kits/network/{libnetwork => }/dns/isc/ctl_p.h (100%) rename src/kits/network/{libnetwork => }/dns/isc/ctl_srvr.c (99%) rename src/kits/network/{libnetwork => }/dns/isc/ev_connects.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/ev_files.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/ev_streams.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/ev_timers.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/ev_waits.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/eventlib.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/eventlib_p.h (100%) rename src/kits/network/{libnetwork => }/dns/isc/heap.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/hex.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/logging.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/logging_p.h (100%) rename src/kits/network/{libnetwork => }/dns/isc/memcluster.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/movefile.c (100%) rename src/kits/network/{libnetwork => }/dns/isc/tree.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_date.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_name.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_netint.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_parse.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_print.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_samedomain.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_sign.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_ttl.c (100%) rename src/kits/network/{libnetwork => }/dns/nameser/ns_verify.c (100%) rename src/kits/network/{libnetwork => }/dns/port_after.h (96%) rename src/kits/network/{libnetwork => }/dns/port_before.h (100%) rename src/kits/network/{libnetwork => }/dns/resolv/herror.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_comp.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_data.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_debug.c (99%) rename src/kits/network/{libnetwork => }/dns/resolv/res_debug.h (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_findzonecut.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_init.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_mkquery.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_mkupdate.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_mkupdate.h (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_private.h (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_query.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_send.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_sendsigned.c (100%) rename src/kits/network/{libnetwork => }/dns/resolv/res_update.c (100%) rename src/kits/network/{libnetwork => }/dns/src/TLSInit.cpp (100%) rename src/kits/network/{compat/libnet => dns/src}/ethers.c (100%) rename src/kits/network/{libnetwork => }/dns/src/gettimeofday.c (100%) rename src/kits/network/{libnetwork => }/dns/src/linkaddr.c (100%) rename src/kits/network/{libnetwork => }/dns/src/res_resultcodes.c (100%) rename src/kits/network/{libnetwork => }/dns/src/strsep.c (100%) create mode 100644 src/kits/network/interfaces.cpp delete mode 100644 src/kits/network/libnetwork/Jamfile delete mode 100644 src/kits/network/libnetwork/socket/DEVNOTES delete mode 100644 src/kits/network/libnetwork/socket/Jamfile delete mode 100644 src/kits/network/libnetwork/socket/socket.c rename src/kits/network/{ => old}/Jamfile (100%) rename src/kits/network/{ => old}/README.html (100%) rename src/kits/network/{ => old}/compat/Jamfile (100%) rename src/kits/network/{ => old}/compat/libbind/DEVNOTES (100%) rename src/kits/network/{ => old}/compat/libbind/Jamfile (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/config.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/fd_setsize.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/irp.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/irs.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/assertions.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/ctl.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/dst.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/eventlib.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/heap.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/irpmarshall.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/list.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/logging.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/memcluster.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/misc.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/isc/tree.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/res_update.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/sys/un.h (100%) rename src/kits/network/{libnetwork/dns => old/compat/libbind}/headers/utmp.h (100%) rename src/kits/network/{ => old}/compat/libbind/port_after.h (100%) rename src/kits/network/{ => old}/compat/libbind/port_before.h (100%) rename src/kits/network/{ => old}/compat/libnet/Jamfile (100%) rename src/kits/network/{ => old}/compat/libnet/arc4random.c (100%) rename src/kits/network/{ => old}/compat/libnet/base64.c (100%) rename src/kits/network/{ => old}/compat/libnet/compat.c (100%) rename src/kits/network/{libnetwork/dns/src => old/compat/libnet}/ethers.c (100%) rename src/kits/network/{ => old}/compat/libnet/freeaddrinfo.c (100%) rename src/kits/network/{ => old}/compat/libnet/getaddrinfo.c (100%) rename src/kits/network/{ => old}/compat/libnet/gethostnamadr.c (100%) rename src/kits/network/{ => old}/compat/libnet/getnameinfo.c (100%) rename src/kits/network/{ => old}/compat/libnet/getnetbyaddr.c (100%) rename src/kits/network/{ => old}/compat/libnet/getnetbyname.c (100%) rename src/kits/network/{ => old}/compat/libnet/getnetent.c (100%) rename src/kits/network/{ => old}/compat/libnet/getnetnamadr.c (100%) rename src/kits/network/{ => old}/compat/libnet/getproto.c (100%) rename src/kits/network/{ => old}/compat/libnet/getprotoent.c (100%) rename src/kits/network/{ => old}/compat/libnet/getprotoname.c (100%) rename src/kits/network/{ => old}/compat/libnet/getservbyname.c (100%) rename src/kits/network/{ => old}/compat/libnet/getservbyport.c (100%) rename src/kits/network/{ => old}/compat/libnet/getservent.c (100%) rename src/kits/network/{ => old}/compat/libnet/headers/arpa/inet.h (100%) rename src/kits/network/{ => old}/compat/libnet/headers/arpa/nameser.h (100%) rename src/kits/network/{ => old}/compat/libnet/headers/netdb.h (100%) rename src/kits/network/{ => old}/compat/libnet/headers/resolv.h (100%) rename src/kits/network/{ => old}/compat/libnet/inet_addr.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_lnaof.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_neta.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_netof.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_network.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_ntoa.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_ntop.c (100%) rename src/kits/network/{ => old}/compat/libnet/inet_pton.c (100%) rename src/kits/network/{ => old}/compat/libnet/linkaddr.c (100%) rename src/kits/network/{ => old}/compat/libnet/netconfig.c (100%) rename src/kits/network/{ => old}/compat/libnet/netdebug.c (100%) rename src/kits/network/{ => old}/compat/libnet/networks (100%) rename src/kits/network/{ => old}/compat/libnet/poll.c (100%) rename src/kits/network/{ => old}/compat/libnet/protocols (100%) rename src/kits/network/{ => old}/compat/libnet/res_comp.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_data.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_debug.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_init.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_mkquery.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_query.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_random.c (100%) rename src/kits/network/{ => old}/compat/libnet/res_send.c (100%) rename src/kits/network/{ => old}/compat/libnet/resolv.conf (100%) rename src/kits/network/{ => old}/compat/libnet/select.c (100%) rename src/kits/network/{ => old}/compat/libnet/services (100%) rename src/kits/network/{ => old}/compat/libnet/sethostent.c (100%) rename src/kits/network/{ => old}/compat/libnet/socket.c (100%) rename src/kits/network/{ => old}/compat/libnetapi/Jamfile (100%) rename src/kits/network/{ => old}/compat/libnetapi/NetAddress.cpp (100%) rename src/kits/network/{ => old}/compat/libnetapi/NetBuffer.cpp (100%) rename src/kits/network/{ => old}/compat/libnetapi/NetDebug.cpp (100%) rename src/kits/network/{ => old}/compat/libnetapi/NetEndpoint.cpp (100%) rename src/kits/network/{ => old}/compat/libsocket/Jamfile (100%) rename src/kits/network/{ => old}/compat/libsocket/socket.c (100%) rename src/kits/network/{ => old}/install.sh (100%) create mode 100644 src/kits/network/socket.cpp diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 886c771d08..bc03a04741 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -22,13 +22,13 @@ if $(INCLUDE_GPL_ADDONS) = 1 { BEOS_BIN = addattr alert basename beep cat catattr chgrp chmod chop chown clear clockconfig cmp comm cp copyattr csplit cut date dd desklink df diff dirname driveinfo - dstcheck du echo eject env error factor false ffm find finddir fortune funzip gawk + dstcheck du echo eject env error factor false ffm find finddir fortune ftp funzip gawk $(X86_ONLY)gdb grep groups gzip head hey id ideinfo idestatus ifconfig iroster isvolume join keymap kill less lessecho lesskey link listarea listattr listdev listimage listport listres listsem ln locate logger logname ls lsindex makebootable md5sum mimeset mkdir mkindex modifiers mount mountvolume mv open pathchk ping play playfile playsound playwav ppp_up pppconfig ps pwd - query quit renice rm rmattr rmindex rmdir roster safemode screen_blanker sed settype + query quit renice rm rmattr rmindex rmdir roster route safemode screen_blanker sed settype setversion setvolume sh shutdown sleep sort split strace su sum sync sysinfo tail tar tee top touch tput traceroute translate true tty uname unmount unzip unzipsfx uptime version waitfor wc whoami xargs xres yes zdiff zforce zgrep zip zipcloak @@ -43,20 +43,20 @@ BEOS_APPS = Terminal Expander People ShowImage Clock Pulse ProcessController BEOS_PREFERENCES = Backgrounds DataTranslations FileTypes Fonts Media Menu Mouse Keyboard Keymap Screen ScreenSaver Sounds Time VirtualMemory ; -BEOS_SYSTEM_LIB = libbe.so $(HAIKU_LIBSTDC++) libnet.so libmedia.so libtracker.so - libtranslation.so libnetwork.so libbind.so libnetapi.so libsocket.so libdebug.so +BEOS_SYSTEM_LIB = libbe.so $(HAIKU_LIBSTDC++) libmedia.so libtracker.so + libtranslation.so libnetwork.so libdebug.so libbsd.so libtextencoding.so libz.so libfreetype.so libpng.so libmidi.so libmidi2.so - libdevice.so libgame.so libscreensaver.so libroot.so libmail.so $(X86_ONLY)libGL.so + libdevice.so libgame.so libscreensaver.so libroot.so $(X86_ONLY)libGL.so libfluidsynth.so ; BEOS_SYSTEM_SERVERS = registrar debug_server syslog_daemon media_server media_addon_server input_server app_server fake_app_server midi_server ; -BEOS_NETWORK_CORE = core ; -BEOS_NETWORK_INTERFACES = ethernet loopback ppp ; -BEOS_NETWORK_PPP = ipcp modem pap pppoe ; -BEOS_NETWORK_PROTOCOLS = icmp ipv4 raw route tcp udp ; +BEOS_NETWORK_DEVICES = ethernet loopback ; +BEOS_NETWORK_DATALINK_PROTOCOLS = ethernet_frame arp ; +#BEOS_NETWORK_PPP = ipcp modem pap pppoe ; +BEOS_NETWORK_PROTOCOLS = ipv4 tcp udp icmp ; BEOS_ADD_ONS_ACCELERANTS = $(X86_ONLY)radeon.accelerant $(X86_ONLY)nv.accelerant $(X86_ONLY)mga.accelerant $(X86_ONLY)nm.accelerant $(X86_ONLY)intel_extreme.accelerant @@ -86,7 +86,7 @@ BEOS_ADD_ONS_DRIVERS_GRAPHICS = $(X86_ONLY)radeon.driver $(X86_ONLY)nv.driver $(X86_ONLY)nm.driver $(X86_ONLY)mga.driver $(X86_ONLY)intel_extreme vesa ; BEOS_ADD_ONS_DRIVERS_NET = etherpci ipro1000 rtl8139 rtl8169 sis900 - via-rhine wb840 net_stack_driver + etherpci via-rhine wb840 net_stack $(GPL_ONLY)bcm440x $(GPL_ONLY)bcm570x ; BEOS_ADD_ONS_DRIVERS_ACPI = $(X86_ONLY)acpi_button $(X86_ONLY)acpi_ns_dump ; @@ -132,6 +132,8 @@ AddFilesToHaikuImage beos system : kernel_$(TARGET_ARCH) ; # libs AddFilesToHaikuImage beos system lib : $(BEOS_SYSTEM_LIB) ; +AddSymlinkToHaikuImage beos system lib : libnetwork.so : libsocket.so ; +AddSymlinkToHaikuImage beos system lib : libnetwork.so : libbind.so ; # servers AddFilesToHaikuImage beos system servers : $(BEOS_SYSTEM_SERVERS) ; @@ -186,11 +188,11 @@ AddFilesToHaikuImage beos etc KanBe dic canna : $(kanbeDicCanna) ; AddDirectoryToHaikuImage beos etc KanBe dic group ; AddDirectoryToHaikuImage beos etc KanBe dic user ; -local libnetFiles = networks protocols resolv.conf services ; -libnetFiles = $(libnetFiles:G=libnet-files) ; -SEARCH on $(libnetFiles) - = [ FDirName $(HAIKU_TOP) src kits network compat libnet ] ; -AddFilesToHaikuImage beos etc : $(libnetFiles) ; +#local libnetFiles = networks protocols resolv.conf services ; +#libnetFiles = $(libnetFiles:G=libnet-files) ; +#SEARCH on $(libnetFiles) +# = [ FDirName $(HAIKU_TOP) src kits network compat libnet ] ; +#AddFilesToHaikuImage beos etc : $(libnetFiles) ; local keymapFiles = [ GLOB [ FDirName $(HAIKU_TOP) src data etc keymaps ] : *.keymap ] ; keymapFiles = $(keymapFiles:BG=keymap) ; @@ -238,9 +240,11 @@ AddFilesToHaikuImage beos system add-ons input_server devices AddFilesToHaikuImage beos system add-ons input_server filters : screen_saver ; # AddFilesToHaikuImage beos system add-ons input_server methods : canna ; AddFilesToHaikuImage beos system add-ons kernel network - : $(BEOS_NETWORK_CORE) ; -AddFilesToHaikuImage beos system add-ons kernel network interfaces - : $(BEOS_NETWORK_INTERFACES) ; + : stack ; +AddFilesToHaikuImage beos system add-ons kernel network devices + : $(BEOS_NETWORK_DEVICES) ; +AddFilesToHaikuImage beos system add-ons kernel network datalink_protocols + : $(BEOS_NETWORK_DATALINK_PROTOCOLS) ; AddFilesToHaikuImage beos system add-ons kernel network ppp : $(BEOS_NETWORK_PPP) ; AddFilesToHaikuImage beos system add-ons kernel network protocols diff --git a/headers/posix/arpa/inet.h b/headers/posix/arpa/inet.h index c481b903d2..03d843f83c 100644 --- a/headers/posix/arpa/inet.h +++ b/headers/posix/arpa/inet.h @@ -1,6 +1,9 @@ /* - * ++Copyright++ 1983, 1993 - * - + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + +/* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * @@ -49,58 +52,57 @@ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. - * - - * --Copyright-- */ - -/* - * @(#)inet.h 8.1 (Berkeley) 6/2/93 - * $Id$ - */ - #ifndef _INET_H_ #define _INET_H_ -/* External definitions for functions in inet(3) */ +#include #include -#include +#include #include + #define inet_addr __inet_addr #define inet_aton __inet_aton #define inet_lnaof __inet_lnaof -#define inet_makeaddr __inet_makeaddr +#define inet_makeaddr __inet_makeaddr #define inet_neta __inet_neta #define inet_netof __inet_netof -#define inet_network __inet_network -#define inet_net_ntop __inet_net_ntop -#define inet_net_pton __inet_net_pton -#define inet_cidr_ntop __inet_cidr_ntop -#define inet_cidr_pton __inet_cidr_pton +#define inet_network __inet_network +#define inet_net_ntop __inet_net_ntop +#define inet_net_pton __inet_net_pton +#define inet_cidr_ntop __inet_cidr_ntop +#define inet_cidr_pton __inet_cidr_pton #define inet_ntoa __inet_ntoa #define inet_pton __inet_pton #define inet_ntop __inet_ntop -#define inet_nsap_addr __inet_nsap_addr -#define inet_nsap_ntoa __inet_nsap_ntoa +#define inet_nsap_addr __inet_nsap_addr +#define inet_nsap_ntoa __inet_nsap_ntoa -__BEGIN_DECLS -unsigned long inet_addr __P((const char *)); -int inet_aton __P((const char *, struct in_addr *)); -unsigned long inet_lnaof __P((struct in_addr)); -struct in_addr inet_makeaddr __P((u_long , u_long)); -char * inet_neta __P((u_long, char *, size_t)); -unsigned long inet_netof __P((struct in_addr)); -unsigned long inet_network __P((const char *)); -char *inet_net_ntop __P((int, const void *, int, char *, size_t)); -int inet_net_pton __P((int, const char *, void *, size_t)); -char *inet_cidr_ntop __P((int, const void *, int, char *, size_t)); -int inet_cidr_pton __P((int, const char *, void *, int *)); -/*const*/ char *inet_ntoa __P((struct in_addr)); -int inet_pton __P((int, const char *, void *)); -const char *inet_ntop __P((int, const void *, char *, size_t)); -u_int inet_nsap_addr __P((const char *, u_char *, int)); -char *inet_nsap_ntoa __P((int, const u_char *, char *)); -__END_DECLS +#ifdef __cplusplus +extern "C" { +#endif -#endif /* !_INET_H_ */ +in_addr_t inet_addr(const char *); +int inet_aton(const char *, struct in_addr *); +unsigned long inet_lnaof(struct in_addr); +struct in_addr inet_makeaddr(u_long , u_long); +char *inet_neta(u_long, char *, size_t); +unsigned long inet_netof(struct in_addr); +unsigned long inet_network(const char *); +char *inet_net_ntop(int, const void *, int, char *, size_t); +int inet_net_pton(int, const char *, void *, size_t); +char *inet_cidr_ntop(int, const void *, int, char *, size_t); +int inet_cidr_pton(int, const char *, void *, int *); +char *inet_ntoa(struct in_addr); +int inet_pton(int, const char *, void *); +const char *inet_ntop(int, const void *, char *, size_t); +u_int inet_nsap_addr(const char *, u_char *, int); +char *inet_nsap_ntoa(int, const u_char *, char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _INET_H_ */ diff --git a/headers/posix/arpa/nameser.h b/headers/posix/arpa/nameser.h index 3052b1e787..c393611f99 100644 --- a/headers/posix/arpa/nameser.h +++ b/headers/posix/arpa/nameser.h @@ -1,3 +1,8 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + /* * Copyright (c) 1983, 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -47,19 +52,15 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - -/* - * $Id$ - */ - #ifndef _ARPA_NAMESER_H_ #define _ARPA_NAMESER_H_ -#define BIND_4_COMPAT +#include #include -#include #include +#include + /* * Revision information. This is the release date in YYYYMMDD format. @@ -68,27 +69,26 @@ * compare for equality; rather, use it to determine whether your libbind.a * contains a new enough lib/nameser/ to support the feature you need. */ - #define __NAMESER 19991006 /* New interface version stamp. */ /* * Define constants based on RFC 883, RFC 1034, RFC 1035 */ -#define NS_PACKETSZ 512 /* default UDP packet size */ -#define NS_MAXDNAME 1025 /* maximum domain name */ -#define NS_MAXMSG 65535 /* maximum message size */ -#define NS_MAXCDNAME 255 /* maximum compressed domain name */ -#define NS_MAXLABEL 63 /* maximum length of domain label */ -#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ -#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ -#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ -#define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ -#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ -#define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ -#define NS_INADDRSZ 4 /* IPv4 T_A */ -#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#define NS_PACKETSZ 512 /* default UDP packet size */ +#define NS_MAXDNAME 1025 /* maximum domain name */ +#define NS_MAXMSG 65535 /* maximum message size */ +#define NS_MAXCDNAME 255 /* maximum compressed domain name */ +#define NS_MAXLABEL 63 /* maximum length of domain label */ +#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ +#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ +#define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ +#define NS_INADDRSZ 4 /* IPv4 T_A */ +#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ #define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ -#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ +#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ /* * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() @@ -111,11 +111,14 @@ typedef enum __ns_sect { * leading _'s on the member names. Use the accessor functions, not the _'s. */ typedef struct __ns_msg { - const u_char *_msg, *_eom; - u_int16_t _id, _flags, _counts[ns_s_max]; + const u_char *_msg; + const u_char *_eom; + u_int16_t _id; + u_int16_t _flags; + u_int16_t _counts[ns_s_max]; const u_char *_sections[ns_s_max]; - ns_sect _sect; - int _rrnum; + ns_sect _sect; + int _rrnum; const u_char *_msg_ptr; } ns_msg; @@ -135,12 +138,12 @@ extern struct _ns_flagdata _ns_flagdata[]; * This is a parsed record. It is caller allocated and has no dynamic data. */ typedef struct __ns_rr { - char name[NS_MAXDNAME]; - u_int16_t type; - u_int16_t rr_class; - u_int32_t ttl; - u_int16_t rdlength; - const u_char * rdata; + char name[NS_MAXDNAME]; + u_int16_t type; + u_int16_t rr_class; + u_int32_t ttl; + u_int16_t rdlength; + const u_char *rdata; } ns_rr; /* Accessor macros - this is part of the public interface. */ @@ -158,7 +161,7 @@ typedef struct __ns_rr { */ typedef enum __ns_flag { ns_f_qr, /* Question/Response. */ - ns_f_opcode, /* Operation code. */ + ns_f_opcode, /* Operation code. */ ns_f_aa, /* Authoritative Answer. */ ns_f_tc, /* Truncation occurred. */ ns_f_rd, /* Recursion Desired. */ @@ -177,7 +180,7 @@ typedef enum __ns_opcode { ns_o_query = 0, /* Standard query. */ ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ ns_o_status = 2, /* Name server status query (unsupported). */ - /* Opcode 3 is undefined/reserved. */ + /* Opcode 3 is undefined/reserved. */ ns_o_notify = 4, /* Zone change notification. */ ns_o_update = 5, /* Zone update message. */ ns_o_max = 6 @@ -219,9 +222,10 @@ typedef enum __ns_update_operation { * This structure is used for TSIG authenticated messages */ struct ns_tsig_key { - char name[NS_MAXDNAME], alg[NS_MAXDNAME]; - unsigned char *data; - int len; + char name[NS_MAXDNAME]; + char alg[NS_MAXDNAME]; + unsigned char *data; + int len; }; typedef struct ns_tsig_key ns_tsig_key; @@ -229,11 +233,11 @@ typedef struct ns_tsig_key ns_tsig_key; * This structure is used for TSIG authenticated TCP messages */ struct ns_tcp_tsig_state { - int counter; - struct dst_key *key; - void *ctx; - unsigned char sig[NS_PACKETSZ]; - int siglen; + int counter; + struct dst_key *key; + void *ctx; + unsigned char sig[NS_PACKETSZ]; + int siglen; }; typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; @@ -250,7 +254,7 @@ typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; */ typedef enum __ns_type { ns_t_invalid = 0, /* Cookie. */ - ns_t_a = 1, /* Host address. */ + ns_t_a = 1, /* Host address. */ ns_t_ns = 2, /* Authoritative server. */ ns_t_md = 3, /* Mail destination. */ ns_t_mf = 4, /* Mail forwarder. */ @@ -473,14 +477,14 @@ typedef enum __ns_cert_types { * ANSI C identifier hiding for bind's lib/nameser. */ #define ns_msg_getflag __ns_msg_getflag -#define ns_get16 __ns_get16 -#define ns_get32 __ns_get32 -#define ns_put16 __ns_put16 -#define ns_put32 __ns_put32 +#define ns_get16 __ns_get16 +#define ns_get32 __ns_get32 +#define ns_put16 __ns_put16 +#define ns_put32 __ns_put32 #define ns_initparse __ns_initparse -#define ns_skiprr __ns_skiprr -#define ns_parserr __ns_parserr -#define ns_sprintrr __ns_sprintrr +#define ns_skiprr __ns_skiprr +#define ns_parserr __ns_parserr +#define ns_sprintrr __ns_sprintrr #define ns_sprintrrf __ns_sprintrrf #define ns_format_ttl __ns_format_ttl #define ns_parse_ttl __ns_parse_ttl @@ -494,79 +498,81 @@ typedef enum __ns_cert_types { #define ns_name_uncompress __ns_name_uncompress #define ns_name_skip __ns_name_skip #define ns_name_rollback __ns_name_rollback -#define ns_sign __ns_sign -#define ns_sign2 __ns_sign2 -#define ns_sign_tcp __ns_sign_tcp +#define ns_sign __ns_sign +#define ns_sign2 __ns_sign2 +#define ns_sign_tcp __ns_sign_tcp #define ns_sign_tcp2 __ns_sign_tcp2 #define ns_sign_tcp_init __ns_sign_tcp_init #define ns_find_tsig __ns_find_tsig -#define ns_verify __ns_verify +#define ns_verify __ns_verify #define ns_verify_tcp __ns_verify_tcp #define ns_verify_tcp_init __ns_verify_tcp_init #define ns_samedomain __ns_samedomain #define ns_subdomain __ns_subdomain #define ns_makecanon __ns_makecanon -#define ns_samename __ns_samename +#define ns_samename __ns_samename -__BEGIN_DECLS -int ns_msg_getflag __P((ns_msg, int)); -u_int ns_get16 __P((const u_char *)); -u_long ns_get32 __P((const u_char *)); -void ns_put16 __P((u_int, u_char *)); -void ns_put32 __P((u_long, u_char *)); -int ns_initparse __P((const u_char *, int, ns_msg *)); -int ns_skiprr __P((const u_char *, const u_char *, ns_sect, int)); -int ns_parserr __P((ns_msg *, ns_sect, int, ns_rr *)); -int ns_sprintrr __P((const ns_msg *, const ns_rr *, - const char *, const char *, char *, size_t)); -int ns_sprintrrf __P((const u_char *, size_t, const char *, - ns_class, ns_type, u_long, const u_char *, - size_t, const char *, const char *, - char *, size_t)); -int ns_format_ttl __P((u_long, char *, size_t)); -int ns_parse_ttl __P((const char *, u_long *)); -u_int32_t ns_datetosecs __P((const char *cp, int *errp)); -int ns_name_ntol __P((const u_char *, u_char *, size_t)); -int ns_name_ntop __P((const u_char *, char *, size_t)); -int ns_name_pton __P((const char *, u_char *, size_t)); -int ns_name_unpack __P((const u_char *, const u_char *, - const u_char *, u_char *, size_t)); -int ns_name_pack __P((const u_char *, u_char *, int, - const u_char **, const u_char **)); -int ns_name_uncompress __P((const u_char *, const u_char *, - const u_char *, char *, size_t)); -int ns_name_compress __P((const char *, u_char *, size_t, - const u_char **, const u_char **)); -int ns_name_skip __P((const u_char **, const u_char *)); -void ns_name_rollback __P((const u_char *, const u_char **, - const u_char **)); -int ns_sign __P((u_char *, int *, int, int, void *, - const u_char *, int, u_char *, int *, time_t)); -int ns_sign2 __P((u_char *, int *, int, int, void *, - const u_char *, int, u_char *, int *, time_t, - u_char **, u_char **)); -int ns_sign_tcp __P((u_char *, int *, int, int, - ns_tcp_tsig_state *, int)); -int ns_sign_tcp2 __P((u_char *, int *, int, int, - ns_tcp_tsig_state *, int, - u_char **, u_char **)); -int ns_sign_tcp_init __P((void *, const u_char *, int, - ns_tcp_tsig_state *)); -u_char *ns_find_tsig __P((u_char *, u_char *)); -int ns_verify __P((u_char *, int *, void *, - const u_char *, int, u_char *, int *, - time_t *, int)); -int ns_verify_tcp __P((u_char *, int *, ns_tcp_tsig_state *, int)); -int ns_verify_tcp_init __P((void *, const u_char *, int, - ns_tcp_tsig_state *)); -int ns_samedomain __P((const char *, const char *)); -int ns_subdomain __P((const char *, const char *)); -int ns_makecanon __P((const char *, char *, size_t)); -int ns_samename __P((const char *, const char *)); -__END_DECLS - -#ifdef BIND_4_COMPAT -#include +#ifdef __cplusplus +extern "C" { #endif -#endif /* !_ARPA_NAMESER_H_ */ +int ns_msg_getflag(ns_msg, int); +u_int ns_get16(const u_char *); +u_long ns_get32(const u_char *); +void ns_put16(u_int, u_char *); +void ns_put32(u_long, u_char *); +int ns_initparse(const u_char *, int, ns_msg *); +int ns_skiprr(const u_char *, const u_char *, ns_sect, int); +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); +int ns_sprintrr(const ns_msg *, const ns_rr *, + const char *, const char *, char *, size_t); +int ns_sprintrrf(const u_char *, size_t, const char *, + ns_class, ns_type, u_long, const u_char *, + size_t, const char *, const char *, + char *, size_t); +int ns_format_ttl(u_long, char *, size_t); +int ns_parse_ttl(const char *, u_long *); +u_int32_t ns_datetosecs(const char *cp, int *errp); +int ns_name_ntol(const u_char *, u_char *, size_t); +int ns_name_ntop(const u_char *, char *, size_t); +int ns_name_pton(const char *, u_char *, size_t); +int ns_name_unpack(const u_char *, const u_char *, + const u_char *, u_char *, size_t); +int ns_name_pack(const u_char *, u_char *, int, + const u_char **, const u_char **); +int ns_name_uncompress(const u_char *, const u_char *, + const u_char *, char *, size_t); +int ns_name_compress(const char *, u_char *, size_t, + const u_char **, const u_char **); +int ns_name_skip(const u_char **, const u_char *); +void ns_name_rollback(const u_char *, const u_char **, + const u_char **); +int ns_sign(u_char *, int *, int, int, void *, + const u_char *, int, u_char *, int *, time_t); +int ns_sign2(u_char *, int *, int, int, void *, + const u_char *, int, u_char *, int *, time_t, + u_char **, u_char **); +int ns_sign_tcp(u_char *, int *, int, int, + ns_tcp_tsig_state *, int); +int ns_sign_tcp2(u_char *, int *, int, int, + ns_tcp_tsig_state *, int, + u_char **, u_char **); +int ns_sign_tcp_init(void *, const u_char *, int, + ns_tcp_tsig_state *); +u_char *ns_find_tsig(u_char *, u_char *); +int ns_verify(u_char *, int *, void *, + const u_char *, int, u_char *, int *, + time_t *, int); +int ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int); +int ns_verify_tcp_init(void *, const u_char *, int, + ns_tcp_tsig_state *); +int ns_samedomain(const char *, const char *); +int ns_subdomain(const char *, const char *); +int ns_makecanon(const char *, char *, size_t); +int ns_samename(const char *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _ARPA_NAMESER_H_ */ diff --git a/headers/posix/net/if.h b/headers/posix/net/if.h index 697346a059..8aadc4157a 100644 --- a/headers/posix/net/if.h +++ b/headers/posix/net/if.h @@ -1,278 +1,100 @@ -/* if.h - * Interface definitions for beos +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. */ - #ifndef _NET_IF_H #define _NET_IF_H -/* FIXME: this file is NOT POSIX compliant, and rely on way too much OS-dependent - definition. - Moving private parts to private headers should help clean up this file - - POSIX net/if.h spec: - http://www.opengroup.org/onlinepubs/007904975/basedefs/net/if.h.html -*/ -#include /* FIXME */ -#include -#include #include +#include + + +#define IF_NAMESIZE 32 + +/* BSD specific/proprietary part */ + +#define IFNAMSIZ IF_NAMESIZE + +struct ifreq_parameter { + char base_name[IF_NAMESIZE]; + char device[128]; + uint8_t sub_type; +}; + +struct ifreq_stream_stats { + uint32_t packets; + uint32_t errors; + uint64_t bytes; + uint32_t multicast_packets; + uint32_t dropped; +}; + +struct ifreq_stats { + struct ifreq_stream_stats receive; + struct ifreq_stream_stats send; + uint32_t collisions; +}; + +struct ifreq { + char ifr_name[IF_NAMESIZE]; + union { + struct sockaddr ifr_addr; + struct sockaddr ifr_dstaddr; + struct sockaddr ifr_broadaddr; + struct sockaddr ifr_mask; + struct ifreq_parameter ifr_parameter; + struct ifreq_stats ifr_stats; + struct route_entry ifr_route; + int ifr_flags; + int ifr_index; + int ifr_metric; + int ifr_mtu; + int ifr_media; + int ifr_type; + }; +}; + +/* interface flags */ +#define IFF_UP 0x0001 +#define IFF_BROADCAST 0x0002 /* valid broadcast address */ +#define IFF_LOOPBACK 0x0008 +#define IFF_POINTOPOINT 0x0010 /* point-to-point link */ +#define IFF_NOARP 0x0040 /* no address resolution */ +#define IFF_AUTOUP 0x0080 /* auto dial */ +#define IFF_PROMISC 0x0100 /* receive all packets */ +#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */ +#define IFF_SIMPLEX 0x0800 /* doesn't receive own transmissions */ +#define IFF_MULTICAST 0x8000 /* supports multicast */ + +struct ifconf { + int ifc_len; /* size of buffer */ + union { + void *ifc_buf; + struct ifreq *ifc_req; + int ifc_value; + }; +}; + +/* POSIX definitions follow */ + +struct if_nameindex { + unsigned if_index; /* positive interface index */ + char *if_name; /* interface name, ie. "loopback" */ +}; + #ifdef __cplusplus extern "C" { #endif -/* Forward reference... */ -struct socket; - -/* Media types are now listed in net/if_types.h */ - -/* Interface flags */ -enum { - IFF_UP = 0x0001, - IFF_DOWN = 0x0002, - IFF_PROMISC = 0x0004, - IFF_RUNNING = 0x0008, - IFF_MULTICAST = 0x0010, - IFF_BROADCAST = 0x0020, - IFF_POINTOPOINT = 0x0040, - IFF_NOARP = 0x0080, - IFF_LOOPBACK = 0x0100, - IFF_DEBUG = 0x0200, - IFF_LINK0 = 0x0400, - IFF_LINK1 = 0x0800, - IFF_LINK2 = 0x1000, - IFF_SIMPLEX = 0x2000 -}; - -struct ifq { - struct mbuf *head; - struct mbuf *tail; - int maxlen; - int len; - sem_id lock; - sem_id pop; -}; - -#define IFQ_FULL(ifq) (ifq->len >= ifq->maxlen) - -#define IFQ_ENQUEUE(ifq, m) { \ - acquire_sem((ifq)->lock); \ - (m)->m_nextpkt = 0; \ - if ((ifq)->tail == 0) \ - (ifq)->head = m; \ - else \ - (ifq)->tail->m_nextpkt = m; \ - (ifq)->tail = m; \ - (ifq)->len++; \ - release_sem((ifq)->lock); \ - release_sem((ifq)->pop); \ -} - -#define IFQ_DEQUEUE(ifq, m) { \ - acquire_sem((ifq)->lock); \ - (m) = (ifq)->head; \ - if (m) { \ - if (((ifq)->head = (m)->m_nextpkt) == 0) \ - (ifq)->tail = 0; \ - (m)->m_nextpkt = 0; \ - (ifq)->len--; \ - } \ - release_sem((ifq)->lock); \ -} - -struct ifaddr { - struct ifaddr *ifa_next; /* the next address for the interface */ - struct ifnet *ifa_ifp; /* pointer to the interface structure */ - - struct sockaddr *ifa_addr; /* the address - cast to be a suitable type, so we - * use this structure to store any type of address that - * we have a struct sockaddr_? for. e.g. - * link level address via sockaddr_dl and - * ipv4 via sockeddr_in - * same for next 2 pointers as well - */ - struct sockaddr *ifa_dstaddr; /* if we're on a point-to-point link this - * is the other end */ - struct sockaddr *ifa_netmask; /* The netmask we're using */ - - /* check or clean routes... */ - void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *); - uint8 ifa_flags; /* flags (mainly routing */ - uint16 ifa_refcnt; /* how many references are there to - * this structure? */ - int ifa_metric; /* the metirc for this interface/address */ -}; -#define ifa_broadaddr ifa_dstaddr - -struct if_data { - uint8 ifi_type; /* type of media */ - uint8 ifi_addrlen; /* length of media address length */ - uint8 ifi_hdrlen; /* size of media header */ - uint32 ifi_mtu; /* mtu */ - uint32 ifi_metric; /* routing metric */ - uint32 ifi_baudrate; /* baudrate of line */ - /* statistics!! */ - int32 ifi_ipackets; /* packets received on interface */ - int32 ifi_ierrors; /* input errors on interface */ - int32 ifi_opackets; /* packets sent on interface */ - int32 ifi_oerrors; /* output errors on interface */ - int32 ifi_collisions; /* collisions on csma interfaces */ - int32 ifi_ibytes; /* total number of octets received */ - int32 ifi_obytes; /* total number of octets sent */ - int32 ifi_imcasts; /* packets received via multicast */ - int32 ifi_omcasts; /* packets sent via multicast */ - int32 ifi_iqdrops; /* dropped on input, this interface */ - int32 ifi_noproto; /* destined for unsupported protocol */ -}; - -struct ifnet { - struct ifnet *if_next; /* next device */ - struct ifaddr *if_addrlist; /* linked list of addresses */ - int devid; /* our device id if we have one... */ - int id; /* id within the stack's device list */ - char *name; /* name of driver e.g. tulip */ - int if_unit; /* number of unit e.g 0 */ - char *if_name; /* full name, e.g. tulip0 */ - struct if_data ifd; /* if_data structure, shortcuts below */ - int if_flags; /* if flags */ - int if_index; /* our index in ifnet_addrs and interfaces */ - - struct ifq *rxq; - thread_id rx_thread; - struct ifq *txq; - thread_id tx_thread; - struct ifq *devq; - - int (*start) (struct ifnet *); - int (*stop) (struct ifnet *); - void (*input) (struct mbuf*); - int (*output)(struct ifnet *, struct mbuf*, - struct sockaddr*, struct rtentry *); - int (*ioctl) (struct ifnet *, ulong, caddr_t); -}; -#define if_mtu ifd.ifi_mtu -#define if_type ifd.ifi_type -#define if_addrlen ifd.ifi_addrlen -#define if_hdrlen ifd.ifi_hdrlen -#define if_metric ifd.ifi_metric -#define if_baudrate ifd.ifi_baudrate -#define if_ipackets ifd.ifi_ipackets -#define if_ierrors ifd.ifi_ierrors -#define if_opackets ifd.ifi_opackets -#define if_oerrors ifd.ifi_oerrors -#define if_collisions ifd.ifi_collisions -#define if_ibytes ifd.ifi_ibytes -#define if_obytes ifd.ifi_obytes -#define if_imcasts ifd.ifi_imcasts -#define if_omcasts ifd.ifi_omcasts -#define if_iqdrops ifd.ifi_iqdrops -#define if_noproto ifd.ifi_noproto - -#define IFNAMSIZ 16 - -/* This structure is used for passing interface requests via ioctl */ -struct ifreq { - char ifr_name[IFNAMSIZ]; /* name of interface */ - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - uint16 ifru_flags; - int ifru_metric; - char * ifru_data; - } ifr_ifru; -}; -#define ifr_addr ifr_ifru.ifru_addr -#define ifr_dstaddr ifr_ifru.ifru_dstaddr -#define ifr_broadaddr ifr_ifru.ifru_broadaddr -#define ifr_flags ifr_ifru.ifru_flags -#define ifr_metric ifr_ifru.ifru_metric -#define ifr_mtu ifr_ifru.ifru_metric /* sneaky overload :) */ -#define ifr_data ifr_ifru.ifru_data - -struct ifconf { - int ifc_len; /* length of associated buffer */ - union { - char * ifcu_buf; - struct ifreq *ifcu_req; - } ifc_ifcu; -}; -#define ifc_buf ifc_ifcu.ifcu_buf -#define ifc_req ifc_ifcu.ifcu_req - - -#define IFAFREE(ifa) \ -do { \ - if ((ifa)->ifa_refcnt <= 0) \ - ifafree(ifa); \ - else \ - (ifa)->ifa_refcnt--; \ -} while (0) - -/* used to pass in additional information, such as aliases */ -struct ifaliasreq { - char ifa_name[IFNAMSIZ]; - struct sockaddr ifra_addr; - struct sockaddr ifra_broadaddr; -#define ifra_dstaddr ifra_broadaddr - struct sockaddr ifra_mask; -}; - -#define IFA_ROUTE RTF_UP - -/* - * Message format for use in obtaining information about interfaces - * from sysctl and the routing socket. - */ -struct if_msghdr { - u_short ifm_msglen; /* to skip over non-understood messages */ - u_char ifm_version; /* future binary compatability */ - u_char ifm_type; /* message type */ - int ifm_addrs; /* like rtm_addrs */ - int ifm_flags; /* value of if_flags */ - u_short ifm_index; /* index for associated ifp */ - struct if_data ifm_data;/* statistics and other data about if */ -}; - -/* - * Message format for use in obtaining information about interface addresses - * from sysctl and the routing socket. - */ -struct ifa_msghdr { - u_short ifam_msglen; /* to skip over non-understood messages */ - u_char ifam_version; /* future binary compatability */ - u_char ifam_type; /* message type */ - int ifam_addrs; /* like rtm_addrs */ - int ifam_flags; /* value of ifa_flags */ - u_short ifam_index; /* index for associated ifp */ - int ifam_metric; /* value of ifa_metric */ -}; - -/* function declaration */ -struct ifq *start_ifq(void); -void stop_ifq(struct ifq *); -struct ifnet *get_interfaces(void); -struct ifnet *ifunit(char *name); -struct ifaddr *ifa_ifwithaddr(struct sockaddr *); -struct ifaddr *ifa_ifwithaf(int); -struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *); -struct ifaddr *ifa_ifwithnet(struct sockaddr *); -struct ifaddr *ifa_ifwithroute(int, struct sockaddr *, - struct sockaddr *); -struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *); -void ifafree(struct ifaddr *); - -void if_attach(struct ifnet *ifp); -void if_detach(struct ifnet *ifp); - -int ifioctl(struct socket *so, ulong cmd, caddr_t data); -int ifconf(int cmd, char *data); -void if_init(void); +unsigned if_nametoindex(const char *name); +char *if_indextoname(unsigned index, char *nameBuffer); +struct if_nameindex *if_nameindex(void); +void if_freenameindex(struct if_nameindex *interfaceArray); #ifdef __cplusplus } #endif -#endif /* _NET_IF_H */ - +#endif /* _NET_IF_H */ diff --git a/headers/posix/net/if_arp.h b/headers/posix/net/if_arp.h deleted file mode 100644 index 579d35fd1f..0000000000 --- a/headers/posix/net/if_arp.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)if_arp.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef NET_IF_ARP_H -#define NET_IF_ARP_H -/* - * Address Resolution Protocol. - * - * See RFC 826 for protocol description. ARP packets are variable - * in size; the arphdr structure defines the fixed-length portion. - * Protocol type values are the same as those for 10 Mb/s Ethernet. - * It is followed by the variable-sized fields ar_sha, arp_spa, - * arp_tha and arp_tpa in that order, according to the lengths - * specified. Field names used correspond to RFC 826. - */ -struct arphdr { - uint16 ar_hrd; /* format of hardware address */ - uint16 ar_pro; /* format of protocol address */ - uint8 ar_hln; /* length of hardware address */ - uint8 ar_pln; /* length of protocol address */ - uint16 ar_op; /* one of: */ -/* - * The remaining fields are variable in size, - * according to the sizes above. - */ -#ifdef COMMENT_ONLY - uint8 ar_sha[]; /* sender hardware address */ - uint8 ar_spa[]; /* sender protocol address */ - uint8 ar_tha[]; /* target hardware address */ - uint8 ar_tpa[]; /* target protocol address */ -#endif -}; - -#define ARPHRD_ETHER 1 /* ethernet hardware format */ -#define ARPHRD_IEEE802 6 /* IEEE 802 hardware format */ -#define ARPHRD_FRELAY 15 /* frame relay hardware format */ - -#define ARPOP_REQUEST 1 /* request to resolve address */ -#define ARPOP_REPLY 2 /* response to previous request */ -#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ -#define ARPOP_REVREPLY 4 /* response giving protocol address */ -#define ARPOP_INVREQUEST 8 /* request to identify peer */ -#define ARPOP_INVREPLY 9 /* response identifying peer */ - -/* - * ARP ioctl request - */ -struct arpreq { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ -}; -/* arp_flags and at_flags field values */ -#define ATF_INUSE 0x01 /* entry in use */ -#define ATF_COM 0x02 /* completed entry (enaddr valid) */ -#define ATF_PERM 0x04 /* permanent entry */ -#define ATF_PUBL 0x08 /* publish entry (respond for other host) */ -#define ATF_USETRAILERS 0x10 /* has requested trailers */ - -#endif /* NET_IF_ARP_H */ diff --git a/headers/posix/net/if_dl.h b/headers/posix/net/if_dl.h index 14b891e1ac..9420e58d00 100644 --- a/headers/posix/net/if_dl.h +++ b/headers/posix/net/if_dl.h @@ -1,38 +1,28 @@ -/* if.h - * Interface definitions for beos +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. */ +#ifndef _NET_IF_DL_H +#define _NET_IF_DL_H -#ifndef OBOS_IF_DL_H -#define OBOS_IF_DL_H -#include +#include -#ifdef __cplusplus -extern "C" { -#endif -/* link level sockaddr structure */ +/* Link level sockaddr structure */ struct sockaddr_dl { - uint8 sdl_len; /* Total length of sockaddr */ - uint8 sdl_family; /* AF_LINK */ - uint16 sdl_index; /* if != 0, system given index for interface */ - uint8 sdl_type; /* interface type */ - uint8 sdl_nlen; /* interface name length, no trailing 0 reqd. */ - uint8 sdl_alen; /* link level address length */ - uint8 sdl_slen; /* link layer selector length */ - char sdl_data[24]; /* minimum work area, can be larger; - contains both if name and ll address */ + uint8_t sdl_len; /* Total length of sockaddr */ + uint8_t sdl_family; /* AF_LINK */ + uint16_t sdl_e_type; /* link level frame type */ + uint32_t sdl_index; /* index for interface */ + uint8_t sdl_type; /* interface type */ + uint8_t sdl_nlen; /* interface name length (not terminated with a null byte) */ + uint8_t sdl_alen; /* link level address length */ + uint8_t sdl_slen; /* link layer selector length */ + char sdl_data[20]; /* minimum work area, can be larger */ }; /* Macro to get a pointer to the link level address */ -#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) - -void link_addr (const char *, struct sockaddr_dl *); -char *link_ntoa (const struct sockaddr_dl *); - -#ifdef __cplusplus -} -#endif - -#endif /* OBOS_IF_DL_H */ +#define LLADDR(s) ((char *)((s)->sdl_data + (s)->sdl_nlen)) +#endif /* _NET_IF_DL_H */ diff --git a/headers/posix/net/if_ppp.h b/headers/posix/net/if_ppp.h deleted file mode 100644 index b331efa0d4..0000000000 --- a/headers/posix/net/if_ppp.h +++ /dev/null @@ -1,129 +0,0 @@ -/* $OpenBSD: if_ppp.h,v 1.6 2001/06/09 06:16:38 angelos Exp $ */ -/* $NetBSD: if_ppp.h,v 1.11 1996/03/15 02:28:05 paulus Exp $ */ - -/* - * if_ppp.h - Point-to-Point Protocol definitions. - * - * Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef _NET_IF_PPP_H_ -#define _NET_IF_PPP_H_ - -/* - * Bit definitions for flags. - */ -#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */ -#define SC_COMP_AC 0x00000002 /* header compression (output) */ -#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */ -#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */ -#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */ -#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */ -#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */ -#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */ -#define SC_DEBUG 0x00010000 /* enable debug messages */ -#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */ -#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */ -#define SC_LOG_RAWIN 0x00080000 /* log all chars received */ -#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */ -#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */ -#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */ -#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */ -#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */ -#define SC_MASK 0x0fff00ff /* bits that user can change */ - -/* - * State bits in sc_flags, not changeable by user. - */ -#define SC_TIMEOUT 0x00000400 /* timeout is currently pending */ -#define SC_VJ_RESET 0x00000800 /* need to reset VJ decomp */ -#define SC_COMP_RUN 0x00001000 /* compressor has been inited */ -#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */ -#define SC_DC_ERROR 0x00004000 /* non-fatal decomp error detected */ -#define SC_DC_FERROR 0x00008000 /* fatal decomp error detected */ -#define SC_TBUSY 0x10000000 /* xmitter doesn't need a packet yet */ -#define SC_PKTLOST 0x20000000 /* have lost or dropped a packet */ -#define SC_FLUSH 0x40000000 /* flush input until next PPP_FLAG */ -#define SC_ESCAPED 0x80000000 /* saw a PPP_ESCAPE */ - -/* - * Ioctl definitions. - */ - -struct npioctl { - int protocol; /* PPP procotol, e.g. PPP_IP */ - int on; -}; - -/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */ -struct ppp_option_data { - u_char *ptr; - u_int length; - int transmit; -}; - -struct ifpppstatsreq { - char ifr_name[IFNAMSIZ]; - struct ppp_stats stats; -}; - -struct ifpppcstatsreq { - char ifr_name[IFNAMSIZ]; - struct ppp_comp_stats stats; -}; - -/* - * Ioctl definitions. - */ - -#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */ -#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */ -#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */ -#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */ -#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */ -#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */ -#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */ -#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */ -#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */ -#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */ -#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */ -#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */ -#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */ -#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data) -#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */ -#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */ -#define PPPIOCGIDLE _IOR('t', 74, struct ppp_idle) /* get idle time */ -#define PPPIOCSPASS _IOW('t', 71, struct bpf_program) /* set pass filter */ -#define PPPIOCSACTIVE _IOW('t', 70, struct bpf_program) /* set active filt */ - -/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */ -#define PPPIOCGMTU _IOR('t', 73, int) /* get interface MTU */ -#define PPPIOCSMTU _IOW('t', 72, int) /* set interface MTU */ - -/* - * These two are interface ioctls so that pppstats can do them on - * a socket without having to open the serial device. - */ -#define SIOCGPPPSTATS _IOWR('i', 123, struct ifpppstatsreq) -#define SIOCGPPPCSTATS _IOWR('i', 122, struct ifpppcstatsreq) - -#ifdef _KERNEL_MODE -int pppoutput (struct ifnet *, struct mbuf *, struct sockaddr *, - struct rtentry *); -void pppinput (struct mbuf *); -#endif - -#endif /* _NET_IF_PPP_H_ */ diff --git a/headers/posix/net/if_types.h b/headers/posix/net/if_types.h index 88f61f9594..0d5cf7f2e8 100644 --- a/headers/posix/net/if_types.h +++ b/headers/posix/net/if_types.h @@ -1,23 +1,15 @@ -/* if_types.h - * - * +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. */ +#ifndef _NET_IF_TYPES_H +#define _NET_IF_TYPES_H -#ifndef NET_IF_TYPES_H -#define NET_IF_TYPES_H - -/* We just list the ones here we actually use... */ - -#define IFT_ETHER 0x06 -#define IFT_PPP 0x17 -#define IFT_LOOP 0x18 -#define IFT_SLIP 0x1c -#define IFT_RS232 0x21 -#define IFT_PARA 0x22 /* Parallel port! ?? */ -#define IFT_ATM 0x25 -#define IFT_MODEM 0x31 /* Just a simple generic modem */ -#define IFT_FASTETHER 0x32 /* 100BaseT ethernet */ -#define IFT_ISDN 0x3f /* ISDN / X.25 */ - -#endif /* NET_IF_TYPES_H */ +#define IFT_OTHER 0x01 +#define IFT_ETHER 0x06 +#define IFT_PPP 0x17 +#define IFT_LOOP 0x18 +#define IFT_SLIP 0x1c +#define IFT_MODEM 0x30 +#endif /* _NET_IF_TYPES_H */ diff --git a/headers/posix/net/radix.h b/headers/posix/net/radix.h deleted file mode 100644 index a186bbf27f..0000000000 --- a/headers/posix/net/radix.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)radix.h 8.2 (Berkeley) 10/31/94 - * $FreeBSD: src/sys/net/radix.h,v 1.16.2.1 2000/05/03 19:17:11 wollman Exp $ - */ - -#ifndef _NET_RADIX_H_ -#define _NET_RADIX_H_ - -//#include - -/* - * Radix search tree node layout. - */ - -struct radix_node { - struct radix_mask *rn_mklist; /* list of masks contained in subtree */ - struct radix_node *rn_parent; /* parent */ - short rn_bit; /* bit offset; -1-index(netmask) */ - char rn_bmask; /* node: mask for bit test*/ - u_char rn_flags; /* enumerated next */ -#define RNF_NORMAL 1 /* leaf contains normal route */ -#define RNF_ROOT 2 /* leaf is root leaf for tree */ -#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */ - union { - struct { /* leaf only data: */ - char * rn_Key; /* object of search */ - char * rn_Mask; /* netmask, if present */ - struct radix_node *rn_Dupedkey; - } rn_leaf; - struct { /* node only data: */ - int rn_Off; /* where to start compare */ - struct radix_node *rn_L;/* progeny */ - struct radix_node *rn_R;/* progeny */ - } rn_node; - } rn_u; -#ifdef RN_DEBUG - int rn_info; - struct radix_node *rn_twin; - struct radix_node *rn_ybro; -#endif -}; - -#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey -#define rn_key rn_u.rn_leaf.rn_Key -#define rn_mask rn_u.rn_leaf.rn_Mask -#define rn_offset rn_u.rn_node.rn_Off -#define rn_left rn_u.rn_node.rn_L -#define rn_right rn_u.rn_node.rn_R - -/* - * Annotations to tree concerning potential routes applying to subtrees. - */ - -struct radix_mask { - short rm_bit; /* bit offset; -1-index(netmask) */ - char rm_unused; /* cf. rn_bmask */ - u_char rm_flags; /* cf. rn_flags */ - struct radix_mask *rm_mklist; /* more masks to try */ - union { - char * rmu_mask; /* the mask */ - struct radix_node *rmu_leaf; /* for normal routes */ - } rm_rmu; - int rm_refs; /* # of references to this struct */ -}; - -#define rm_mask rm_rmu.rmu_mask -#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ - -#define MKGet(m) {\ - if (rn_mkfreelist) {\ - m = rn_mkfreelist; \ - rn_mkfreelist = (m)->rm_mklist; \ - } else \ - R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\ - -#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);} - -typedef int walktree_f_t (struct radix_node *, void *); - -struct radix_node_head { - struct radix_node *rnh_treetop; - int rnh_addrsize; /* permit, but not require fixed keys */ - int rnh_pktsize; /* permit, but not require fixed keys */ - struct radix_node *(*rnh_addaddr) /* add based on sockaddr */ - (void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[]); - struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ - (void *v, void *mask, - struct radix_node_head *head, struct radix_node nodes[]); - struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ - (void *v, struct radix_node_head *head); - struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ - (void *v, void *mask, struct radix_node_head *head); - struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ - (void *v, struct radix_node_head *head); - int (*rnh_walktree) /* traverse tree */ - (struct radix_node_head *head, walktree_f_t *f, void *w); - int (*rnh_walktree_from) /* traverse tree below a */ - (struct radix_node_head *head, void *a, void *m, - walktree_f_t *f, void *w); - void (*rnh_close) /* do something when the last ref drops */ - (struct radix_node *rn, struct radix_node_head *head); - struct radix_node rnh_nodes[3]; /* empty tree for common case */ -}; - -#define Bcmp(a, b, n) memcmp(((char *)(a)), ((char *)(b)), (n)) -#define Bcopy(a, b, n) memcpy(((char *)(b)), ((char *)(a)), (unsigned)(n)) -#define Bzero(p, n) memset((char *)(p),0, (int)(n)); -#define R_Malloc(p, t, n) do { \ - (p = (t) malloc((unsigned int)(n))); \ - memset(p, 0, sizeof(*p)); \ - } while (0) -#define Free(p) free((char *)p); - -void rn_init (void); -int rn_inithead (void **, int); -int rn_refines (void *, void *); -struct radix_node - *rn_addmask (void *, int, int), - *rn_addroute (void *, void *, struct radix_node_head *, - struct radix_node [2]), - *rn_delete (void *, void *, struct radix_node_head *), - *rn_lookup (void *v_arg, void *m_arg, - struct radix_node_head *head), - *rn_match (void *, struct radix_node_head *); - -/* extra fucntion so we don't have to export the mask_rnhead */ -struct radix_node *rn_head_search(void *argv_v); - -#endif /* _NET_RADIX_H_ */ diff --git a/headers/posix/net/raw_cb.h b/headers/posix/net/raw_cb.h deleted file mode 100644 index 8af2d33caa..0000000000 --- a/headers/posix/net/raw_cb.h +++ /dev/null @@ -1,17 +0,0 @@ -/* raw_cb.h */ - -#ifndef NET_RAW_CB_H -#define NET_RAW_CB_H - -struct rawcb { - struct rawcb *rcb_next; - struct rawcb *rcb_prev; - struct socket *rcb_socket; - struct sockaddr *rcb_faddr; - struct sockaddr *rcb_laddr; - struct sockproto rcb_proto; -}; - -#define sotorawcb(so) ((struct rawcb*)(so)->so_pcb) - -#endif /* NET_RAW_CB_H */ diff --git a/headers/posix/net/route.h b/headers/posix/net/route.h index 1dd5be0435..c024aafb80 100644 --- a/headers/posix/net/route.h +++ b/headers/posix/net/route.h @@ -1,208 +1,34 @@ -/* route.h */ - +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _NET_ROUTE_H #define _NET_ROUTE_H -#include -#include /* for AF_MAX */ -/* - * A route consists of a destination address and a reference - * to a routing entry. These are often held by protocols - * in their control blocks, e.g. inpcb. - */ -struct route { - struct rtentry *ro_rt; - struct sockaddr ro_dst; + +#include + + +#define RTF_UP 0x00000001 +#define RTF_GATEWAY 0x00000002 +#define RTF_HOST 0x00000004 +#define RTF_REJECT 0x00000008 +#define RTF_DYNAMIC 0x00000010 +#define RTF_MODIFIED 0x00000020 +#define RTF_DEFAULT 0x00000080 +#define RTF_STATIC 0x00000800 +#define RTF_BLACKHOLE 0x00001000 +#define RTF_LOCAL 0x00200000 + +// This structure is used to pass routes to and from the network stack +// (via struct ifreq) + +struct route_entry { + struct sockaddr *destination; + struct sockaddr *mask; + struct sockaddr *gateway; + uint32_t flags; + uint32_t mtu; }; -/* - * These numbers are used by reliable protocols for determining - * retransmission behavior and are included in the routing structure. - */ -struct rt_metrics { - uint32 rmx_locks; /* Kernel must leave these values alone */ - uint32 rmx_mtu; /* MTU for this path */ - uint32 rmx_hopcount; /* max hops expected */ - uint32 rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_recvpipe; /* inbound delay-bandwith product */ - u_long rmx_sendpipe; /* outbound delay-bandwith product */ - u_long rmx_ssthresh; /* outbound gateway buffer limit */ - u_long rmx_rtt; /* estimated round trip time */ - u_long rmx_rttvar; /* estimated rtt variance */ - u_long rmx_pksent; /* packets sent using this route */ -}; - -/* - * rmx_rtt and rmx_rttvar are stored as microseconds; - * RTTTOPRHZ(rtt) converts to a value suitable for use - * by a protocol slowtimo counter. - */ -#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ -#define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ)) - -struct rtentry { - struct radix_node rt_nodes[2]; /* tree glue, and other values */ - struct sockaddr *rt_gateway; /* value */ - uint rt_flags; /* up/down?, host/net */ - int rt_refcnt; /* # held references */ - uint32 rt_use; /* raw # packets forwarded */ - struct ifnet *rt_ifp; /* the answer: interface to use */ - struct ifaddr *rt_ifa; /* the answer: interface to use */ - struct sockaddr *rt_genmask; /* for generation of cloned routes */ - char * rt_llinfo; /* pointer to link level info cache */ - struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ - struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ - struct rtentry *rt_parent; /* If cloned, parent of this route. */ - /* XXX - add this! */ - // rt_timer; * queue of timeouts for misc funcs * -}; -#define rt_use rt_rmx.rmx_pksent -#define rt_key(r) ((struct sockaddr *)((r)->rt_nodes->rn_key)) -#define rt_mask(r) ((struct sockaddr *)((r)->rt_nodes->rn_mask)) - -#define RTF_UP 0x1 /* route usable */ -#define RTF_GATEWAY 0x2 /* destination is a gateway */ -#define RTF_HOST 0x4 /* host entry (net otherwise) */ -#define RTF_REJECT 0x8 /* host or net unreachable */ -#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ -#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ -#define RTF_DONE 0x40 /* message confirmed */ -#define RTF_MASK 0x80 /* subnet mask present */ -#define RTF_CLONING 0x100 /* generate new routes on use */ -#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ -#define RTF_LLINFO 0x400 /* generated by ARP or ESIS */ -#define RTF_STATIC 0x800 /* manually added */ -#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ -#define RTF_PROTO3 0x2000 /* protocol specific routing flag */ -#define RTF_PROTO2 0x4000 /* protocol specific routing flag */ -#define RTF_PROTO1 0x8000 /* protocol specific routing flag */ - -#define RTM_VERSION 3 /* Up the ante and ignore older versions */ - -#define RTM_ADD 0x1 /* Add Route */ -#define RTM_DELETE 0x2 /* Delete Route */ -#define RTM_CHANGE 0x3 /* Change Metrics or flags */ -#define RTM_GET 0x4 /* Report Metrics */ -#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */ -#define RTM_REDIRECT 0x6 /* Told to use different route */ -#define RTM_MISS 0x7 /* Lookup failed on this address */ -#define RTM_LOCK 0x8 /* fix specified metrics */ -#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ -#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ -#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ -#define RTM_NEWADDR 0xc /* address being added to iface */ -#define RTM_DELADDR 0xd /* address being removed from iface */ -#define RTM_IFINFO 0xe /* iface going up/down etc. */ - -#define RTV_MTU 0x1 /* init or lock _mtu */ -#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ -#define RTV_EXPIRE 0x4 /* init or lock _hopcount */ -#define RTV_RPIPE 0x8 /* init or lock _recvpipe */ -#define RTV_SPIPE 0x10 /* init or lock _sendpipe */ -#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ -#define RTV_RTT 0x40 /* init or lock _rtt */ -#define RTV_RTTVAR 0x80 /* init or lock _rttvar */ - -/* - * Bitmask values for rtm_addr. - */ -#define RTA_DST 0x1 /* destination sockaddr present */ -#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ -#define RTA_NETMASK 0x4 /* netmask sockaddr present */ -#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ -#define RTA_IFP 0x10 /* interface name sockaddr present */ -#define RTA_IFA 0x20 /* interface addr sockaddr present */ -#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ -#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ - -/* - * Index offsets for sockaddr array for alternate internal encoding. - */ -#define RTAX_DST 0 /* destination sockaddr present */ -#define RTAX_GATEWAY 1 /* gateway sockaddr present */ -#define RTAX_NETMASK 2 /* netmask sockaddr present */ -#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ -#define RTAX_IFP 4 /* interface name sockaddr present */ -#define RTAX_IFA 5 /* interface addr sockaddr present */ -#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ -#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ -#define RTAX_MAX 8 /* size of array to allocate */ - -struct rt_msghdr { - uint16 rtm_msglen; - uint8 rtm_version; - uint8 rtm_type; - - uint16 rtm_index; - int rtm_flags; - int rtm_addrs; - int rtm_seq; - int rtm_errno; - int rtm_use; - uint32 rtm_inits; - struct rt_metrics rtm_rmx; -}; - -struct rt_addrinfo { - int rti_addrs; - struct sockaddr *rti_info[RTAX_MAX]; - int rti_flags; - struct ifaddr *rti_ifa; - struct ifnet *rti_ifp; - struct rt_msghdr *rti_rtm; -}; - -struct route_cb { - int32 ip_count; /* how many AF_INET structures we have */ - int32 any_count; /* total of all above... */ -}; - -struct walkarg { - int w_op; - int w_arg; - int w_given; - int w_needed; - int w_tmemsize; - char * w_where; - char * w_tmem; -}; - -/* - * Routing statistics. - */ -struct rtstat { - int32 rts_badredirect; /* bogus redirect calls */ - int32 rts_dynamic; /* routes created by redirects */ - int32 rts_newgateway; /* routes modified by redirects */ - int32 rts_unreach; /* lookups which failed */ - int32 rts_wildcard; /* lookups satisfied by a wildcard */ -}; - -#define RTFREE(rt) do { \ - if ((rt)->rt_refcnt <= 1) \ - rtfree(rt); \ - else \ - (rt)->rt_refcnt--; \ -} while (0) - -extern struct rtstat rtstat; -extern struct radix_node_head *rt_tables[AF_MAX+1]; - -void route_init(void); - -int rtinit (struct ifaddr *, int, int); -void rtalloc (struct route *); -struct rtentry *rtalloc1 (struct sockaddr *, int); -void rtfree (struct rtentry *); -int rtrequest (int, struct sockaddr *, - struct sockaddr *, struct sockaddr *, int, - struct rtentry **); -void rt_maskedcopy(struct sockaddr *src, - struct sockaddr *dst, - struct sockaddr *netmask); -int rt_setgate (struct rtentry *, struct sockaddr *, - struct sockaddr *); - -struct radix_node_head ** get_rt_tables(void); - -#endif /* NET_ROUTE_H */ +#endif /* _NET_ROUTE_H */ diff --git a/headers/posix/netdb.h b/headers/posix/netdb.h index d00d5871a2..b608d8305d 100644 --- a/headers/posix/netdb.h +++ b/headers/posix/netdb.h @@ -1,6 +1,4 @@ /* - * ++Copyright++ 1980, 1983, 1988, 1993 - * - * Copyright (c) 1980, 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -80,20 +78,12 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - - * --Copyright-- */ - -/* - * @(#)netdb.h 8.1 (Berkeley) 6/2/93 - * $Id$ - */ - #ifndef _NETDB_H_ #define _NETDB_H_ #include -#include +#include #include #include #include diff --git a/headers/posix/netinet/icmp_var.h b/headers/posix/netinet/icmp_var.h deleted file mode 100644 index 4cad177422..0000000000 --- a/headers/posix/netinet/icmp_var.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Parts of this file are covered under the following copyright */ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef NETINET_ICMP_VAR_H -#define NETINET_ICMP_VAR_H - -#include "netinet/ip_icmp.h" - -struct icmpstat { - int32 icps_oldicmp; - int32 icps_oldshort; - int32 icps_badcode; - int32 icps_badlen; - int32 icps_checksum; - int32 icps_tooshort; - int32 icps_error; - int32 icps_reflect; - int32 icps_outhist[ICMP_MAXTYPE + 1]; - int32 icps_inhist[ICMP_MAXTYPE + 1]; -}; - -//#ifdef _KERNEL_MODE -//struct icmpstat icmpstat; -//#endif - -#endif /* NETINET_ICMP_VAR_H */ diff --git a/headers/posix/netinet/if_ether.h b/headers/posix/netinet/if_ether.h deleted file mode 100644 index 0cd684ee14..0000000000 --- a/headers/posix/netinet/if_ether.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)if_ether.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef NETINET_IF_ETHER_H -#define NETINET_IF_ETHER_H - -#include "net/if_arp.h" - -/* - * Ethernet address - 6 octets - * this is only used by the ethers(3) functions. - */ -struct ether_addr { - uint8 ether_addr_octet[6]; -}; - -/* - * Some Ethernet constants. - */ -#define ETHER_ADDR_LEN 6 /* Ethernet address length */ -#define ETHER_TYPE_LEN 2 /* Ethernet type field length */ -#define ETHER_CRC_LEN 4 /* Ethernet CRC lenght */ -#define ETHER_HDR_LEN ((ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN) -#define ETHER_MIN_LEN 64 /* Minimum frame length, CRC included */ -#define ETHER_MAX_LEN 1518 /* Maximum frame length, CRC included */ - -struct ether_header { - uint8 ether_dhost[ETHER_ADDR_LEN]; - uint8 ether_shost[ETHER_ADDR_LEN]; - uint16 ether_type; -}; - -#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ -#define ETHERTYPE_IP 0x0800 /* IP protocol */ -#define ETHERTYPE_ARP 0x0806 /* address resolution protocol */ -#define ETHERTYPE_REVARP 0x8035 /* reverse addr resolution protocol */ -#define ETHERTYPE_8021Q 0x8100 /* IEEE 802.1Q VLAN tagging */ -#define ETHERTYPE_IPV6 0x86DD /* IPv6 protocol */ -#define ETHERTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ -#define ETHERTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ -#define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ - -#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ - -#define ETHERMTU (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) -#define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) - - -//#ifdef _NETWORK_STACK - -/* - * Macro to map an IP multicast address to an Ethernet multicast address. - * The high-order 25 bits of the Ethernet address are statically assigned, - * and the low-order 23 bits are taken from the low end of the IP address. - */ -#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \ - /* struct in_addr *ipaddr; */ \ - /* u_int8_t enaddr[ETHER_ADDR_LEN]; */ \ -{ \ - (enaddr)[0] = 0x01; \ - (enaddr)[1] = 0x00; \ - (enaddr)[2] = 0x5e; \ - (enaddr)[3] = ((uint8 *)ipaddr)[1] & 0x7f; \ - (enaddr)[4] = ((uint8 *)ipaddr)[2]; \ - (enaddr)[5] = ((uint8 *)ipaddr)[3]; \ -} - -/* - * Macro to map an IPv6 multicast address to an Ethernet multicast address. - * The high-order 16 bits of the Ethernet address are statically assigned, - * and the low-order 32 bits are taken from the low end of the IPv6 address. - */ -#define ETHER_MAP_IPV6_MULTICAST(ip6addr, enaddr) \ - /* struct in6_addr *ip6addr; */ \ - /* u_int8_t enaddr[ETHER_ADDR_LEN]; */ \ -{ \ - (enaddr)[0] = 0x33; \ - (enaddr)[1] = 0x33; \ - (enaddr)[2] = ((u_int8_t *)ip6addr)[12]; \ - (enaddr)[3] = ((u_int8_t *)ip6addr)[13]; \ - (enaddr)[4] = ((u_int8_t *)ip6addr)[14]; \ - (enaddr)[5] = ((u_int8_t *)ip6addr)[15]; \ -} -//#endif - -/* - * Structure shared between the ethernet driver modules and - * the address resolution code. For example, each ec_softc or il_softc - * begins with this structure. - */ -struct arpcom { - struct ifnet ac_if; /* network-visible interface */ - uint8 ac_enaddr[ETHER_ADDR_LEN]; /* ethernet hardware address */ - struct in_addr ac_ipaddr; - char ac__pad[2]; /* pad for some machines */ -// struct ether_multi *ac_multiaddrs; /* list of ether multicast addrs */ - int ac_multicnt; /* length of ac_multiaddrs list */ -}; - -struct ether_device { - struct arpcom sc_ac; - struct ether_device *next; /* next ether_device */ -}; -#define sc_if sc_ac.ac_if -#define sc_addr sc_ac.ac_enaddr - -struct ether_arp { - struct arphdr ea_hdr; - u_char arp_sha[6]; - u_char arp_spa[4]; - u_char arp_tha[6]; - u_char arp_tpa[4]; -}; -#define arp_hrd ea_hdr.ar_hrd -#define arp_pro ea_hdr.ar_pro -#define arp_hln ea_hdr.ar_hln -#define arp_pln ea_hdr.ar_pln -#define arp_op ea_hdr.ar_op - -struct llinfo_arp { - struct llinfo_arp *la_next; - struct llinfo_arp *la_prev; - struct rtentry *la_rt; - struct mbuf *la_hold; - int32 la_asked; -}; - -#define la_timer la_rt->rt_rmx.rmx_expire - -struct sockaddr_inarp { - uint8 sin_len; - uint8 sin_family; - uint16 sin_port; - struct in_addr sin_addr; - struct in_addr sin_srcaddr; - uint16 sin_tos; - uint16 sin_other; -}; -#define SIN_PROXY 1 - -/* - * IP and ethernet specific routing flags - */ -#define RTF_USETRAILERS RTF_PROTO1 /* use trailers */ -#define RTF_ANNOUNCE RTF_PROTO2 /* announce new arp entry */ -#define RTF_PERMANENT_ARP RTF_PROTO3 /* only manual overwrite of entry */ - -//#ifdef _NETWORK_STACK - -int arpresolve(struct arpcom *ac, struct rtentry *rt, struct mbuf *m, - struct sockaddr *dst, uint8 *desten); -//void arpwhohas(struct arpcom *ac, struct in_addr *ia); - - -//#else - -char *ether_ntoa (struct ether_addr *); -struct ether_addr *ether_aton (char *); -int ether_ntohost (char *, struct ether_addr *); -int ether_hostton (char *, struct ether_addr *); -int ether_line(char *line, struct ether_addr *e, char *hostname); - -//#endif - -#endif /* NETINET_IF_ETHER_H */ - diff --git a/headers/posix/netinet/in.h b/headers/posix/netinet/in.h index 84f0b91529..0d39124033 100644 --- a/headers/posix/netinet/in.h +++ b/headers/posix/netinet/in.h @@ -6,20 +6,21 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif -typedef unsigned short in_port_t; -typedef unsigned long in_addr_t; +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; /* We can't include since we are a posix file, * and we are not allowed to import all the BeOS types here. */ #ifndef htonl - extern unsigned long __swap_int32(unsigned long); /* private */ - extern unsigned short __swap_int16(unsigned short); /* private */ + extern uint32_t __swap_int32(uint32_t); /* private */ + extern uint16_t __swap_int16(uint16_t); /* private */ #if BYTE_ORDER == LITTLE_ENDIAN #define htonl(x) __swap_int32(x) #define ntohl(x) __swap_int32(x) @@ -73,11 +74,11 @@ struct in_addr { * IP Version 4 socket address. */ struct sockaddr_in { - uint8 sin_len; - uint8 sin_family; - uint16 sin_port; + uint8_t sin_len; + uint8_t sin_family; + uint16_t sin_port; struct in_addr sin_addr; - int8 sin_zero[24]; + int8_t sin_zero[24]; }; /* the address is therefore at sin_addr.s_addr */ @@ -99,7 +100,7 @@ struct sockaddr_in { #define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ #define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ -#define __IPADDR(x) ((uint32) htonl((uint32)(x))) +#define __IPADDR(x) ((uint32_t)htonl((uint32_t)(x))) #define INADDR_ANY __IPADDR(0x00000000) #define INADDR_LOOPBACK __IPADDR(0x7f000001) @@ -114,27 +115,27 @@ struct sockaddr_in { #define INADDR_NONE __IPADDR(0xffffffff) -#define IN_CLASSA(i) (((uint32)(i) & __IPADDR(0x80000000)) == \ +#define IN_CLASSA(i) (((uint32_t)(i) & __IPADDR(0x80000000)) == \ __IPADDR(0x00000000)) #define IN_CLASSA_NET __IPADDR(0xff000000) #define IN_CLASSA_NSHIFT 24 #define IN_CLASSA_HOST __IPADDR(0x00ffffff) #define IN_CLASSA_MAX 128 -#define IN_CLASSB(i) (((uint32)(i) & __IPADDR(0xc0000000)) == \ +#define IN_CLASSB(i) (((uint32_t)(i) & __IPADDR(0xc0000000)) == \ __IPADDR(0x80000000)) #define IN_CLASSB_NET __IPADDR(0xffff0000) #define IN_CLASSB_NSHIFT 16 #define IN_CLASSB_HOST __IPADDR(0x0000ffff) #define IN_CLASSB_MAX 65536 -#define IN_CLASSC(i) (((uint32)(i) & __IPADDR(0xe0000000)) == \ +#define IN_CLASSC(i) (((uint32_t)(i) & __IPADDR(0xe0000000)) == \ __IPADDR(0xc0000000)) #define IN_CLASSC_NET __IPADDR(0xffffff00) #define IN_CLASSC_NSHIFT 8 #define IN_CLASSC_HOST __IPADDR(0x000000ff) -#define IN_CLASSD(i) (((uint32)(i) & __IPADDR(0xf0000000)) == \ +#define IN_CLASSD(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ __IPADDR(0xe0000000)) /* These ones aren't really net and host fields, but routing needn't know. */ #define IN_CLASSD_NET __IPADDR(0xf0000000) @@ -143,8 +144,8 @@ struct sockaddr_in { #define IN_MULTICAST(i) IN_CLASSD(i) -#define IN_EXPERIMENTAL(i) (((uint32)(i) & 0xf0000000) == 0xf0000000) -#define IN_BADCLASS(i) (((uint32)(i) & 0xf0000000) == 0xf0000000) +#define IN_EXPERIMENTAL(i) (((uint32_t)(i) & 0xf0000000) == 0xf0000000) +#define IN_BADCLASS(i) (((uint32_t)(i) & 0xf0000000) == 0xf0000000) #define IP_MAX_MEMBERSHIPS 20 @@ -163,7 +164,7 @@ int in_localaddr (struct in_addr); void in_socktrim (struct sockaddr_in*); /* uint16 in_cksum (struct mbuf *, int); */ struct mbuf; -uint16 in_cksum(struct mbuf *m, int len, int off); +uint16_t in_cksum(struct mbuf *m, int len, int off); #ifdef __cplusplus } diff --git a/headers/posix/netinet/in_pcb.h b/headers/posix/netinet/in_pcb.h deleted file mode 100644 index 4b0e7be659..0000000000 --- a/headers/posix/netinet/in_pcb.h +++ /dev/null @@ -1,71 +0,0 @@ -/* in_pcb.h - * internet protcol control blocks - */ - -//#include -#include -#include -#include -#include -#include - -#ifndef _NETINET_INPCB_H -#define _NETINET_INPCB_H - -enum { - INP_HDRINCL = 0x01, - INP_RECVOPTS = 0x02, - INP_RECVRETOPTS = 0x04, - INP_RECVDSTADDR = 0x08 /* receive IP destination as control inf. */ -}; -#define INP_CONTROLOPT (INP_RECVOPTS | INP_RECVRETOPTS | INP_RECVDSTADDR) - -/* Constants for in_pcblookup */ -enum { - INPLOOKUP_WILDCARD = 1, - INPLOOKUP_SETLOCAL = 2, - INPLOOKUP_IPV6 = 4 -}; - -struct inpcb { - struct inpcb *inp_next; - struct inpcb *inp_prev; - struct inpcb *inp_head; - - struct in_addr faddr; /* foreign address */ - uint16 fport; /* foreign port # */ - struct in_addr laddr; /* local address */ - uint16 lport; /* local port # */ - - struct socket *inp_socket; - char *inp_ppcb; /* pointer to a per protocol pcb*/ - struct ip inp_ip; /* header prototype */ - int inp_flags; /* flags */ - struct mbuf *inp_options; /* IP options */ - /* more will be required */ - struct route inp_route; /* the route to host */ -}; - -int in_pcbinit (void); -int in_pcballoc (struct socket *, struct inpcb *); -int in_pcbbind (struct inpcb *, struct mbuf *); -int in_pcbconnect (struct inpcb *, struct mbuf *); -void in_pcbdetach (struct inpcb *); -int in_pcbdisconnect (struct inpcb *); -void in_losing (struct inpcb *); -void in_setpeeraddr (struct inpcb *, struct mbuf *); -void in_setsockaddr (struct inpcb *, struct mbuf *); - -struct inpcb *in_pcblookup(struct inpcb *head, struct in_addr faddr, - uint16 fport_a, struct in_addr laddr, - uint16 lport_a, int flags); -struct rtentry *in_pcbrtentry (struct inpcb *); -void in_pcbnotify (struct inpcb *, struct sockaddr *, - uint16, struct in_addr, uint16, - int, void (*)(struct inpcb *, int)); - -/* helpful macro's */ -#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) - -#endif /* _NETINET_INPCB_H */ - diff --git a/headers/posix/netinet/in_systm.h b/headers/posix/netinet/in_systm.h deleted file mode 100644 index f74af50fac..0000000000 --- a/headers/posix/netinet/in_systm.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - *The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - *This product includes software developed by the University of - *California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - *@(#)in_systm.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef NETINET_IN_SYSTM_H -#define NETINET_IN_SYSTM_H - -#include -/* - * Miscellaneous internetwork - * definitions for kernel. - */ - -/* - * Network types. - * - * Internally the system keeps counters in the headers with the bytes - * swapped so that VAX instructions will work on them. It reverses - * the bytes before transmission at each protocol level. The n_ types - * represent the types with the bytes in ``high-ender'' order. - */ -typedef uint16_t n_short; /* short as received from the net */ -typedef uint32_t n_long; /* long as received from the net */ - -typedef uint32_t n_time; /* ms since 00:00 GMT, byte rev */ - -#define iptime() (htonl((uint32_t)real_time_clock_usecs())) - -#endif /* NETINET_IN_SYSTM_H */ - - diff --git a/headers/posix/netinet/in_var.h b/headers/posix/netinet/in_var.h deleted file mode 100644 index d42741edb7..0000000000 --- a/headers/posix/netinet/in_var.h +++ /dev/null @@ -1,66 +0,0 @@ -/* in_var.h */ -#ifndef NETINET_IN_VAR_H -#define NETINET_IN_VAR_H - -#include -#include - -struct in_ifaddr { - struct ifaddr ia_ifa; - struct in_ifaddr *ia_next; - - uint32 ia_net; - uint32 ia_netmask; - uint32 ia_subnet; - uint32 ia_subnetmask; - struct in_addr ia_netbroadcast; - struct sockaddr_in ia_addr; - struct sockaddr_in ia_dstaddr; /* broadcast address */ - struct sockaddr_in ia_sockmask; - /*XXX - milticast address list */ -}; -#define ia_ifp ia_ifa.ifa_ifp -#define ia_flags ia_ifa.ifa_flags -#define ia_broadaddr ia_dstaddr - -#define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) -#define sintosa(sin) ((struct sockaddr *)(sin)) - -/* used to pass in additional information, such as aliases */ -struct in_aliasreq { - char ifa_name[IFNAMSIZ]; - struct sockaddr_in ifra_addr; - struct sockaddr_in ifra_broadaddr; -#define ifra_dstaddr ifra_broadaddr - struct sockaddr_in ifra_mask; -}; - - -struct in_multi { - struct in_addr inm_addr; - struct ifnet *inm_ifp; - struct in_ifaddr *inm_ia; - uint inm_refcount; - uint inm_timer; - struct in_multi *next; - struct in_multi **prev; - uint inm_state; -}; - -/* - * Given a pointer to an in_ifaddr (ifaddr), - * return a pointer to the addr as a sockaddr_in. - */ - -#define IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr)) - -// extern struct in_ifaddr *in_ifaddr; - - int in_control(struct socket *so, int cmd, char *data, struct ifnet *ifp); - int in_ifinit(struct ifnet *dev, struct in_ifaddr *ia, struct sockaddr_in *sin, - int scrub); - int inetctlerr(int cmd); - struct in_ifaddr *get_primary_addr(void); - -#endif /* NETINET_IN_VAR_H */ - diff --git a/headers/posix/netinet/ip.h b/headers/posix/netinet/ip.h index ddf0ed3ea0..4bdfdea604 100644 --- a/headers/posix/netinet/ip.h +++ b/headers/posix/netinet/ip.h @@ -5,7 +5,6 @@ #ifndef _NETINET_IP_H #define _NETINET_IP_H -#include #include #include @@ -81,10 +80,10 @@ struct ip_timestamp { ipt_oflw:4; #endif union ipt_timestamp { - n_time ipt_time[1]; + uint32_t ipt_time[1]; struct ipt_ta { struct in_addr ipt_addr; - n_time ipt_time; + uint32_t ipt_time; } ipt_ta; } ipt_timestamp; }; diff --git a/headers/posix/netinet/ip_icmp.h b/headers/posix/netinet/ip_icmp.h index 84e5ac6e5d..ca441da97b 100644 --- a/headers/posix/netinet/ip_icmp.h +++ b/headers/posix/netinet/ip_icmp.h @@ -50,27 +50,27 @@ struct icmp { uint8_t ih_pptr; struct in_addr ih_gwaddr; struct ih_idseq { - n_short icd_id; - n_short icd_seq; + uint16_t icd_id; + uint16_t icd_seq; } ih_idseq; int32_t ih_void; /* ICMP_UNREACH_NEEDFRAG (RFC 1191) */ struct ih_pmtu { - n_short ipm_void; - n_short ipm_nextmtu; + uint16_t ipm_void; + uint16_t ipm_nextmtu; } ih_pmtu; } icmp_hun; union { struct id_ts { - n_time its_otime; - n_time its_rtime; - n_time its_ttime; + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; } id_ts; struct id_ip { struct ip idi_ip; } id_ip; - uint32 id_mask; + uint32_t id_mask; char id_data[1]; } icmp_dun; }; diff --git a/headers/posix/netinet/tcp_debug.h b/headers/posix/netinet/tcp_debug.h deleted file mode 100644 index 4a8008b3eb..0000000000 --- a/headers/posix/netinet/tcp_debug.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_debug.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef NETINET_TCP_DEBUG_H_ -#define NETINET_TCP_DEBUG_H_ - -struct tcp_debug { - n_time td_time; - short td_act; - short td_ostate; - caddr_t td_tcb; - struct tcpiphdr td_ti; - short td_req; - struct tcpcb td_cb; -}; - -#define TA_INPUT 0 -#define TA_OUTPUT 1 -#define TA_USER 2 -#define TA_RESPOND 3 -#define TA_DROP 4 - -//#ifdef TANAMES -//char *tanames[] = -// { "input", "output", "user", "respond", "drop" }; -//#endif /* TANAMES */ - -#define TCP_NDEBUG 100 -struct tcp_debug tcp_debug[TCP_NDEBUG]; -int tcp_debx; -#endif /* _NETINET_TCP_DEBUG_H_ */ diff --git a/headers/posix/netinet/tcp_fsm.h b/headers/posix/netinet/tcp_fsm.h deleted file mode 100644 index a8150f8034..0000000000 --- a/headers/posix/netinet/tcp_fsm.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_fsm.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef _NETINET_TCP_FSM_H_ -#define _NETINET_TCP_FSM_H_ - -/* - * TCP FSM state definitions. - * Per RFC793, September, 1981. - */ - -#define TCP_NSTATES 11 - -#define TCPS_CLOSED 0 /* closed */ -#define TCPS_LISTEN 1 /* listening for connection */ -#define TCPS_SYN_SENT 2 /* active, have sent syn */ -#define TCPS_SYN_RECEIVED 3 /* have sent and received syn */ -/* states < TCPS_ESTABLISHED are those where connections not established */ -#define TCPS_ESTABLISHED 4 /* established */ -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -/* states > TCPS_CLOSE_WAIT are those where user has closed */ -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define TCPS_CLOSING 7 /* closed xchd FIN; await ACK */ -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ - -#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) -#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) -#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) - -#ifdef TCPOUTFLAGS -/* - * Flags used when sending segments in tcp_output. - * Basic flags (TH_RST,TH_ACK,TH_SYN,TH_FIN) are totally - * determined by state, with the proviso that TH_FIN is sent only - * if all data queued for output is included in the segment. - */ -u_char tcp_outflags[TCP_NSTATES] = { - TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, - TH_ACK, TH_ACK, - TH_FIN|TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, -}; -#endif /* TCPOUTFLAGS */ - -#ifdef TCPSTATES -char *tcpstates[] = { - "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", - "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", - "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", -}; -#endif /* TCPSTATES */ -#endif /* _NETINET_TCP_FSM_H_ */ diff --git a/headers/posix/netinet/tcp_seq.h b/headers/posix/netinet/tcp_seq.h deleted file mode 100644 index 0d707bbf77..0000000000 --- a/headers/posix/netinet/tcp_seq.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tcp_seq.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef _NETINET_TCP_SEQ_H_ -#define _NETINET_TCP_SEQ_H_ - -/* - * TCP sequence numbers are 32 bit integers operated - * on with modular arithmetic. These macros can be - * used to compare such integers. - */ -#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) -#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) -#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) -#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) - -/* - * Macros to initialize tcp sequence numbers for - * send and receive from initial send and receive - * sequence numbers. - */ -#define tcp_rcvseqinit(tp) \ - (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 - -#define tcp_sendseqinit(tp) \ - (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = \ - (tp)->iss - -#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ - -//#ifdef _NETWORK_STACK -extern tcp_seq tcp_iss; /* tcp initial send seq # */ -//#endif /* _NETWORK_STACK */ - -#endif /* _NETINET_TCP_SEQ_H_ */ diff --git a/headers/posix/netinet/tcp_timer.h b/headers/posix/netinet/tcp_timer.h deleted file mode 100644 index fd3e9618e8..0000000000 --- a/headers/posix/netinet/tcp_timer.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - *The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef NETINET_TCP_TIMERS_H -#define NETINET_TCP_TIMERS_H - -/* - * Definitions of the TCP timers. These timers are counted - * down PR_SLOWHZ times a second. - */ -#define TCPT_NTIMERS 4 - -#define TCPT_REXMT 0 /* retransmission timer */ -#define TCPT_PERSIST 1 /* presist timer */ -#define TCPT_KEEP 2 /* keeplaive timer or conn est timer */ -#define TCPT_2MSL 3 /* 2MSL timer or FIN_WAIT_2 timer */ - -/* - * The TCPT_REXMT timer is used to force retransmissions. - * The TCP has the TCPT_REXMT timer set whenever segments - * have been sent for which ACKs are expected but not yet - * received. If an ACK is received which advances tp->snd_una, - * then the retransmit timer is cleared (if there are no more - * outstanding segments) or reset to the base value (if there - * are more ACKs expected). Whenever the retransmit timer goes off, - * we retransmit one unacknowledged segment, and do a backoff - * on the retransmit timer. - * - * The TCPT_PERSIST timer is used to keep window size information - * flowing even if the window goes shut. If all previous transmissions - * have been acknowledged (so that there are no retransmissions in progress), - * and the window is too small to bother sending anything, then we start - * the TCPT_PERSIST timer. When it expires, if the window is nonzero, - * we go to transmit state. Otherwise, at intervals send a single byte - * into the peer's window to force him to update our window information. - * We do this at most as often as TCPT_PERSMIN time intervals, - * but no more frequently than the current estimate of round-trip - * packet time. The TCPT_PERSIST timer is cleared whenever we receive - * a window update from the peer. - * - * The TCPT_KEEP timer is used to keep connections alive. If an - * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, - * but not yet established, then we drop the connection. Once the connection - * is established, if the connection is idle for TCPTV_KEEP_IDLE time - * (and keepalives have been enabled on the socket), we begin to probe - * the connection. We force the peer to send us a segment by sending: - * - * This segment is (deliberately) outside the window, and should elicit - * an ack segment in response from the peer. If, despite the TCPT_KEEP - * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE - * amount of time probing, then we drop the connection. - */ - -/* - * Time constants. - */ -#define TCPTV_MSL ( 30*PR_SLOWHZ ) /* max seg lifetime (hah!) */ -#define TCPTV_SRTTBASE 0 /* base roundtrip time; - * if 0, no idea yet */ -#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ ) /* assumed RTT if no info */ - -#define TCPTV_PERSMIN ( 5*PR_SLOWHZ ) /* retransmit persistance */ -#define TCPTV_PERSMAX ( 60*PR_SLOWHZ ) /* maximum persist interval */ - -#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ ) /* initial connect keep alive */ -#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ -#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ ) /* default probe interval */ -#define TCPTV_KEEPCNT 8 /* max probes before drop */ - -#define TCPTV_MIN ( 1*PR_SLOWHZ ) /* minimum allowable value */ -#define TCPTV_REXMTMAX ( 64*PR_SLOWHZ ) /* max allowable REXMT value */ - -#define TCP_LINGERTIME 120 /* at most 2 minutes... */ -#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ - -//#ifdef TCPTIMERS -//char *tcptimers[] = -// { "REXMT", "PERSIST", "KEEP", "2MSL" }; -//#endif /* TCPTIMERS */ -extern char *tcptimers[]; - -/* - * Force a time value to be in a certain range. - */ -#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ - (tv) = (value); \ - if ((tv) < (tvmin)) \ - (tv) = (tvmin); \ - else if ((tv) > (tvmax)) \ - (tv) = (tvmax); \ -} - -//#ifdef _NETWORK_STACK -extern int tcptv_keep_init; -extern int tcp_keepidle; /* time before keepalive probes begin */ -extern int tcp_keepintvl; /* time between keepalive probes */ -extern int tcp_maxidle; /* time to drop after starting probes */ -extern int tcp_ttl; /* time to live for TCP segs */ -extern int tcp_backoff[]; - - -//#endif /* _NETWORK_STACK */ - -#endif /* NETINET_TCP_TIMERS_H */ diff --git a/headers/posix/netinet/tcp_var.h b/headers/posix/netinet/tcp_var.h deleted file mode 100644 index 586c2b717a..0000000000 --- a/headers/posix/netinet/tcp_var.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - *The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef NETINET_TCP_VAR_H -#define NETINET_TCP_VAR_H - -/* - * Tcp control block, one per tcp connection - */ -struct tcpcb { - struct tcpiphdr *seg_next; - struct tcpiphdr *seg_prev; - int16 t_state; /* state of this connection */ - int16 t_timer[TCPT_NTIMERS]; /* tcp timers */ - int16 t_rxtshift; /* log(2) of rexmt exp. backoff */ - int16 t_rxtcur; /* current retransmit value */ - int16 t_dupacks; /* consecutive dup acks recd */ - uint16 t_maxseg; /* maximum segment size */ - int8 t_force; /* 1 if forcing out a byte */ - uint16 t_flags; - - struct tcpiphdr *t_template; /* skeletal packet for transmit */ - struct inpcb *t_inpcb; /* back pointer to internet pcb */ -/* - * The following fields are used as in the protocol specification. - * See RFC783, Dec. 1981, page 21. - */ -/* send sequence variables */ - tcp_seq snd_una; /* send unacknowledged */ - tcp_seq snd_nxt; /* send next */ - tcp_seq snd_up; /* send urgent pointer */ - tcp_seq snd_wl1; /* window update seg seq number */ - tcp_seq snd_wl2; /* window update seg ack number */ - tcp_seq iss; /* initial send sequence number */ - unsigned long snd_wnd; /* send window */ - -/* receive sequence variables */ - unsigned long rcv_wnd; /* receive window */ - tcp_seq rcv_nxt; /* receive next */ - tcp_seq rcv_up; /* receive urgent pointer */ - tcp_seq irs; /* initial receive sequence number */ - -/* - * Additional variables for this implementation. - */ -/* receive variables */ - tcp_seq rcv_adv; /* advertised window */ -/* retransmit variables */ - tcp_seq snd_max; /* highest sequence number sent; - * used to recognize retransmits - */ -/* congestion control (for slow start, source quench, retransmit after loss) */ - unsigned long snd_cwnd; /* congestion-controlled window */ - unsigned long snd_ssthresh; /* snd_cwnd size threshhold for - * for slow start exponential to - * linear switch - */ - uint16 t_maxopd; /* mss plus options */ - uint16 t_peermss; /* peer's maximum segment size */ - -/* - * transmit timing stuff. See below for scale of srtt and rttvar. - * "Variance" is actually smoothed difference. - */ - int16 t_idle; /* inactivity time */ - int16 t_rtt; /* round trip time */ - tcp_seq t_rtseq; /* sequence number being timed */ - uint16 t_srtt; /* smoothed round-trip time */ - uint16 t_rttvar; /* variance in round-trip time */ - uint16 t_rttmin; /* minimum rtt allowed */ - uint32 max_sndwnd; /* largest window peer has offered */ - -/* out-of-band data */ - int8 t_oobflags; /* have some */ - int8 t_iobc; /* input character */ - int16 t_softerror; /* possible error, not yet reported... */ -/* RFC 1323 variables */ - uint8 snd_scale; /* window scaling for send window */ - uint8 rcv_scale; /* window scaling for recv window */ - uint8 request_r_scale; /* pending window scaling */ - uint8 requested_s_scale; - uint32 ts_recent; /* timestamp echo data */ - uint32 ts_recent_age; /* when last updated */ - tcp_seq last_ack_sent; -}; - -#define intotcpcb(ip) ((struct tcpcb*)(ip)->inp_ppcb) -#define sototcpcb(so) (intotcpcb(sotoinpcb(so))) - -#define TF_ACKNOW 0x0001 /* send ACK immeadiately */ -#define TF_DELACK 0x0002 /* send ACK, but try to delay it */ -#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ -#define TF_NOOPT 0x0008 /* don't use tcp options */ -#define TF_SENTFIN 0x0010 /* have sent FIN */ -#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ -#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ -#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ -#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ -#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ -#define TF_SIGNATURE 0x0400 /* require TCP MD5 signature */ - -#define TCPOOB_HAVEDATA 0x01 /* we have TCP OOB data */ -#define TCPOOB_HADDATA 0x02 /* we've had some TCP OOB data */ - -/* - * The smoothed round-trip time and estimated variance - * are stored as fixed point numbers scaled by the values below. - * For convenience, these scales are also used in smoothing the average - * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). - * With these scales, srtt has 3 bits to the right of the binary point, - * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the - * binary point, and is smoothed with an ALPHA of 0.75. - */ -#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ -#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ -#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ -#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ - -#define TCP_REXMTVAL(tp) \ - ((((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) >> 2) -/* - * TCP statistics. - * Many of these should be kept per connection, - * but that's inconvenient at the moment. - */ -struct tcpstat { - uint32 tcps_connattempt; /* connections initiated */ - uint32 tcps_accepts; /* connections accepted */ - uint32 tcps_connects; /* connections established */ - uint32 tcps_drops; /* connections dropped */ - uint32 tcps_conndrops; /* embryonic connections dropped */ - uint32 tcps_closed; /* conn. closed (includes drops) */ - uint32 tcps_segstimed; /* segs where we tried to get rtt */ - uint32 tcps_rttupdated; /* times we succeeded */ - uint32 tcps_delack; /* delayed acks sent */ - uint32 tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ - uint32 tcps_rexmttimeo; /* retransmit timeouts */ - uint32 tcps_persisttimeo; /* persist timeouts */ - uint32 tcps_persistdrop; /* connections dropped in persist */ - uint32 tcps_keeptimeo; /* keepalive timeouts */ - uint32 tcps_keepprobe; /* keepalive probes sent */ - uint32 tcps_keepdrops; /* connections dropped in keepalive */ - - uint32 tcps_sndtotal; /* total packets sent */ - uint32 tcps_sndpack; /* data packets sent */ - uint64 tcps_sndbyte; /* data bytes sent */ - uint32 tcps_sndrexmitpack; /* data packets retransmitted */ - uint64 tcps_sndrexmitbyte; /* data bytes retransmitted */ - uint64 tcps_sndrexmitfast; /* Fast retransmits */ - uint32 tcps_sndacks; /* ack-only packets sent */ - uint32 tcps_sndprobe; /* window probes sent */ - uint32 tcps_sndurg; /* packets sent with URG only */ - uint32 tcps_sndwinup; /* window update-only packets sent */ - uint32 tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ - - uint32 tcps_rcvtotal; /* total packets received */ - uint32 tcps_rcvpack; /* packets received in sequence */ - uint64 tcps_rcvbyte; /* bytes received in sequence */ - uint32 tcps_rcvbadsum; /* packets received with ccksum errs */ - uint32 tcps_rcvbadoff; /* packets received with bad offset */ - uint32 tcps_rcvmemdrop; /* packets dropped for lack of memory */ - uint32 tcps_rcvnosec; /* packets dropped for lack of ipsec */ - uint32 tcps_rcvshort; /* packets received too short */ - uint32 tcps_rcvduppack; /* duplicate-only packets received */ - uint64 tcps_rcvdupbyte; /* duplicate-only bytes received */ - uint32 tcps_rcvpartduppack; /* packets with some duplicate data */ - uint64 tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ - uint32 tcps_rcvoopack; /* out-of-order packets received */ - uint64 tcps_rcvoobyte; /* out-of-order bytes received */ - uint32 tcps_rcvpackafterwin; /* packets with data after window */ - uint64 tcps_rcvbyteafterwin; /* bytes rcvd after window */ - uint32 tcps_rcvafterclose; /* packets rcvd after "close" */ - uint32 tcps_rcvwinprobe; /* rcvd window probe packets */ - uint32 tcps_rcvdupack; /* rcvd duplicate acks */ - uint32 tcps_rcvacktoomuch; /* rcvd acks for unsent data */ - uint32 tcps_rcvackpack; /* rcvd ack packets */ - uint64 tcps_rcvackbyte; /* bytes acked by rcvd acks */ - uint32 tcps_rcvwinupd; /* rcvd window update packets */ - uint32 tcps_pawsdrop; /* segments dropped due to PAWS */ - uint32 tcps_predack; /* times hdr predict ok for acks */ - uint32 tcps_preddat; /* times hdr predict ok for data pkts */ - - uint32 tcps_pcbhashmiss; /* input packets missing pcb hash */ - uint32 tcps_noport; /* no socket on port */ - uint32 tcps_badsyn; /* SYN packet with src==dst rcv'ed */ - - uint32 tcps_rcvbadsig; /* rcvd bad/missing TCP signatures */ - uint64 tcps_rcvgoodsig; /* rcvd good TCP signatures */ - uint32 tcps_inhwcsum; /* input hardware-checksummed packets */ - uint32 tcps_outhwcsum; /* output hardware-checksummed packets */ -}; - -/* - * Names for TCP sysctl objects. - */ - -#define TCPCTL_RFC1323 1 /* enable/disable RFC1323 timestamps/scaling */ -#define TCPCTL_KEEPINITTIME 2 /* TCPT_KEEP value */ -#define TCPCTL_KEEPIDLE 3 /* allow tcp_keepidle to be changed */ -#define TCPCTL_KEEPINTVL 4 /* allow tcp_keepintvl to be changed */ -#define TCPCTL_SLOWHZ 5 /* return kernel idea of PR_SLOWHZ */ -#define TCPCTL_BADDYNAMIC 6 /* return bad dynamic port bitmap */ -#define TCPCTL_RECVSPACE 7 /* receive buffer space */ -#define TCPCTL_SENDSPACE 8 /* send buffer space */ -#define TCPCTL_IDENT 9 /* get connection owner */ -#define TCPCTL_SACK 10 /* selective acknowledgement, rfc 2018 */ -#define TCPCTL_MSSDFLT 11 /* Default maximum segment size */ -#define TCPCTL_RSTPPSLIMIT 12 /* RST pps limit */ -#define TCPCTL_MAXID 13 - -//#ifdef _NETWORK_STACK - -extern struct inpcb tcb; -extern struct tcpstat tcpstat; -extern int tcp_mssdflt; -extern int tcp_do_rfc1323; -extern unsigned long tcp_now; - - -void tcp_input(struct mbuf *, int); -int tcp_output(struct tcpcb*); -int tcp_mss(struct tcpcb *, uint); -void tcp_mss_update(struct tcpcb *); -void tcp_quench(struct inpcb *, int); -int tcp_userreq(struct socket *, int, struct mbuf *, struct mbuf *, - struct mbuf *); -struct tcpcb * tcp_timers(struct tcpcb *, int); -struct tcpcb *tcp_close(struct tcpcb *); -void tcp_setpersist(struct tcpcb *); -struct tcpcb *tcp_drop(struct tcpcb *, int); -void tcp_respond(struct tcpcb *, struct tcpiphdr *, struct mbuf *, - tcp_seq, tcp_seq, int); -void tcp_xmit_timer(struct tcpcb *, int16); -void tcp_dooptions(struct tcpcb *, u_char *, int, struct tcpiphdr *, - int *, uint32 *, uint32 *); -struct tcpiphdr *tcp_template(struct tcpcb *); -void tcp_pulloutofband(struct socket *, struct tcpiphdr *, struct mbuf *); - -void tcp_canceltimers(struct tcpcb *); -void tcp_trace(int16, int16, struct tcpcb *, void *, int, int); - -void tcp_slowtimer(void *data); -void tcp_fasttimer(void *data); - - - -//#endif - -#endif /* NETINET_TCP_VAR_H */ diff --git a/headers/posix/netinet/tcpip.h b/headers/posix/netinet/tcpip.h deleted file mode 100644 index 231ffdd853..0000000000 --- a/headers/posix/netinet/tcpip.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - *The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifndef NETINET_TCPIP_H -#define NETINET_TCPIP_H - -/* The TCP + IPv4 header (NB no options) */ -struct tcpiphdr { - struct ipovly ti_i; - struct tcphdr ti_t; -}; - -#define ti_next ti_i.ih_next -#define ti_prev ti_i.ih_prev -#define ti_x1 ti_i.ih_x1 -#define ti_pr ti_i.ih_pr -#define ti_len ti_i.ih_len -#define ti_src ti_i.ih_src -#define ti_dst ti_i.ih_dst -#define ti_sport ti_t.th_sport -#define ti_dport ti_t.th_dport -#define ti_seq ti_t.th_seq -#define ti_ack ti_t.th_ack -#define ti_x2 ti_t.th_x2 -#define ti_off ti_t.th_off -#define ti_flags ti_t.th_flags -#define ti_win ti_t.th_win -#define ti_sum ti_t.th_sum -#define ti_urp ti_t.th_urp - -#define REASS_MBUF(ti) (*(struct mbuf **)&((ti)->ti_t)) - -#endif /* NETINET_TCPIP_H */ diff --git a/headers/posix/netinet/udp_var.h b/headers/posix/netinet/udp_var.h deleted file mode 100644 index a058bd04fc..0000000000 --- a/headers/posix/netinet/udp_var.h +++ /dev/null @@ -1,51 +0,0 @@ -/* udp_var.h */ - -#ifndef UDP_VAR_H -#define UDP_VAR_H - -#include "netinet/ip_var.h" - -struct udpiphdr { - struct ipovly ui_i; - struct udphdr ui_u; -}; -#define ui_next ui_i.ih_next -#define ui_prev ui_i.ih_prev -#define ui_x1 ui_i.ih_x1 /* NB _x1 (one) */ -#define ui_pr ui_i.ih_pr -#define ui_len ui_i.ih_len -#define ui_src ui_i.ih_src -#define ui_dst ui_i.ih_dst -#define ui_sport ui_u.uh_sport -#define ui_dport ui_u.uh_dport -#define ui_ulen ui_u.uh_ulen -#define ui_sum ui_u.uh_sum - -struct udpstat { - /* input statistics: */ - uint32 udps_ipackets; /* total input packets */ - uint32 udps_hdrops; /* packet shorter than header */ - uint32 udps_badsum; /* checksum error */ - uint32 udps_nosum; /* no checksum */ - uint32 udps_badlen; /* data length larger than packet */ - uint32 udps_noport; /* no socket on port */ - uint32 udps_noportbcast; /* of above, arrived as broadcast */ - uint32 udps_nosec; /* dropped for lack of ipsec */ - uint32 udps_fullsock; /* not delivered, input socket full */ - uint32 udps_pcbhashmiss; /* input packets missing pcb hash */ - uint32 udps_inhwcsum; /* input hardware-csummed packets */ - /* output statistics: */ - uint32 udps_opackets; /* total output packets */ - uint32 udps_outhwcsum; /* output hardware-csummed packets */ -}; - -/* - * Names for UDP sysctl objects - */ -#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ -#define UDPCTL_BADDYNAMIC 2 /* return bad dynamic port bitmap */ -#define UDPCTL_RECVSPACE 3 /* receive buffer space */ -#define UDPCTL_SENDSPACE 4 /* send buffer space */ -#define UDPCTL_MAXID 5 - -#endif diff --git a/headers/posix/netinet6/in6.h b/headers/posix/netinet6/in6.h new file mode 100644 index 0000000000..abe5d9eab1 --- /dev/null +++ b/headers/posix/netinet6/in6.h @@ -0,0 +1,30 @@ +/* + * Copyright 2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _NETINET6_IN6_H_ +#define _NETINET6_IN6_H_ + + +#include +#include + + +struct in6_addr { + uint8_t s6_addr[16]; +}; + +/* + * IP Version 6 socket address. + */ + +struct sockaddr_in6 { + uint8_t sin6_len; + sa_family_t sin6_family; + in_port_t sin6_port + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +#endif /* _NETINET6_IN6_H_ */ diff --git a/headers/posix/resolv.h b/headers/posix/resolv.h index 376ff13fa2..54ef65542e 100644 --- a/headers/posix/resolv.h +++ b/headers/posix/resolv.h @@ -57,7 +57,7 @@ #define _RESOLV_H_ #include -#include +#include #include #include #include diff --git a/headers/posix/sys/bitypes.h b/headers/posix/sys/bitypes.h deleted file mode 100644 index f9f7982c90..0000000000 --- a/headers/posix/sys/bitypes.h +++ /dev/null @@ -1,3 +0,0 @@ -#include -#include -#include diff --git a/headers/posix/sys/file.h b/headers/posix/sys/file.h deleted file mode 100644 index 742c73e50a..0000000000 --- a/headers/posix/sys/file.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SYS_FILE_H -#define _SYS_FILE_H - -#include - -#endif diff --git a/headers/posix/sys/filio.h b/headers/posix/sys/filio.h deleted file mode 100644 index a68c42200b..0000000000 --- a/headers/posix/sys/filio.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file sys/filio.h - * @brief ioctl() definitions for file descriptor operations - */ - -#ifndef _SYS_FILIO_H -#define _SYS_FILIO_H -/** - * @defgroup IOCTL_filio sys/filio.h - * @brief ioctl() definitions for file descriptor operations - * @ingroup OpenBeOS_POSIX - * @ingroup IOCTL - * @{ - */ - -#include - -/** @def FIOCLEX set close on exec - * @ref FD_CLOEXEC */ -#define FIOCLEX _IO('f', 1) -/** @def FIONCLEX remove close on exec flag - * @ref FD_CLOEXEC*/ -#define FIONCLEX _IO('f', 2) -/** @def FIBMAP get logical block - * @note this is not yet implemented on OpenBeOS */ -#define FIBMAP _IOWR('f', 122, void *) -/** @def FIOASYNC set/clear async I/O */ -#define FIOASYNC _IOW('f', 123, int) -/** @def FIOGETOWN get owner */ -#define FIOGETOWN _IOR('f', 123, int) -/** @def FIOSETOWN set owner */ -#define FIOSETOWN _IOW('f', 123, int) -/** @def FIONBIO set/clear non-blocking I/O */ -#define FIONBIO _IOW('f', 126, int) -/** @def FIONREAD get number of bytes available to read */ -#define FIONREAD _IOW('f', 127, int) - -/** @} */ - -#endif /* _SYS_FILIO_H */ diff --git a/headers/posix/sys/ioccom.h b/headers/posix/sys/ioccom.h deleted file mode 100644 index 9af5c74643..0000000000 --- a/headers/posix/sys/ioccom.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file sys/ioccom.h - * @brief Definitions & maros common to ioctl - */ - -#ifndef _SYS_IOCCOM_H -#define _SYS_IOCCOM_H - -/** - * @defgroup IOCTL_common sys/ioccom.h - * @brief Definitions & maros common to ioctl() - * @ingroup OpenBeOS_POSIX - * @ingroup IOCTL - * Ioctl values passed as the command (2nd) variable have the - * command encoded in the lower word and the size of any parameters - * in the upper word (in or out). - * The high 3 bits are used to encode whether it's in or out. - * Due to this you can't just give an ioctl value, you need to encode - * it using macros described in - * @ref IOCTL_macros - * @{ - */ - -/** @defgroup IOCTL_parm ioctl() parameter definitions - * @ingroup IOCTL_common - * @{ - */ -/** @def IOC_VOID */ -#define IOC_VOID (ulong)0x20000000 -/** @def IOC_OUT ioctl expects data (output) */ -#define IOC_OUT (ulong)0x40000000 -/** @def IOC_IN ioctl passes a value in */ -#define IOC_IN (ulong)0x80000000 -/** @def IOC_INOUT ioctl passes data in and out */ -#define IOC_INOUT (IOC_IN|IOC_OUT) -/** @def IOC_DIRMASK */ -#define IOC_DIRMASK (ulong)0xe0000000 -/** @} */ - -/** - * @defgroup IOCTL_macros IOCTL macros - * These should be used to define the values passed in as cmd to - * ioctl() - * @ingroup IOCTL_common - * @{ - */ -/** @def IOCPARM_MASK mask used to for following macros */ -#define IOCPARM_MASK 0x1fff -/** @def IOCPARM_LEN(x) length of the data passed as param */ -#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK) -/** @def IOCBASECMD(x) the base command encoded in the ioctl value */ -#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16)) -/** @def IOCGROUP(x) which group of ioctl() commands does this belong to? */ -#define IOCGROUP(x) (((x) >> 8) & 0xff) -/** @def IOCPARM_MAX Maximum size of parameter that can be passed (20 bytes) */ -#define IOCPARM_MAX 20 - -/** - * @defgroup IOCTL_createmacros macro's to create ioctl() values - * @brief these macro's should be used to create new ioctl() values - * @ingroup IOCTL_common - * @{ - */ -/** @def _IOC(inout, group, num , len) create a new ioctl */ -#define _IOC(inout, group, num, len) \ - (inout | ((len & IOCPARM_MASK)<<16) | ((group) << 8) | (num)) -/** @def _IO(g,n) create a new void ioctl for group g, number n */ -#define _IO(g,n) _IOC(IOC_VOID, (g), (n), 0) -/** @def _IOR(g,n,t) create a ioctl() that reads a value of type t*/ -#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t)) -/** @def _IOW(g,n,t) ioctl() that writes value of type t, group g, number n */ -#define _IOW(g,n,t) _IOC(IOC_IN , (g), (n), sizeof(t)) -/** @def _IOWR(g,n,t) ioctl() that reads/writes value of type t - * @note this isn't _IORW as this causes name conflicts on some systems */ -#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) -/** @} */ - -/** @} */ - -#endif /* _SYS_IOCCOM_H */ diff --git a/headers/posix/sys/ioctl.h b/headers/posix/sys/ioctl.h index eccb5b375d..dd53321b6c 100644 --- a/headers/posix/sys/ioctl.h +++ b/headers/posix/sys/ioctl.h @@ -1,39 +1,12 @@ -/** - * @file sys/ioctl.h - * @brief I/O control functions +/* + * Copyright 2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. */ - #ifndef _SYS_IOCTL_H #define _SYS_IOCTL_H -/** - * @defgroup IOCTL sys/ioctl.h - * @brief I/O control functions - * @ingroup OpenBeOS_POSIX - * @{ - */ +/* These only work on sockets for now */ +#define FIONBIO 0xbe000000 +#define FIONREAD 0xbe000001 -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#ifndef _KERNEL_MODE - /** @fn int ioctl(int fd, ulong cmd, ...) - * Manipulates the characteristics of the affected descriptor. May be used - * on all forms of descriptor, including sockets and pipes. cmd should be one - * of the values given in - * @ref IOCTL_cmds - */ - int ioctl(int, ulong, ...); -#endif /* !_KERNEL_MODE */ - -#ifdef __cplusplus -} -#endif - -/** @} */ -#endif /* _SYS_IOCTL_H */ +#endif /* _SYS_IOCTL_H */ diff --git a/headers/posix/sys/select.h b/headers/posix/sys/select.h index 557e98af7c..aabd2d48e4 100644 --- a/headers/posix/sys/select.h +++ b/headers/posix/sys/select.h @@ -1,8 +1,9 @@ +/* + * Copyright 2002-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _SYS_SELECT_H #define _SYS_SELECT_H -/* -** Distributed under the terms of the OpenBeOS License. -*/ #include diff --git a/headers/posix/sys/socket.h b/headers/posix/sys/socket.h index 5646ecbd58..4e845869a6 100644 --- a/headers/posix/sys/socket.h +++ b/headers/posix/sys/socket.h @@ -1,68 +1,47 @@ -/* sys/socket.h */ - - +/* + * Copyright 2002-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _SYS_SOCKET_H #define _SYS_SOCKET_H + #include #include -#include -#include +#include -#if __cplusplus -extern "C" { -#endif /* __cplusplus */ typedef uint32_t socklen_t; -/* These are the address/protocol families we'll be using... */ -/* NB these should be added to as required... */ - -/* If we want to have Binary compatability we may need to alter these - * to agree with the Be versions... - */ -#define AF_UNSPEC 0 -#define AF_INET 1 -#define AF_LOCAL 2 -#define AF_UNIX AF_LOCAL /* for compatability */ -#define AF_ROUTE 3 -#define AF_LINK 4 -#define AF_INET6 5 -#define AF_IPX 7 -#define AF_IMPLINK 20 - -#define AF_MAX 24 +/* Address families */ +#define AF_UNSPEC 0 +#define AF_INET 1 +#define AF_APPLETALK 2 +#define AF_ROUTE 3 +#define AF_LINK 4 +#define AF_INET6 5 +#define AF_DLI 6 +#define AF_IPX 7 +#define AF_NOTIFY 8 +#define AF_LOCAL 9 +#define AF_UNIX AF_LOCAL +#define AF_MAX 10 +/* Protocol families, deprecated */ #define PF_UNSPEC AF_UNSPEC #define PF_INET AF_INET #define PF_ROUTE AF_ROUTE #define PF_LINK AF_LINK -#define PF_INET6 AF_INET6 -#define PF_IPX AF_IPX -#define PF_IMPLINK AF_IMPLINK +#define PF_INET6 AF_INET6 -/* Types of socket we can create (eventually) */ -#ifndef BUILDING_R5_LIBNET -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 -#define SOCK_RAW 3 -#define SOCK_MISC 255 -#else /* BUILDING_R5_LIBNET */ -/* XXX: HACK: we use socket emulation for libnet.so */ -#define SOCK_DGRAM 10 -#define SOCK_STREAM 11 -#define SOCK_RAW 12 -#define SOCK_MISC 255 -#define SOCK_NATIVE_STREAM 1 -#define SOCK_NATIVE_DGRAM 2 -#define SOCK_NATIVE_RAW 3 -#define SOCK_NATIVE_MISC 255 -#endif /* BUILDING_R5_LIBNET */ +/* Socket types */ +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 +#define SOCK_MISC 255 -/* - * Option flags per-socket. - */ -#define SOL_SOCKET 0xffffffff +/* Socket options for SOL_SOCKET level */ +#define SOL_SOCKET -1 #define SO_ACCEPTCONN 0x00000001 /* socket has had listen() */ #define SO_BROADCAST 0x00000002 /* permit sending of broadcast msgs */ @@ -75,9 +54,6 @@ typedef uint32_t socklen_t; #define SO_USELOOPBACK 0x00000100 /* bypass hardware when possible */ #define SO_LINGER 0x00000200 /* linger on close if data present */ -/* - * Additional options, not kept in so_options. - */ #define SO_SNDBUF 0x40000001 /* send buffer size */ #define SO_SNDLOWAT 0x40000002 /* send low-water mark */ #define SO_SNDTIMEO 0x40000003 /* send timeout */ @@ -86,206 +62,94 @@ typedef uint32_t socklen_t; #define SO_RCVTIMEO 0x40000006 /* receive timeout */ #define SO_ERROR 0x40000007 /* get error status and clear */ #define SO_TYPE 0x40000008 /* get socket type */ - -/* not handled by OpenBeOS */ #define SO_NONBLOCK 0x40000009 #define SO_BINDTODEVICE 0x4000000a -/* only defined in OpenBeOS */ -#define SO_NETPROC 0x00001020 /* multiplex; network processing */ - -/* - * These are the valid values for the "how" field used by shutdown(2). - */ +/* Shutdown options */ #define SHUT_RD 0 #define SHUT_WR 1 #define SHUT_RDWR 2 -/* for BONE compatibility */ -#define SHUTDOWN_RECV SHUT_RD -#define SHUTDOWN_SEND SHUT_WR -#define SHUTDOWN_BOTH SHUT_RDWR +#define SOMAXCONN 32 /* Max listen queue for a socket */ struct linger { - int l_onoff; - int l_linger; + int l_onoff; + int l_linger; }; struct sockaddr { - uint8_t sa_len; - uint8_t sa_family; - uint8_t sa_data[30]; + uint8_t sa_len; + uint8_t sa_family; + uint8_t sa_data[30]; }; /* this can hold ANY sockaddr we care to throw at it! */ struct sockaddr_storage { - uint8_t ss_len; /* total length */ - uint8_t ss_family; /* address family */ - uint8_t __ss_pad1[6]; /* align to quad */ - uint64_t __ss_pad2; /* force alignment for stupid compilers */ - uint8_t __ss_pad3[240]; /* pad to a total of 256 bytes */ + uint8_t ss_len; /* total length */ + uint8_t ss_family; /* address family */ + uint8_t __ss_pad1[6]; /* align to quad */ + uint64_t __ss_pad2; /* force alignment for stupid compilers */ + uint8_t __ss_pad3[112]; /* pad to a total of 128 bytes */ }; -struct sockproto { - uint16_t sp_family; - uint16_t sp_protocol; -}; - -#define CTL_NET 4 - -#define CTL_NET_NAMES { \ - { 0, 0 }, \ - { "unix", CTLTYPE_NODE }, \ - { "inet", CTLTYPE_NODE }, \ - { "implink", CTLTYPE_NODE }, \ - { "pup", CTLTYPE_NODE }, \ - { "chaos", CTLTYPE_NODE }, \ - { "xerox_ns", CTLTYPE_NODE }, \ - { "iso", CTLTYPE_NODE }, \ - { "emca", CTLTYPE_NODE }, \ - { "datakit", CTLTYPE_NODE }, \ - { "ccitt", CTLTYPE_NODE }, \ - { "ibm_sna", CTLTYPE_NODE }, \ - { "decnet", CTLTYPE_NODE }, \ - { "dec_dli", CTLTYPE_NODE }, \ - { "lat", CTLTYPE_NODE }, \ - { "hylink", CTLTYPE_NODE }, \ - { "appletalk", CTLTYPE_NODE }, \ - { "route", CTLTYPE_NODE }, \ - { "link_layer", CTLTYPE_NODE }, \ - { "xtp", CTLTYPE_NODE }, \ - { "coip", CTLTYPE_NODE }, \ - { "cnt", CTLTYPE_NODE }, \ - { "rtip", CTLTYPE_NODE }, \ - { "ipx", CTLTYPE_NODE }, \ - { "inet6", CTLTYPE_NODE }, \ - { "pip", CTLTYPE_NODE }, \ - { "isdn", CTLTYPE_NODE }, \ - { "natm", CTLTYPE_NODE }, \ - { "encap", CTLTYPE_NODE }, \ - { "sip", CTLTYPE_NODE }, \ - { "key", CTLTYPE_NODE }, \ -} - -/* - * PF_ROUTE - Routing table - * - * Three additional levels are defined: - * Fourth: address family, 0 is wildcard - * Fifth: type of info, defined below - * Sixth: flag(s) to mask with for NET_RT_FLAGS - */ -#define NET_RT_DUMP 1 /* dump; may limit to a.f. */ -#define NET_RT_FLAGS 2 /* by flags, e.g. RESOLVING */ -#define NET_RT_IFLIST 3 /* survey interface list */ -#define NET_RT_MAXID 4 - -#define CTL_NET_RT_NAMES { \ - { 0, 0 }, \ - { "dump", CTLTYPE_STRUCT }, \ - { "flags", CTLTYPE_STRUCT }, \ - { "iflist", CTLTYPE_STRUCT }, \ -} - - /* Max listen queue for a socket */ -#define SOMAXCONN 5 /* defined as 128 in OpenBSD */ - struct msghdr { - char * msg_name; /* address we're using (optional) */ - uint msg_namelen; /* length of address */ - struct iovec *msg_iov; /* scatter/gather array we'll use */ - uint msg_iovlen; /* # elements in msg_iov */ - char * msg_control; /* extra data */ - uint msg_controllen; /* length of extra data */ - int msg_flags; /* flags */ + char *msg_name; /* address we're using (optional) */ + socklen_t msg_namelen; /* length of address */ + struct iovec *msg_iov; /* scatter/gather array we'll use */ + int msg_iovlen; /* # elements in msg_iov */ + char *msg_control; /* extra data */ + socklen_t msg_controllen; /* length of extra data */ + int msg_flags; /* flags */ }; -/* Defines used in msghdr structure. */ -#define MSG_OOB 0x1 /* process out-of-band data */ -#define MSG_PEEK 0x2 /* peek at incoming message */ -#define MSG_DONTROUTE 0x4 /* send without using routing tables */ -#define MSG_EOR 0x8 /* data completes record */ -#define MSG_TRUNC 0x10 /* data discarded before delivery */ -#define MSG_CTRUNC 0x20 /* control data lost before delivery */ -#define MSG_WAITALL 0x40 /* wait for full request or error */ -#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ -#define MSG_BCAST 0x100 /* this message rec'd as broadcast */ -#define MSG_MCAST 0x200 /* this message rec'd as multicast */ -/* not defind in OpenBeOS */ -#define MSG_EOF 0x400 /* data completes connection */ - +/* Flags for the msghdr.msg_flags field */ +#define MSG_OOB 0x0001 /* process out-of-band data */ +#define MSG_PEEK 0x0002 /* peek at incoming message */ +#define MSG_DONTROUTE 0x0004 /* send without using routing tables */ +#define MSG_EOR 0x0008 /* data completes record */ +#define MSG_TRUNC 0x0010 /* data discarded before delivery */ +#define MSG_CTRUNC 0x0020 /* control data lost before delivery */ +#define MSG_WAITALL 0x0040 /* wait for full request or error */ +#define MSG_DONTWAIT 0x0080 /* this message should be nonblocking */ +#define MSG_BCAST 0x0100 /* this message rec'd as broadcast */ +#define MSG_MCAST 0x0200 /* this message rec'd as multicast */ +#define MSG_EOF 0x0400 /* data completes connection */ struct cmsghdr { - uint cmsg_len; - int cmsg_level; - int cmsg_type; - /* there now follows uchar[] cmsg_data */ + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; + /* data follows */ }; -#define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */ -#define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */ -#define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */ -#define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */ -#define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */ +#if __cplusplus +extern "C" { +#endif -#define SIOCADDRT _IOW('r', 10, struct ortentry) /* add route */ -#define SIOCDELRT _IOW('r', 11, struct ortentry) /* delete route */ - -#define SIOCSIFADDR _IOW('i', 12, struct ifreq) /* set ifnet address */ -#define OSIOCGIFADDR _IOWR('i', 13, struct ifreq) /* get ifnet address */ -#define SIOCGIFADDR _IOWR('i', 33, struct ifreq) /* get ifnet address */ -#define SIOCSIFDSTADDR _IOW('i', 14, struct ifreq) /* set p-p address */ -#define OSIOCGIFDSTADDR _IOWR('i', 15, struct ifreq) /* get p-p address */ -#define SIOCGIFDSTADDR _IOWR('i', 34, struct ifreq) /* get p-p address */ -#define SIOCSIFFLAGS _IOW('i', 16, struct ifreq) /* set ifnet flags */ -#define SIOCGIFFLAGS _IOWR('i', 17, struct ifreq) /* get ifnet flags */ -#define OSIOCGIFBRDADDR _IOWR('i', 18, struct ifreq) /* get broadcast addr */ -#define SIOCGIFBRDADDR _IOWR('i', 35, struct ifreq) /* get broadcast addr */ -#define SIOCSIFBRDADDR _IOW('i', 19, struct ifreq) /* set broadcast addr */ -#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */ -#define SIOCGIFCONF _IOWR('i', 36, struct ifconf) /* get ifnet list */ -#define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */ -#define SIOCGIFNETMASK _IOWR('i', 37, struct ifreq) /* get net addr mask */ -#define SIOCSIFNETMASK _IOW('i', 22, struct ifreq) /* set net addr mask */ -#define SIOCGIFMETRIC _IOWR('i', 23, struct ifreq) /* get IF metric */ -#define SIOCSIFMETRIC _IOW('i', 24, struct ifreq) /* set IF metric */ -#define SIOCDIFADDR _IOW('i', 25, struct ifreq) /* delete IF addr */ -#define SIOCAIFADDR _IOW('i', 26, struct ifaliasreq)/* add/chg IF alias */ -#define SIOCGIFDATA _IOWR('i', 27, struct ifreq) /* get if_data */ - -#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet MTU */ -#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet MTU */ - -#define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* add m'cast addr */ -#define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* del m'cast addr */ - - -#ifndef _KERNEL_MODE -/* Function declarations */ -int socket (int, int, int); -int socketpair(int domain, int type, int protocol, int socket_vector[2]); -int bind(int, const struct sockaddr *, socklen_t); -int connect(int, const struct sockaddr *, socklen_t); -int listen(int, int); -int accept(int, struct sockaddr *, socklen_t *); -int closesocket(int); -int shutdown(int sock, int how); - -ssize_t send(int, const void *, size_t, int); -ssize_t recv(int, void *, size_t, int); -ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); -ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); - -int setsockopt(int, int, int, const void *, socklen_t); -int getsockopt(int, int, int, void *, socklen_t *); -int getpeername(int, struct sockaddr *, socklen_t *); -int getsockname(int, struct sockaddr *, socklen_t *); -#endif /* _KERNEL_MODE */ +int accept(int socket, struct sockaddr *address, socklen_t *_addressLength); +int bind(int socket, const struct sockaddr *address, socklen_t addressLength); +int connect(int socket, const struct sockaddr *address, socklen_t addressLength); +int getpeername(int socket, struct sockaddr *address, socklen_t *_addressLength); +int getsockname(int socket, struct sockaddr *address, socklen_t *_addressLength); +int getsockopt(int socket, int level, int option, void *value, socklen_t *_length); +int listen(int socket, int backlog); +ssize_t recv(int socket, void *buffer, size_t length, int flags); +ssize_t recvfrom(int socket, void *buffer, size_t bufferLength, int flags, + struct sockaddr *address, socklen_t *_addressLength); +ssize_t recvmsg(int socket, struct msghdr *message, int flags); +ssize_t send(int socket, const void *buffer, size_t length, int flags); +ssize_t sendmsg(int socket, const struct msghdr *message, int flags); +ssize_t sendto(int socket, const void *message, size_t length, int flags, + const struct sockaddr *address, socklen_t addressLength); +int setsockopt(int socket, int level, int option, const void *value, socklen_t length); +int shutdown(int socket, int how); +int socket(int domain, int type, int protocol); +int sockatmark(int socket); +int socketpair(int domain, int type, int protocol, int socketVector[2]); #if __cplusplus } -#endif /* __cplusplus */ - -#endif /* _SYS_SOCKET_H */ +#endif +#endif /* _SYS_SOCKET_H */ diff --git a/headers/posix/sys/sockio.h b/headers/posix/sys/sockio.h new file mode 100644 index 0000000000..1508b489c4 --- /dev/null +++ b/headers/posix/sys/sockio.h @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SYS_SOCKIO_H +#define _SYS_SOCKIO_H + + +enum { + SIOCADDRT = 8900, /* add route */ + SIOCDELRT, /* delete route */ + SIOCSIFADDR, /* set interface address */ + SIOCGIFADDR, /* get interface address */ + SIOCSIFDSTADDR, /* set point-to-point address */ + SIOCGIFDSTADDR, /* get point-to-point address */ + SIOCSIFFLAGS, /* set interface flags */ + SIOCGIFFLAGS, /* get interface flags */ + SIOCGIFBRDADDR, /* get broadcast address */ + SIOCSIFBRDADDR, /* set broadcast address */ + SIOCGIFCOUNT, /* count interfaces */ + SIOCGIFCONF, /* get interface list */ + SIOCGIFINDEX, /* interface name -> index */ + SIOCGIFNAME, /* interface index -> name */ + SIOCGIFNETMASK, /* get net address mask */ + SIOCSIFNETMASK, /* set net address mask */ + SIOCGIFMETRIC, /* get interface metric */ + SIOCSIFMETRIC, /* set interface metric */ + SIOCDIFADDR, /* delete interface address */ + SIOCAIFADDR, /* configure interface alias */ + SIOCADDMULTI, /* add multicast address */ + SIOCDELMULTI, /* delete multicast address */ + SIOCGIFMTU, /* get interface MTU */ + SIOCSIFMTU, /* set interface MTU */ + SIOCSIFMEDIA, /* set net media */ + SIOCGIFMEDIA, /* get net media */ + + SIOCGRTSIZE, /* get route table size */ + SIOCGRTTABLE, /* get route table */ + + SIOCGIFSTATS, /* get interface stats */ + SIOCGIFPARAM, /* get interface parameter */ + SIOCGIFTYPE, /* get interface type */ + + SIOCSPACKETCAP, /* Start capturing packets on an interface */ + SIOCCPACKETCAP, /* Stop capturing packets on an interface */ + + SIOCSHIWAT, /* set high watermark */ + SIOCGHIWAT, /* get high watermark */ + SIOCSLOWAT, /* set low watermark */ + SIOCGLOWAT, /* get low watermark */ + SIOCATMARK, /* at out-of-band mark? */ + SIOCSPGRP, /* set process group */ + SIOCGPGRP /* get process group */ +}; + +#endif /* _SYS_SOCKIO_H */ diff --git a/headers/posix/sys/uio.h b/headers/posix/sys/uio.h index 669a369694..93dfe47651 100644 --- a/headers/posix/sys/uio.h +++ b/headers/posix/sys/uio.h @@ -1,8 +1,9 @@ +/* + * Copyright 2002-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _SYS_UIO_H #define _SYS_UIO_H -/* -** Distributed under the terms of the Haiku License. -*/ #include diff --git a/headers/private/net/core_funcs.h b/headers/private/net/core_funcs.h deleted file mode 100644 index 5559c6cded..0000000000 --- a/headers/private/net/core_funcs.h +++ /dev/null @@ -1,110 +0,0 @@ -/* core_funcs.h - * convenience macros to for calling core functions in the kernel - */ - -#ifndef OBOS_CORE_FUNCS_H -#define OBOS_CORE_FUNCS_H - -#include "core_module.h" - -# define add_protosw core->add_protosw -# define add_domain core->add_domain -# define remove_domain core->remove_domain -# define add_protocol core->add_protocol -# define remove_protocol core->remove_protocol -# define start_rx_thread core->start_rx_thread -# define start_tx_thread core->start_tx_thread - -# define get_max_hdr core->get_max_hdr -# define set_max_linkhdr core->set_max_linkhdr -# define get_max_linkhdr core->get_max_linkhdr -# define set_max_protohdr core->set_max_protohdr -# define get_max_protohdr core->get_max_protohdr - -# define net_add_timer core->net_add_timer -# define net_remove_timer core->net_remove_timer - -# define start_ifq core->start_ifq -# define stop_ifq core->stop_ifq - -# define pool_init core->pool_init -# define pool_get core->pool_get -# define pool_put core->pool_put - -# define m_get core->m_get -# define m_gethdr core->m_gethdr -# define m_free core->m_free -# define m_freem core->m_freem -# define m_cat core->m_cat -# define m_adj core->m_adj -# define m_prepend core->m_prepend -# define m_pullup core->m_pullup -# define m_copydata core->m_copydata -# define m_copyback core->m_copyback -# define m_copym core->m_copym -# define m_reserve core->m_reserve -# define m_devget core->m_devget - -# define if_attach core->if_attach -# define if_detach core->if_detach - -# define in_pcballoc core->in_pcballoc -# define in_pcbconnect core->in_pcbconnect -# define in_pcbdisconnect core->in_pcbdisconnect -# define in_pcbbind core->in_pcbbind -# define in_pcblookup core->in_pcblookup -# define in_pcbdetach core->in_pcbdetach -# define in_pcbrtentry core->in_pcbrtentry -# define in_canforward core->in_canforward -# define in_localaddr core->in_localaddr -# define in_losing core->in_losing -# define in_broadcast core->in_broadcast -# define in_control core->in_control -# define in_setsockaddr core->in_setsockaddr -# define in_setpeeraddr core->in_setpeeraddr -# define in_pcbnotify core->in_pcbnotify -# define inetctlerrmap core->inetctlerrmap -# define in_cksum core->in_cksum - -# define ifa_ifwithdstaddr core->ifa_ifwithdstaddr -# define ifa_ifwithaddr core->ifa_ifwithaddr -# define ifa_ifwithnet core->ifa_ifwithnet -# define ifa_ifwithroute core->ifa_ifwithroute -# define ifaof_ifpforaddr core->ifaof_ifpforaddr -# define ifafree core->ifafree - -# define sockbuf_append core->sockbuf_append -# define sockbuf_appendaddr core->sockbuf_appendaddr -# define sockbuf_drop core->sockbuf_drop -# define sockbuf_flush core->sockbuf_flush -# define sockbuf_reserve core->sockbuf_reserve - -# define soreserve core->soreserve -# define sowakeup core->sowakeup -# define sonewconn core->sonewconn - -# define socket_set_connected core->socket_set_connected -# define socket_set_connecting core->socket_set_connecting -# define socket_set_disconnected core->socket_set_disconnected -# define socket_set_disconnecting core->socket_set_disconnecting -# define socket_set_hasoutofband core->socket_set_hasoutofband -# define socket_set_cantsendmore core->socket_set_cantsendmore -# define socket_set_cantrcvmore core->socket_set_cantrcvmore - -# define rtfree core->rtfree -# define rtalloc core->rtalloc -# define rtalloc1 core->rtalloc1 -# define rtrequest core->rtrequest - -# define rt_setgate core->rt_setgate -# define get_rt_tables core->get_rt_tables - -# define rn_addmask core->rn_addmask -# define rn_head_search core->rn_head_search - -# define get_interfaces core->get_interfaces -# define get_primary_addr core->get_primary_addr - -# define net_sysctl core->net_sysctl - -#endif /* OBOS_CORE_FUNCS_H */ diff --git a/headers/private/net/core_module.h b/headers/private/net/core_module.h deleted file mode 100644 index b951e3a241..0000000000 --- a/headers/private/net/core_module.h +++ /dev/null @@ -1,167 +0,0 @@ -/* core_module.h - * definitions needed by the core networking module - */ - -#ifndef OBOS_CORE_MODULE_H -#define OBOS_CORE_MODULE_H - -#include -#include -#include -#include -#include -#include -#include - -struct core_module_info { - module_info module; - - int (*start)(void); - int (*stop)(void); - status_t (*control_net_module)(const char *name, uint32 op, void *data, - size_t length); - void (*add_domain)(struct domain *, int); - void (*remove_domain)(int); - void (*add_protocol)(struct protosw *, int); - void (*remove_protocol)(struct protosw *pr); - void (*add_protosw)(struct protosw *prt[], int layer); - void (*start_rx_thread)(struct ifnet *dev); - void (*start_tx_thread)(struct ifnet *dev); - - // functions for the 'max_xxx' values - int (*get_max_hdr)(void); - void (*set_max_linkhdr)(int maxLinkHdr); - int (*get_max_linkhdr)(void); - void (*set_max_protohdr)(int maxProtoHdr); - int (*get_max_protohdr)(void); - - /* timer functions */ - net_timer_id (*net_add_timer)(net_timer_hook ,void *, - bigtime_t); - status_t (*net_remove_timer)(net_timer_id); - - /* ifq functions */ - struct ifq *(*start_ifq)(void); - void (*stop_ifq)(struct ifq *); - - /* pool functions */ - status_t (*pool_init)(pool_ctl **p, size_t sz); - char *(*pool_get)(pool_ctl *p); - void (*pool_put)(pool_ctl *p, void *ptr); - void (*pool_destroy)(pool_ctl *p); - - /* socket functions - called "internally" */ - struct socket *(*sonewconn)(struct socket *, int); - int (*soreserve)(struct socket *, uint32, uint32); - int (*sockbuf_reserve)(struct sockbuf *, uint32); - void (*sockbuf_append)(struct sockbuf *, struct mbuf *); - int (*sockbuf_appendaddr)(struct sockbuf *, struct sockaddr *, - struct mbuf *, struct mbuf *); - void (*sockbuf_drop)(struct sockbuf *, int); - void (*sockbuf_flush)(struct sockbuf *sb); - void (*sowakeup)(struct socket *, struct sockbuf *); - void (*socket_set_connected)(struct socket *so); - void (*socket_set_connecting)(struct socket *so); - void (*socket_set_disconnected)(struct socket *so); - void (*socket_set_disconnecting)(struct socket *so); - void (*socket_set_hasoutofband)(struct socket *so); - void (*socket_set_cantrcvmore)(struct socket *so); - void (*socket_set_cantsendmore)(struct socket *so); - - /* pcb options */ - int (*in_pcballoc)(struct socket *, struct inpcb *); - void (*in_pcbdetach)(struct inpcb *); - int (*in_pcbbind)(struct inpcb *, struct mbuf *); - int (*in_pcbconnect)(struct inpcb *, struct mbuf *); - int (*in_pcbdisconnect)(struct inpcb *); - struct inpcb * (*in_pcblookup)(struct inpcb *, - struct in_addr, uint16, struct in_addr, uint16, int); - int (*in_control)(struct socket *, int, caddr_t, - struct ifnet *); - void (*in_losing)(struct inpcb *); - int (*in_canforward)(struct in_addr); - int (*in_localaddr)(struct in_addr); - struct rtentry *(*in_pcbrtentry)(struct inpcb *); - void (*in_setsockaddr)(struct inpcb *, struct mbuf *); - void (*in_setpeeraddr)(struct inpcb *, struct mbuf *); - void (*in_pcbnotify)(struct inpcb *, struct sockaddr *, - uint16, struct in_addr, uint16, - int, void (*)(struct inpcb *, int)); - int (*inetctlerrmap)(int); - uint16 (*in_cksum)(struct mbuf *m, int len, int off); - - - /* mbuf routines... */ - struct mbuf * (*m_gethdr)(int); - struct mbuf * (*m_get)(int); - void (*m_cat)(struct mbuf *, struct mbuf *); - void (*m_adj)(struct mbuf*, int); - struct mbuf * (*m_prepend)(struct mbuf*, int); - struct mbuf *(*m_pullup)(struct mbuf *, int); - void (*m_copyback)(struct mbuf *, int, int, caddr_t); - void (*m_copydata)(struct mbuf *, int, int, caddr_t); - struct mbuf *(*m_copym)(struct mbuf *, int, int); - struct mbuf * (*m_free)(struct mbuf *); - void (*m_freem)(struct mbuf *); - void (*m_reserve)(struct mbuf *, int); - struct mbuf *(*m_devget)(char *, int, int, struct ifnet *, - void (*copy)(const void *, void *, size_t)); - - /* module control routines... */ - void (*add_device)(struct ifnet *); - struct ifnet *(*get_interfaces)(void); - int (*in_broadcast)(struct in_addr, struct ifnet *); - - /* routing */ - void (*rtalloc)(struct route *ro); - struct rtentry *(*rtalloc1)(struct sockaddr *, int); - void (*rtfree)(struct rtentry *); - int (*rtrequest)(int, struct sockaddr *, - struct sockaddr *, struct sockaddr *, int, - struct rtentry **); - struct radix_node *(*rn_addmask)(void *, int, int); - struct radix_node *(*rn_head_search)(void *argv_v); - struct radix_node_head **(*get_rt_tables)(void); - int (*rt_setgate)(struct rtentry *, struct sockaddr *, - struct sockaddr *); - - /* ifnet functions */ - struct ifaddr *(*ifa_ifwithdstaddr)(struct sockaddr *addr); - struct ifaddr *(*ifa_ifwithnet)(struct sockaddr *addr); - void (*if_attach)(struct ifnet *); - void (*if_detach)(struct ifnet *); - struct ifaddr *(*ifa_ifwithaddr)(struct sockaddr *); - struct ifaddr *(*ifa_ifwithroute)(int, struct sockaddr *, - struct sockaddr *); - struct ifaddr *(*ifaof_ifpforaddr)(struct sockaddr *, struct ifnet *); - void (*ifafree)(struct ifaddr *); - - struct in_ifaddr *(*get_primary_addr)(void); - - int (*net_sysctl)(int *, uint, void *, size_t *, void *, size_t); - - /* socket functions - used by socket driver */ - int (*socket_init) (struct socket **nso); - int (*socket_create) (struct socket *so, int dom, int type, int proto); - int (*socket_close) (struct socket *so); - int (*socket_bind) (struct socket *so, caddr_t, int); - int (*socket_listen) (struct socket *so, int backlog); - int (*socket_connect) (struct socket *so, caddr_t, int); - int (*socket_accept) (struct socket *so, struct socket **nso, void *, int *); - int (*socket_recv) (struct socket *so, struct msghdr *, caddr_t namelenp, int *retsize); - int (*socket_send) (struct socket *so, struct msghdr *, int flags, int *retsize); - int (*socket_ioctl) (struct socket *so, int, caddr_t); - int (*socket_writev) (struct socket *so, struct iovec *, int flags); - int (*socket_readv) (struct socket *so, struct iovec *, int *flags); - int (*socket_setsockopt) (struct socket *so, int, int, const void *, size_t); - int (*socket_getsockopt) (struct socket *so, int, int, void *, size_t *); - int (*socket_getpeername) (struct socket *so, struct sockaddr *, int *); - int (*socket_getsockname) (struct socket *so, struct sockaddr *, int *); - int (*socket_socketpair) (struct socket *so, struct socket **nso); - int (*socket_set_event_callback)(struct socket *so, socket_event_callback, void *, int); - int (*socket_shutdown) (struct socket *so, int how); -}; - -#define NET_CORE_MODULE_NAME NETWORK_MODULES_ROOT "core/v1" - -#endif /* OBOS_CORE_MODULE_H */ diff --git a/headers/private/net/ether_driver.h b/headers/private/net/ether_driver.h deleted file mode 100644 index 55dc18c466..0000000000 --- a/headers/private/net/ether_driver.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ether_driver.h - * - * Ethernet driver: handles NE2000 and 3C503 cards - */ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. -*/ -#ifndef _ETHER_DRIVER_H -#define _ETHER_DRIVER_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* - * ioctls: belongs in a public header file - * somewhere, so that the net_server and other ethernet drivers can use. - */ -enum { - ETHER_GETADDR = B_DEVICE_OP_CODES_END, /* get ethernet address */ - ETHER_INIT, /* set irq and port */ - ETHER_NONBLOCK, /* set/unset nonblocking mode */ - ETHER_ADDMULTI, /* add multicast addr */ - ETHER_REMMULTI, /* rem multicast addr */ - ETHER_SETPROMISC, /* set promiscuous */ - ETHER_GETFRAMESIZE, /* get frame size */ - ETHER_ADDTIMESTAMP, /* (try to) add timestamps to packets (BONE ext) */ - ETHER_HASIOVECS, /* does the driver implement writev ? (BONE ext) (bool *) */ - ETHER_GETIFTYPE, /* get the IFT_ type of the interface (int *) */ - ETHER_GETLINKSTATE /* get line speed, quality, duplex mode, etc. */ -}; - - -/* - * 48-bit ethernet address, passed back from ETHER_GETADDR - */ -typedef struct { - unsigned char ebyte[6]; -} ether_address_t; - - -/* - * info passed to ETHER_INIT - */ - -typedef struct ether_init_params { - short port; - short irq; - unsigned long mem; -} ether_init_params_t; - -/* - * info returned from ETHER_GETLINKSTATE - */ - -typedef struct ether_link_state { - float link_speed; /* In Mbits per second */ - float link_quality; /* Set to zero if not connected */ - char duplex_mode; /* Set to 1 for full duplex, 0 for half */ -} ether_link_state_t; - -#ifdef __cplusplus -} -#endif - - -#endif /* _ETHER_DRIVER_H */ diff --git a/headers/private/net/ethernet_module.h b/headers/private/net/ethernet_module.h deleted file mode 100644 index 153fbca1f1..0000000000 --- a/headers/private/net/ethernet_module.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - ethernet_module.h -*/ - -#ifndef ETHERNET_MODULE_H -#define ETHERNET_MODULE_H - -#include "net_module.h" - -#include - -#define NET_ETHERNET_MODULE_NAME NETWORK_MODULES_ROOT "interfaces/ethernet" - -typedef void (*ethernet_receiver_func)(struct mbuf *buf); - -struct ethernet_module_info { - struct kernel_net_module_info info; - - void (*set_pppoe_receiver)(ethernet_receiver_func func); - void (*unset_pppoe_receiver)(void); -}; - -#endif /* ETHERNET_MODULE_H */ diff --git a/headers/private/net/icmp_module.h b/headers/private/net/icmp_module.h deleted file mode 100644 index 49263f3a88..0000000000 --- a/headers/private/net/icmp_module.h +++ /dev/null @@ -1,19 +0,0 @@ -/* icmp_module.h - */ - -#ifndef ICMP_MODULE_H -#define ICMP_MODULE_H - -#include "net_module.h" - -#include - -#define NET_ICMP_MODULE_NAME NETWORK_MODULES_ROOT "protocols/icmp" - -struct icmp_module_info { - struct kernel_net_module_info info; - - void (*error)(struct mbuf *, int, int, n_long, struct ifnet *); -}; - -#endif /* ICMP_MODULE_H */ diff --git a/headers/private/net/ipv4_module.h b/headers/private/net/ipv4_module.h deleted file mode 100644 index 80d9e94955..0000000000 --- a/headers/private/net/ipv4_module.h +++ /dev/null @@ -1,32 +0,0 @@ -/* ipv4_module.h - * definitions for ipv4 protocol - */ - -#ifndef IPV4_MODULE_H -#define IPV4_MODULE_H - -#include "net_module.h" - -#include - -#define NET_IPV4_MODULE_NAME NETWORK_MODULES_ROOT "protocols/ipv4" - -struct ipv4_module_info { - struct kernel_net_module_info info; - - int (*output)(struct mbuf *, - struct mbuf *, - struct route *, - int, void *); - uint16 (*ip_id)(void); - int (*ctloutput)(int, - struct socket *, - int, int, - struct mbuf **); - struct mbuf *(*ip_srcroute)(void); - void (*ip_stripoptions)(struct mbuf *, - struct mbuf *); - struct mbuf *(*srcroute)(void); -}; - -#endif /* IPV4_MODULE_H */ diff --git a/headers/private/net/lock.h b/headers/private/net/lock.h deleted file mode 100644 index 4595176aa8..0000000000 --- a/headers/private/net/lock.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef LOCK_H -#define LOCK_H -/* lock.h - benaphore locking, "faster semaphores", read/write locks -** sorry for all those macros; I wish C would support C++-style -** inline functions. -** -** Initial version by Axel Dörfler, axeld@pinc-software.de -** -** This file may be used under the terms of the OpenBeOS License. -*/ - - -#include - -// for read/write locks -#define MAX_READERS 100000 - - -struct benaphore { - sem_id sem; - int32 count; -}; - -typedef struct benaphore benaphore; - -// it may make sense to add a status field to the rw_lock to -// be able to check if the semaphore could be locked - -struct rw_lock { - sem_id sem; - int32 count; - benaphore writeLock; -}; - -typedef struct rw_lock rw_lock; - -#ifndef _KERNEL_MODE -#define INIT_BENAPHORE(lock,name) \ - { \ - (lock).count = 1; \ - (lock).sem = create_sem(0, name); \ - } - -#else - -#define INIT_BENAPHORE(lock,name) \ - { \ - (lock).count = 1; \ - (lock).sem = create_sem(0, name); \ - set_sem_owner((lock).sem, B_SYSTEM_TEAM); \ - } -#endif - - -#define CHECK_BENAPHORE(lock) \ - ((lock).sem) - -#define UNINIT_BENAPHORE(lock) \ - delete_sem((lock).sem); - -#define ACQUIRE_BENAPHORE(lock) \ - (atomic_add(&((lock).count), -1) <= 0 ? \ - acquire_sem_etc((lock).sem, 1, B_CAN_INTERRUPT, 0) \ - : B_OK) - -#define RELEASE_BENAPHORE(lock) \ - { \ - if (atomic_add(&((lock).count), 1) < 0) \ - release_sem((lock).sem); \ - } - -/* read/write lock */ -#ifndef _KERNEL_MODE -#define INIT_RW_LOCK(lock,name) \ - { \ - (lock).sem = create_sem(0, name); \ - (lock).count = MAX_READERS; \ - INIT_BENAPHORE((lock).writeLock, "r/w write lock"); \ - } - -#else - -#define INIT_RW_LOCK(lock,name) \ - { \ - (lock).sem = create_sem(0, name); \ - set_sem_owner((lock).sem, B_SYSTEM_TEAM); \ - (lock).count = MAX_READERS; \ - INIT_BENAPHORE((lock).writeLock, "r/w write lock"); \ - } - -#endif -#define CHECK_RW_LOCK(lock) \ - ((lock).sem) - -#define UNINIT_RW_LOCK(lock) \ - delete_sem((lock).sem); \ - UNINIT_BENAPHORE((lock).writeLock) - -#define ACQUIRE_READ_LOCK(lock) \ - { \ - if (atomic_add(&(lock).count, -1) <= 0) \ - acquire_sem((lock).sem); \ - } - -#define RELEASE_READ_LOCK(lock) \ - { \ - if (atomic_add(&(lock).count, 1) < 0) \ - release_sem((lock).sem); \ - } - -#define ACQUIRE_WRITE_LOCK(lock) \ - { \ - int32 readers; \ - ACQUIRE_BENAPHORE((lock).writeLock); \ - readers = atomic_add(&(lock).count, -MAX_READERS); \ - if (readers < MAX_READERS) \ - acquire_sem_etc((lock).sem,readers <= 0 ? 1 : MAX_READERS - readers,0,0); \ - RELEASE_BENAPHORE((lock).writeLock); \ - } - -#define RELEASE_WRITE_LOCK(lock) \ - { \ - int32 readers = atomic_add(&(lock).count,MAX_READERS); \ - if (readers < 0) \ - release_sem_etc((lock).sem,readers <= -MAX_READERS ? 1 : -readers,B_CAN_INTERRUPT); \ - } - -#endif /* LOCK_H */ diff --git a/headers/private/net/mbuf.h b/headers/private/net/mbuf.h deleted file mode 100644 index 8f08c789a8..0000000000 --- a/headers/private/net/mbuf.h +++ /dev/null @@ -1,311 +0,0 @@ -/* mbuf.h - * network buffer definitions - * - * Based on BSD's mbuf principal. - */ - -#include "pools.h" - -#ifndef OBOS_MBUF_H -#define OBOS_MBUF_H - -/* MBuf's are all of a single size, MSIZE bytes. If we have more data - * than can be fitted we can add a single "MBuf cluster" which is of - * fixed size MCLBYTES. - * If the data to be written is larger than MCLMINBYTES bytes we won't use - * the storage provided within the MBuf, but rather all data will go - * directly into an added cluster. - */ - -#define MSIZE 256 /* total size of structure */ -#define MCLSHIFT 11 -#define MCLBYTES (1 << MCLSHIFT) - -#define MCLMAXBYTES 2048 /* they can't be bigger than 2k */ -#define MLEN (MSIZE - sizeof(struct m_hdr)) /* data length w/o a pkt_hdr */ -#define MHLEN (MLEN - sizeof(struct pkt_hdr)) /* data length w/pkt_hdr */ -#define CLLEN (MCLBYTES - sizeof(struct cl_hdr)) - -#define MINCLSIZE (MHLEN + 1) - -/* mbuf header structure - * This appears at teh start of every MBuf - */ -struct m_hdr { - struct mbuf *m_next; /* next mbuf in a chain */ - struct mbuf *m_nxtpkt; /* next chain in a packet/queue */ - char * m_data; /* pointer to data */ - uint32 m_len; /* length data in this mbuf NB NOT total length */ - uint16 m_type; /* what sort of data do we have ? */ - uint16 m_flags; /* flags as defined below */ - uint16 m_cksum; /* flags about the checksum on the packet */ -}; - -/* pkt_hdr - * This is ONLY found in the first MBuf in a chain and is valid - * ONLY if we have the M_PKTHDR flag is set - */ -/* XXX - we also need to record things like the interface and also maintain - * a list of the packets associated with this message here. - */ -struct pkt_hdr { - struct ifnet *rcvif; /* interface we came it on */ - int len; /* total length */ - int csum; /* hardware cksum info... */ -}; - -/* m_ext - * External storage, i.e. a cluster - */ -struct m_ext { - char *ext_buf; /* start of the buffer */ -// void *(ext_free)(); /* free routine (if not standard) */ - uint ext_size; /* how big is the buffer */ -}; - -/* struct mbuf - * The actual buffer structure. - * This is defined as unions as the size is slightly variable - * depending on the options set. - */ - -struct mbuf { - struct m_hdr m_hdr; - union { - struct { - struct pkt_hdr MH_pkthdr; - union { - struct m_ext MH_ext; - char MH_databuf[MHLEN]; - } MH_dat; - } MH; - char m_databuf[MLEN]; - } um_dat; -}; - -/* these are simply shortcuts... */ -#define m_next m_hdr.m_next -#define m_len m_hdr.m_len -#define m_data m_hdr.m_data -#define m_type m_hdr.m_type -#define m_flags m_hdr.m_flags -#define m_cksum m_hdr.m_cksum -#define m_nextpkt m_hdr.m_nxtpkt -#define m_ext um_dat.MH.MH_dat.MH_ext -#define m_pktdat um_dat.MH.MH_dat.MH_databuf -#define m_pkthdr um_dat.MH.MH_pkthdr -#define m_dat um_dat.m_databuf - -/* define a little macro that gives us the data pointer for an mbuf */ -#define mtod(m, t) ((t)((m)->m_data)) -#define dtom(x) ((struct mbuf *)((int)(x) & ~(MSIZE-1))) - -/* mbuf flags */ -enum { - M_EXT = 0x0001, /* has extenal storage attached */ - M_PKTHDR = 0x0002, /* contains the packet header */ - M_EOR = 0x0004, /* end of record (not used for tcp/udp) */ - M_CLUSTER = 0x0008, /* external storage is a cluster */ -/* - M_PROTO = 0x0010, * protocol specific * -*/ - M_BCAST = 0x0100, /* rx/tx as a link-level broadcast */ - M_MCAST = 0x0200, /* rx/tx as a link-level multicast */ - M_CONF = 0x0400, /* packet was encrypted?? */ - M_AUTH = 0x0800, /* packet was authenticated */ - M_COMP = 0x1000, /* packet was compressed */ - M_ANYCAST6 = 0x4000 /* it was an IPv6 anycast packet */ -}; -/* the M_COPYFLAGS lists the flags that can be copied when we copy - * an mbuf with the M_PKTHDR flag set */ -#define M_COPYFLAGS (M_PKTHDR | M_EOR | M_BCAST | M_MCAST) - -/* checksum flags */ -enum { - M_IPV4_CSUM_OUT = 0x0001, /* ipv4 checksum required */ - M_TCPV4_CSUM_OUT = 0x0002, /* TCP v4 checksum required */ - M_UDPV4_CSUM_OUT = 0x0004, - - M_IPV4_CSUM_IN_OK = 0x0008, - M_IPV4_CSUM_IN_OUT = 0x0010, - - M_TCP_CSUM_IN_OK = 0x0020, - M_TCP_CSUM_IN_BAD = 0x0040, - - M_UDP_CSUM_IN_OK = 0x0080, - M_UDP_CSUM_IN_BAD = 0x0100 -}; - -/* MBuf types */ -enum { - MT_FREE = 0, /* should be on free list */ - MT_DATA = 1, /* dynamic data allocation */ - MT_HEADER = 2, /* packet header */ - MT_SONAME = 3, - MT_SOOPTS = 4, - MT_FTABLE = 5, /* fragment reassembly header */ - MT_CONTROL = 6, /* extra-data protocol message */ - MT_OOBDATA = 7 /* out-of-band data */ -}; - -/* length to m_copy to copy all */ -#define M_COPYALL 1000000000 - -/* now some macro's to make life easier... */ - -/* need to add the macro's here :) */ - -#define MRESETDATA(m) do { \ - if ((m)->m_flags & M_EXT) \ - (m)->m_data = (m)->m_ext.ext_buf; \ - else if ((m)->m_flags & M_PKTHDR) \ - (m)->m_data = (m)->m_pktdat; \ - else \ - (m)->m_data = (m)->dat; \ - } while (0) - -/* fill in an mbuf */ -#define MGET(n, type) \ - n = (struct mbuf*) pool_get(mbpool); \ - if (n) { \ - (n)->m_type = (type); \ - (n)->m_next = NULL; \ - (n)->m_nextpkt = NULL; \ - (n)->m_data = (n)->m_dat; \ - (n)->m_flags = 0; \ - (n)->m_cksum = 0; \ - } - -#define MGETHDR(n, type) \ - n = (struct mbuf*) pool_get(mbpool); \ - if (n) { \ - (n)->m_type = (type); \ - (n)->m_next = NULL; \ - (n)->m_nextpkt = NULL; \ - (n)->m_data = (n)->m_pktdat; \ - (n)->m_flags = M_PKTHDR; \ - (n)->m_cksum = 0; \ - } - -#define _MEXTREMOVE(m) do { \ - if ((m)->m_flags & M_CLUSTER) { \ - pool_put(clpool, (m)->m_ext.ext_buf); \ - } \ - (m)->m_flags &= ~(M_CLUSTER|M_EXT); \ - (m)->m_ext.ext_size = 0; \ - } while (0) - -#define MFREE(m, n) \ - if ((m)->m_flags & M_EXT) { \ - _MEXTREMOVE(m); \ - } \ - (n) = (m)->m_next; \ - pool_put(mbpool, m); - -/* set the data pointer to place an object of size len at the end - * of the mbuf, aligned to long word (16 bits) - */ -#define M_ALIGN(m, len) \ - { (m)->m_data += (MLEN - (len)) &~ (sizeof(int16) -1);} - -#define MH_ALIGN(m, len) \ - { (m)->m_data += (MHLEN - (len)) &~ (sizeof(int16) -1);} - -#define M_MOVE_HDR(to, from) { \ - (to)->m_pkthdr = (from)->m_pkthdr; \ - (from)->m_flags &= ~M_PKTHDR; \ - } - -#define M_MOVE_PKTHDR(to, from) { \ - (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ - M_MOVE_HDR((to), (from)); \ - (to)->m_data = (to)->m_pktdat; \ - } - -#define MCLGET(m) do { \ - (m)->m_ext.ext_buf = pool_get(clpool); \ - if ((m)->m_ext.ext_buf != NULL) { \ - (m)->m_data = (m)->m_ext.ext_buf; \ - (m)->m_flags |= M_EXT|M_CLUSTER; \ - (m)->m_ext.ext_size = MCLBYTES; \ - } \ - } while (0) - -#define M_LEADINGSPACE(m) \ - ((m)->m_flags & M_EXT ? (m)->m_data - (m)->m_ext.ext_buf : \ - (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \ - (m)->m_data - (m)->m_dat) - -#define M_PREPEND(m, plen) { \ - if (M_LEADINGSPACE(m) >= (plen)) { \ - (m)->m_data -= (plen); \ - (m)->m_len += (plen); \ - } else \ - (m) = m_prepend((m), (plen)); \ - if ((m) && (m)->m_flags & M_PKTHDR) \ - (m)->m_pkthdr.len += (plen); \ -} - -/* - * Duplicate just m_pkthdr from from to to. - */ -#define M_DUP_HDR(to, from) { \ - (to)->m_pkthdr = (from)->m_pkthdr; \ -} - -/* - * Duplicate mbuf pkthdr from from to to. - * from must have M_PKTHDR set, and to must be empty. - */ -#define M_DUP_PKTHDR(to, from) { \ - (to)->m_flags = (from)->m_flags & M_COPYFLAGS; \ - M_DUP_HDR((to), (from)); \ - (to)->m_data = (to)->m_pktdat; \ -} - -#define M_TRAILINGSPACE(m) \ - ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size - \ - ((m)->m_data + (m)->m_len) : \ - &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len)) - -#define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) - -#define M_DATASTART(m) \ - (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ - (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) - -#define M_DATASIZE(m) \ - (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ - (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) - -/* Functions! */ -void mbinit(void); -struct mbuf *m_get(int type); - -struct mbuf *m_gethdr(int type); -struct mbuf *m_getclr(int type); - -struct mbuf *m_prepend(struct mbuf *m, int len); -struct mbuf *m_devget(char *buf, int totlen, int off0, - struct ifnet *ifp, - void (*copy)(const void *, void *, size_t)); -struct mbuf *m_pullup(struct mbuf *, int len); -void m_copyback(struct mbuf *m0, int off, int len, caddr_t cp); - -struct mbuf *m_free(struct mbuf *mfree); -void m_freem(struct mbuf *m); - -void m_reserve(struct mbuf *mp, int len); -void m_cat(struct mbuf *m, struct mbuf *n); -void m_adj(struct mbuf *mp, int req_len); -void m_copydata(struct mbuf *m, int off, int len, caddr_t cp); -struct mbuf *m_copym(struct mbuf *m, int off0, int len); - -/* debug functions */ -void dump_freelist(void); - -/* Stats structure */ -/* XXX - add me! */ - - -#endif /* OBOS_MBUF_H */ diff --git a/headers/private/net/net_malloc.h b/headers/private/net/net_malloc.h deleted file mode 100644 index 4b041f79a4..0000000000 --- a/headers/private/net/net_malloc.h +++ /dev/null @@ -1,37 +0,0 @@ -/* net_malloc.h - * - * Are we useing the system amlloc or our own... - */ - -#ifndef NET_MALLOC_H -#define NET_MALLOC_H - -#include -#include "net_misc.h" - -#if USE_DEBUG_MALLOC - - - -/* We check the boundary of the malloc'd area at one end of the - * area allocated. If we are outside the area it'll stop, but we can - * check only one end of the boundary. So the following essentially - * allows us to choose which end. - */ -//#define OVERRUN -#ifdef OVERRUN -#define CHECK_OVERRUN 1 -#else -#define CHECK_UNDERRUN 1 -#endif - -/* use the area malloc code from marcus Overhagen */ -void *dbg_malloc(char *file, int line, size_t size); -void dbg_free (char *file, int line, void *ptr); - -#define malloc(s) dbg_malloc(__FILE__, __LINE__, s) -#define free(s) do { dbg_free(__FILE__, __LINE__, s); s = NULL; } while (0) -#endif /* USE_DEBUG_MALLOC */ - -#endif /* NET_MALLOC_H */ - diff --git a/headers/private/net/net_misc.h b/headers/private/net/net_misc.h deleted file mode 100644 index b86fc17c8b..0000000000 --- a/headers/private/net/net_misc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* net_misc.h - * Miscellaneous networking stuff that doesn't yet have a home. - */ - -//#ifdef _NETWORK_STACK - -#ifndef OBOS_NET_MISC_H -#define OBOS_NET_MISC_H - -//#include -#include -#include - -#ifdef _KERNEL_MODE -#include -#define printf dprintf -#endif - -#ifndef __HAIKU__ -/* Not really sure if this is safe... */ -#define EHOSTDOWN (B_POSIX_ERROR_BASE + 45) -#endif - -/* These are GCC only, so we'll need PPC version eventually... */ -struct quehead { - struct quehead *qh_link; - struct quehead *qh_rlink; -}; - -static __inline void insque(void *a, void *b) -{ - struct quehead *element = (struct quehead *)a, - *head = (struct quehead *)b; - - element->qh_link = head->qh_link; - element->qh_rlink = head; - head->qh_link = element; - element->qh_link->qh_rlink = element; -} - -static __inline void remque(void *a) -{ - struct quehead *element = (struct quehead *)a; - - element->qh_link->qh_rlink = element->qh_rlink; - element->qh_rlink->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -/* DEBUG Options! - * - * Having a single option is sort of lame so I'm going to start adding more here... - * - */ -#define SHOW_DEBUG 0 /* general debugging stuff (verbose!) */ -#define SHOW_ROUTE 0 /* show routing information */ -#define ARP_DEBUG 0 /* show ARP debug info */ -#define USE_DEBUG_MALLOC 0 /* use the debug malloc code*/ - -typedef struct ifnet ifnet; - -/* ARP lookup return codes... */ -enum { - ARP_LOOKUP_OK = 1, - ARP_LOOKUP_QUEUED = 2, - ARP_LOOKUP_FAILED = 3 -}; - -typedef uint32 ipv4_addr; - -/* XXX - add some macro's for inserting various types of address - */ - -void net_server_add_device(ifnet *ifn); -//XXX already in netinet/in.h -//uint16 in_cksum(struct mbuf *m, int len, int off); -void local_init(void); - -/* sockets and in_pcb init */ -int sockets_init(void); -void sockets_shutdown(void); -int inpcb_init(void); - -void start_tx_thread(ifnet *dev); -void start_rx_thread(ifnet *dev); - -/* Useful debugging functions */ -void dump_ipv4_addr(char *msg, void *ad); -void print_ipv4_addr(void *ad); -void dump_ether_addr(char *msg, void *ma); -void print_ether_addr(void *ea); -void dump_buffer(char *buffer, int len); -void dump_sockaddr(void *ptr); - -#endif /* OBOS_NET_MISC_H */ - -//#endif /* _NETWORK_STACK */ - diff --git a/headers/private/net/net_module.h b/headers/private/net/net_module.h deleted file mode 100644 index d80de6922a..0000000000 --- a/headers/private/net/net_module.h +++ /dev/null @@ -1,41 +0,0 @@ -/* net_module.h - * fundtions and staructures for all modules using the - * net_server - */ - -#ifndef OBOS_NET_MODULE_H -#define OBOS_NET_MODULE_H - -#include -#include - -#include "mbuf.h" -#include "net_misc.h" -#include "sys/socketvar.h" -#include "net/if.h" -#include "net/route.h" - -#include - -#ifndef __HAIKU__ -#define NETWORK_MODULES_ROOT "obos_network/" -#else -#define NETWORK_MODULES_ROOT "network/" -#endif - -struct kernel_net_module_info { - module_info info; - int (*start)(void *); - int (*stop)(void); - status_t (*control)(uint32 op, void *data, size_t length); -}; - -struct net_module { - struct net_module *next; - char *name; - struct kernel_net_module_info *ptr; - int status; -}; - -#endif /* OBOS_NET_MODULE_H */ - diff --git a/headers/private/net/net_socket.h b/headers/private/net/net_socket.h deleted file mode 100644 index 8266d6fa36..0000000000 --- a/headers/private/net/net_socket.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef _NET_SOCKET_H -#define _NET_SOCKET_H - -#include -#include - -/* Function prototypes */ - -/* These functions are exported through the core module */ - -int socket_init (struct socket **nso); -int socket_create (struct socket *so, int dom, int type, int proto); -int socket_shutdown (struct socket *so, int how); // XXX this one is not used at all -int socket_close (struct socket *so); - -int socket_bind (struct socket *so, char *, int); -int socket_listen (struct socket *so, int backlog); -int socket_connect (struct socket *so, char *, int); -int socket_accept (struct socket *so, struct socket **nso, void *, int *); - -int socket_writev (struct socket *so, struct iovec *, int flags); -int socket_readv (struct socket *so, struct iovec *, int *flags); -int socket_send (struct socket *so, struct msghdr *, int flags, int *retsize); -int socket_recv (struct socket *so, struct msghdr *, caddr_t namelenp, int *retsize); - -int socket_setsockopt (struct socket *so, int, int, const void *, size_t); -int socket_getsockopt (struct socket *so, int, int, void *, size_t *); -int socket_ioctl (struct socket *so, int cmd, caddr_t data); - -int socket_getpeername (struct socket *so, struct sockaddr *, int *); -int socket_getsockname (struct socket *so, struct sockaddr *, int *); - -int socket_socketpair (struct socket *so, struct socket **nso); - -int socket_set_event_callback(struct socket *so, socket_event_callback, void *, int); - - -/* these are all private to the stack...although may be shared with - * other network modules. - */ - - -struct socket *sonewconn(struct socket *head, int connstatus); -int soreserve (struct socket *so, uint32 sndcc, uint32 rcvcc); - -void sockbuf_release(struct sockbuf *sb); -int sockbuf_reserve(struct sockbuf *sb, uint32 cc); -void sockbuf_drop(struct sockbuf *sb, int len); -void sockbuf_droprecord(struct sockbuf *sb); -void sockbuf_flush(struct sockbuf *sb); -int sockbuf_wait(struct sockbuf *sb); -void sockbuf_append(struct sockbuf *sb, struct mbuf *m); -int sockbuf_appendaddr(struct sockbuf *sb, struct sockaddr *asa, - struct mbuf *m0, struct mbuf *control); -int sockbuf_appendcontrol(struct sockbuf *sb, struct mbuf *m0, - struct mbuf *control); -void sockbuf_appendrecord(struct sockbuf *sb, struct mbuf *m0); -void sockbuf_compress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n); -void sockbuf_insertoob(struct sockbuf *, struct mbuf *); - -void sowakeup(struct socket *so, struct sockbuf *sb); - -int sodisconnect(struct socket *); - -void socket_set_hasoutofband(struct socket *so); -void socket_set_cantsendmore(struct socket *so); -void socket_set_cantrcvmore(struct socket *so); -void socket_set_connected(struct socket *so); -void socket_set_connecting(struct socket *so); -void socket_set_disconnected(struct socket *so); -void socket_set_disconnecting(struct socket *so); - -int sorflush(struct socket *so); - -int sockbuf_lock(struct sockbuf *sb); -int nsleep(sem_id chan, char *msg, int timeo); -void wakeup(sem_id chan); - -#endif diff --git a/headers/private/net/net_stack_driver.h b/headers/private/net/net_stack_driver.h deleted file mode 100644 index e09c83b006..0000000000 --- a/headers/private/net/net_stack_driver.h +++ /dev/null @@ -1,169 +0,0 @@ -/* net_stack_driver.h - * structures and defines to deal with the network stack pseudo-driver... - */ - -#ifndef NET_STACK_DRIVER_H -#define NET_STACK_DRIVER_H - -#include -#include -#include - -// Forward declaration -struct sockaddr; - -#define NET_STACK_DRIVER_DEV "net/stack" -#define NET_STACK_DRIVER_PATH "/dev/" NET_STACK_DRIVER_DEV - -enum { - // Paranoia mode: be far away of B_DEVICE_OP_CODES_END opcodes!!! - // You never know what another device driver ioctl() will do - // if think our NET_STACK_* is in fact his DO_RISKY_BUSINESS opcode, or whatever... - NET_IOCTL_BASE = 0xbe230000, - NET_STACK_IOCTL_BASE = NET_IOCTL_BASE + 0x200 -}; - -enum { - // ops not acting on an existing socket - NET_STACK_SOCKET = NET_STACK_IOCTL_BASE, // socket_args * - NET_STACK_GET_COOKIE, // void ** - NET_STACK_CONTROL_NET_MODULE, // control_net_module_args * - NET_STACK_SYSCTL, // sysctl_args * - - // ops acting on an existing socket - NET_STACK_BIND, // sockaddr_args * - NET_STACK_RECVFROM, // struct msghdr * - NET_STACK_RECV, // transfer_args * - NET_STACK_SENDTO, // struct msghdr * - NET_STACK_SEND, // transfer_args * - NET_STACK_LISTEN, // int_args * (value = backlog) - NET_STACK_ACCEPT, // sockaddr_args * - NET_STACK_CONNECT, // sockaddr_args * - NET_STACK_SHUTDOWN, // int_args * (value = how) - NET_STACK_GETSOCKOPT, // sockopt_args * - NET_STACK_SETSOCKOPT, // sockopt_args * - NET_STACK_GETSOCKNAME, // sockaddr_args * - NET_STACK_GETPEERNAME, // sockaddr_args * - NET_STACK_SOCKETPAIR, // socketpair_args * - - // TODO: remove R5 select() emulation - NET_STACK_SELECT, // select_args * - NET_STACK_DESELECT, // select_args * - - NET_STACK_NOTIFY_SOCKET_EVENT, // notify_socket_event_args * (userland stack only) - - NET_STACK_IOCTL_MAX -}; - -struct sockaddr_args { // used by NET_STACK_CONNECT/_BIND/_GETSOCKNAME/_GETPEERNAME - struct sockaddr *addr; - socklen_t addrlen; -}; - -struct sockopt_args { // used by NET_STACK_SETSOCKOPT/_GETSOCKOPT - int level; - int option; - void *optval; - int optlen; -}; - -struct transfer_args { // used by NET_STACK_SEND/_RECV - void *data; - size_t datalen; - int flags; - struct sockaddr *addr; // unused in *_SEND and *_RECV cases - int addrlen; // unused in *_SEND and *_RECV cases -}; - -struct socket_args { // used by NET_STACK_SOCKET - int family; - int type; - int proto; -}; - -struct socketpair_args { // used by NET_STACK_SOCKETPAIR - void *cookie; -}; - -struct accept_args { // used by NET_STACK_ACCEPT - void *cookie; - struct sockaddr *addr; - socklen_t addrlen; -}; - -struct sysctl_args { // used by NET_STACK_SYSCTL - int *name; - uint namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; -}; - -struct control_net_module_args { // used by NET_STACK_CONTROL_NET_MODULE - const char *name; - uint32 op; - void *data; - size_t length; -}; - -/* - Userland stack driver on_socket_event() callback mecanism implementation: - the driver start a kernel thread waiting on a port for - a NET_STACK_SOCKET_EVENT_MSG message, which come with a socket_event_data block. - - The on_socket_event() mechanism stay in driver (kernelland) because it's - only there we can call kernel's notify_select_event() on BONE systems. - For non-BONE systems, we use our own r5_notify_select_event() - implementation, that could be moved into the userland net_server code, - but it'll have split (again!) the /dev/net/stack driver code... -*/ - -struct notify_socket_event_args { // used by NET_STACK_NOTIFY_SOCKET_EVENT - port_id notify_port; // port waiting for notification, -1 = stop notify - void * cookie; // this cookie value will be pass back in the socket_event_args -}; - -#define NET_STACK_SOCKET_EVENT_NOTIFICATION 'sevn' - -struct socket_event_data { - uint32 event; // B_SELECT_READ, B_SELECT_WRITE or B_SELECT_ERROR - void * cookie; // The cookie as set in notify_socket_event_args for this socket -}; - -/* - R5.0.3 and before select() kernel support is too buggy to be used, so - here are the structures we used to support select() on sockets, and *only* on - sockets! -*/ - -struct select_args { // used by NET_STACK_SELECT and NET_STACK_DESELECT - struct selectsync * sync; // in fact, it's the area_id of a r5_selectsync struct!!! - uint32 ref; -}; - -struct r5_selectsync { - sem_id lock; // lock this r5_selectsync - sem_id wakeup; // sem to release to wakeup select() - struct fd_set rbits; // read event bits field - struct fd_set wbits; // write event bits field - struct fd_set ebits; // exception event bits field -}; - - -struct stack_driver_args { - union { - int integer; - struct socket_args socket; - struct accept_args accept; - struct sockaddr_args sockaddr; - struct sockopt_args sockopt; - struct transfer_args transfer; - struct sysctl_args sysctl; - struct select_args select; - struct control_net_module_args control; - struct socketpair_args socketpair; - } u; -}; - -#endif /* NET_STACK_DRIVER_H */ diff --git a/headers/private/net/net_timer.h b/headers/private/net/net_timer.h deleted file mode 100644 index c700d76d56..0000000000 --- a/headers/private/net/net_timer.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef NET_TIMER_H -#define NET_TIMER_H -/* net_timer.h - a small and more or less inaccurate timer for net modules. -** The registered hooks will be called in the thread of the timer. -** -** Initial version by Axel Dörfler, axeld@pinc-software.de -** -** This file may be used under the terms of the OpenBeOS License. -*/ - - -#include - - -typedef void (*net_timer_hook)(void *); -typedef int32 net_timer_id; - - -extern status_t net_init_timer(void); -extern void net_shutdown_timer(void); - -extern net_timer_id net_add_timer(net_timer_hook hook, void *data, bigtime_t interval); -extern status_t net_remove_timer(net_timer_id); - - -#endif /* NET_TIMER_H */ diff --git a/headers/private/net/netconfig.h b/headers/private/net/netconfig.h deleted file mode 100644 index 8b9153c404..0000000000 --- a/headers/private/net/netconfig.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. -*/ -/* - * netconfig.h - * Copyright (c) 1995 Be, Inc. All Rights Reserved - * - * Stuff for reading info out of the /boot/system/netconfig file - */ -#ifndef _NETCONFIG_H -#define _NETCONFIG_H - -#if __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include -#include - -#define NC_MAXCLASSLEN 256 -#define NC_MAXNAMELEN 256 -#define NC_MAXVALLEN 256 - - -static const char NETCONFIGFILE[] = "/network"; -static const char NETCONFIGFILE_TMP[] = "/network.tmp"; - - -typedef struct _netconfig { - FILE *ncfile; - char ncbuf[1020]; -} NETCONFIG; - -typedef char nc_data_t[NC_MAXVALLEN]; - -typedef struct nc_private { - nc_data_t key; - nc_data_t value; -} nc_private_t; - -_IMPEXP_NET NETCONFIG *_netconfig_open(const char *heading); -_IMPEXP_NET char *_netconfig_find(const char *heading, const char *name, char *value, - int nbytes); -_IMPEXP_NET int _netconfig_set(const char *heading, const char *name, const char *value); - - -_IMPEXP_NET net_settings *_net_settings_open(const char *fname); - -_IMPEXP_NET void _net_settings_makedefault(net_settings *ncw); -_IMPEXP_NET int _net_settings_save(net_settings *ncw); -_IMPEXP_NET int _net_settings_save_as(net_settings *ncw, const char *fname); -_IMPEXP_NET void _net_settings_close(net_settings *ncw); - -_IMPEXP_NET int _netconfig_getnext( - NETCONFIG *netconfig, - char **name, - char **value - ); - -_IMPEXP_NET void _netconfig_close(NETCONFIG *netconfig); - - -#define net_settings_isdirty(ncw) (ncw)->_dirty -#define net_settings_makedirty(ncw, mkdirty) (ncw)->_dirty = mkdirty -#define net_settings_makedefault _net_settings_makedefault -#define netconfig_open _netconfig_open -#define net_settings_open _net_settings_open -#define netconfig_find _netconfig_find -#define netconfig_set _netconfig_set -#define net_settings_save _net_settings_save -#define net_settings_save_as _net_settings_save_as -#define net_settings_close _net_settings_close -#define netconfig_getnext _netconfig_getnext -#define netconfig_close _netconfig_close - -#if __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _NETCONFIG_H */ diff --git a/headers/private/net/netdebug.h b/headers/private/net/netdebug.h deleted file mode 100644 index d4e4df7a1c..0000000000 --- a/headers/private/net/netdebug.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * netdebug.h - * - * Debugging message support. Nothing really network specific about - * it, but renamed from "debug.h" to distinguish it from other debug.h's - * that live around the system, and because the *&^%$#@! Metrowerks - * compiler can't deal with subdirs in include directives. - */ -/* - Copyright 1999, Be Incorporated. All Rights Reserved. - This file may be used under the terms of the Be Sample Code License. -*/ -#ifndef _NETDEBUG_H -#define _NETDEBUG_H - -#include - -#ifdef __cplusplus -#define EXTERNC extern "C" -#else -#define EXTERNC extern -#endif - -/* - * Debug messages can go to a file, to the console, to both or to nowhere. - * Use debug_setflags() to set. - */ -#define DEBUG_CONSOLE 1 -#define DEBUG_FILE 2 -#define DEBUG_NOFLUSH 4 - -EXTERNC _IMPEXP_NET void _debug_setflags(unsigned flags); -EXTERNC _IMPEXP_NET unsigned _debug_getflags(void); - -#define debug_setflags _debug_setflags -#define debug_getflags _debug_getflags - -/* - * function -DDEBUG=? comment - * _____________________________________________________ - * wprintf anything for warnings - * dprintf DEBUG > 0 for debugging messages - * ddprintf DEBUG > 1 for extra debugging messages - */ - -EXTERNC _IMPEXP_NET int _wprintf(const char *format, ...); -EXTERNC _IMPEXP_NET int _dprintf(const char *format, ...); - -/* - * Define null function "noprintf" - */ -#define noprintf (void) - -#if DEBUG -#define wprintf _dprintf -#define dprintf _dprintf - -#if DEBUG > 1 -#define ddprintf _dprintf -#else /* DEBUG > 1 */ -#define ddprintf noprintf -#endif /* DEBUG > 1 */ - -#else /* DEBUG */ - -#define wprintf _wprintf -#define dprintf noprintf -#define ddprintf noprintf - -#endif /* DEBUG */ - -#endif /* _NETDEBUG_H */ diff --git a/headers/private/net/netgroup.h b/headers/private/net/netgroup.h deleted file mode 100644 index 2296208c15..0000000000 --- a/headers/private/net/netgroup.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef netgroup_h -#define netgroup_h -#ifndef __GLIBC__ - -/* - * The standard is crazy. These values "belong" to getnetgrent() and - * shouldn't be altered by the caller. - */ -int getnetgrent __P((/* const */ char **, /* const */ char **, - /* const */ char **)); - -int getnetgrent_r __P((char **, char **, char **, char *, int)); - -void endnetgrent __P((void)); - -#ifdef __osf__ -int innetgr __P((char *, char *, char *, char *)); -void setnetgrent __P((char *)); -#else -void setnetgrent __P((const char *)); -int innetgr __P((const char *, const char *, const char *, const char *)); -#endif -#endif -#endif diff --git a/headers/private/net/nhash.h b/headers/private/net/nhash.h deleted file mode 100644 index 2e0fa4bbb7..0000000000 --- a/headers/private/net/nhash.h +++ /dev/null @@ -1,40 +0,0 @@ -/* nhash.h - */ - -#ifndef OBOS_NHASH_H -#define OBOS_NHASH_H - -#include "pools.h" - -typedef struct net_hash_entry net_hash_entry; -typedef struct net_hash net_hash; -typedef struct net_hash_index net_hash_index; - -struct net_hash_entry { - net_hash_entry *next; - int hash; - const void *key; - ssize_t klen; - const void *val; -}; - -struct net_hash_index { - net_hash *nh; - net_hash_entry *this; - net_hash_entry *next; - int index; -}; - -struct net_hash { - net_hash_entry **array; - net_hash_index iterator; - int count; - int max; - struct pool_ctl *pool; -}; - -net_hash *nhash_make(void); -void *nhash_get(net_hash *, const void *key, ssize_t klen); -void nhash_set(net_hash *, const void *, ssize_t , const void *); - -#endif /* OBOS_NHASH_H */ diff --git a/headers/private/net/pools.h b/headers/private/net/pools.h deleted file mode 100644 index 61d3b1d182..0000000000 --- a/headers/private/net/pools.h +++ /dev/null @@ -1,55 +0,0 @@ -/* pools.h - * simple fixed size block allocator - */ - -#ifndef OBOS_POOLS_H -#define OBOS_POOLS_H - - -#include - -#include "lock.h" - - -typedef struct pool_ctl pool_ctl; - -struct pool_mem { - struct pool_mem *next; - area_id aid; - char *base_addr; - size_t mem_size; - char *ptr; - size_t avail; - benaphore lock; -}; - -struct free_blk { - char *next; -}; - -#define POOL_USES_BENAPHORES 0 -#define POOL_DEBUG_NAME_SZ 32 - -struct pool_ctl { - struct pool_mem *list; - char *freelist; - size_t alloc_size; - size_t block_size; -#if POOL_USES_BENAPHORES - benaphore lock; -#else - rw_lock lock; -#endif - int debug; - char name[POOL_DEBUG_NAME_SZ]; -}; - -status_t pool_init(pool_ctl **p, size_t sz); -char *pool_get(pool_ctl *p); -void pool_put(pool_ctl *p, void *ptr); -void pool_destroy(pool_ctl *p); -void pool_debug(struct pool_ctl *p, char *name); - -void pool_debug_walk(pool_ctl *p); - -#endif /* OBOS_POOLS_H */ diff --git a/headers/private/net/protocols.h b/headers/private/net/protocols.h deleted file mode 100644 index a2fff62fc7..0000000000 --- a/headers/private/net/protocols.h +++ /dev/null @@ -1,48 +0,0 @@ -/* protocols.h - * The various protocols we're likely to come across as - * they're identified in the type fields of packets... - */ - -#include "netinet/in.h" - -#ifndef OBOS_PROTOCOLS_H -#define OBOS_PROTOCOLS_H - -/* define some protocol numbers unique to ethernet */ -enum { - ETHER_IPV4 = 0x0800, - ETHER_ARP = 0x0806, - ETHER_RARP = 0x8035, - ETHER_ATALK = 0x809b, /* Appletalk */ - ETHER_SNMP = 0x814c, /* SNMP */ - ETHER_IPV6 = 0x86dd, /* IPv6 */ - ETHER_PPPOE_DISC = 0x8863, /* PPPoE Discovery */ - ETHER_PPPOE_SESS = 0x8864 /* PPPoE Session */ -}; - -/* these are used when assigning slots in the protocol table, so they - * should tie in with IP numbers wherever possible, with other - * protocols fitting in. - * These are used in the module definitions. - */ -enum { - NS_IPV4 = IPPROTO_IP, - NS_ICMP = IPPROTO_ICMP, - NS_IGMP = IPPROTO_IGMP, - NS_TCP = IPPROTO_TCP, - NS_UDP = IPPROTO_UDP, - NS_ETHER=200, - NS_IPV6, - NS_ATALK, - NS_ARP, - NS_RARP, - NS_PPPOE, - NS_SERIAL, - NS_LOOP, - NS_SOCKET, - NS_ROUTE -}; - - -#endif /* OBOS_PROTOCOLS_H */ - diff --git a/headers/private/net/raw_module.h b/headers/private/net/raw_module.h deleted file mode 100644 index c6d59f71cc..0000000000 --- a/headers/private/net/raw_module.h +++ /dev/null @@ -1,20 +0,0 @@ -/* raw_module.h - */ - -#ifndef RAW_MODULE_H -#define RAW_MODULE_H - -#include "net_module.h" - -#include - - -#define NET_RAW_MODULE_NAME NETWORK_MODULES_ROOT "protocols/raw" - -struct raw_module_info { - struct kernel_net_module_info info; - - void (*input)(struct mbuf *, int); -}; - -#endif /* RAW_MODULE_H */ diff --git a/headers/private/net/sys/domain.h b/headers/private/net/sys/domain.h deleted file mode 100644 index 20919dd969..0000000000 --- a/headers/private/net/sys/domain.h +++ /dev/null @@ -1,35 +0,0 @@ -/* domain.h */ - -/* A domain is just a container for like minded protocols! */ - -#ifndef _SYS_DOMAIN_H -#define _SYS_DOMAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct domain { - int dom_family; /* AF_INET and so on */ - char *dom_name; - - void (*dom_init)(void); /* initialise */ - - struct protosw *dom_protosw; /* the protocols we have */ - struct domain *dom_next; - - int (*dom_rtattach)(void **, int); - int dom_rtoffset; - int dom_maxrtkey; -}; - -extern struct domain *domains; - -void add_domain (struct domain *dom, int fam); -void remove_domain (int fam); - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_DOMAIN_H */ diff --git a/headers/private/net/sys/protosw.h b/headers/private/net/sys/protosw.h deleted file mode 100644 index 885038a5f3..0000000000 --- a/headers/private/net/sys/protosw.h +++ /dev/null @@ -1,156 +0,0 @@ -/* protosw.h */ - -#ifndef _SYS_PROTOSW_H -#define _SYS_PROTOSW_H - -#include /* for struct socket */ -#include - -#define PRCO_SETOPT 0 -#define PRCO_GETOPT 1 - -/* every protocol module init's one of these and passes it into - * the add_protocol() function, defined below */ -/* NB The pr_domain pointer will be filled in during the - * add_protocol() call - */ -struct protosw { - char *name; - char *mod_path; - uint16 pr_type; /* SOCK_xxx */ - struct domain *pr_domain; - uint16 pr_protocol; /* protocol number */ - uint16 pr_flags; /* flags, PR_xxx */ - int layer; /* which layer are we? */ - - /* the functions! */ - void (*pr_init)(void); - void (*pr_input)(struct mbuf*, int); - int (*pr_output)(struct mbuf *, struct mbuf *, - struct route *, - int, void *); - - int (*pr_userreq)(struct socket *, int, - struct mbuf *, - struct mbuf *, - struct mbuf *); - int (*pr_sysctl)(int *, uint, void *, size_t *, void *, size_t); - void (*pr_ctlinput)(int, struct sockaddr *, void *); - int (*pr_ctloutput)(int, struct socket*, int, int, struct mbuf **); - - struct protosw *pr_next; /* pointer to next proto structure */ - struct protosw *dom_next; /* next protosw pointed by the domain */ -}; - - -/* - * Values for pr_flags. - * PR_ADDR requires PR_ATOMIC; - * PR_ADDR and PR_CONNREQUIRED are mutually exclusive. - */ -#define PR_ATOMIC 0x01 /* exchange atomic messages only */ -#define PR_ADDR 0x02 /* addresses given with messages */ -#define PR_CONNREQUIRED 0x04 /* connection required by protocol */ -#define PR_WANTRCVD 0x08 /* want PRU_RCVD calls */ -#define PR_RIGHTS 0x10 /* passes capabilities */ -#define PR_ABRTACPTDIS 0x20 /* abort on accept(2) to disconnected - socket */ - -#define PR_SLOWHZ 2 /* 2 timeouts per second... */ -#define PR_FASTHZ 5 /* 5 timeouts per second */ -/* - * Defines for the userreq function req field are below. - * - * (*usrreq)(up, req, m, nam, opt); - * - * up is a (struct socket *) - * req is one of these requests, - * m is a optional mbuf chain containing a message, - * nam is an optional mbuf chain containing an address, - * opt is a pointer to a socketopt structure or nil. - * - * The protocol is responsible for disposal of the mbuf chain m, - * the caller is responsible for any space held by nam and opt. - * A non-zero return from usrreq gives an - * UNIX error number which should be passed to higher level software. - */ -#define PRU_ATTACH 0 /* attach protocol to up */ -#define PRU_DETACH 1 /* detach protocol from up */ -#define PRU_BIND 2 /* bind socket to address */ -#define PRU_LISTEN 3 /* listen for connection */ -#define PRU_CONNECT 4 /* establish connection to peer */ -#define PRU_ACCEPT 5 /* accept connection from peer */ -#define PRU_DISCONNECT 6 /* disconnect from peer */ -#define PRU_SHUTDOWN 7 /* won't send any more data */ -#define PRU_RCVD 8 /* have taken data; more room now */ -#define PRU_SEND 9 /* send this data */ -#define PRU_ABORT 10 /* abort (fast DISCONNECT, DETATCH) */ -#define PRU_CONTROL 11 /* control operations on protocol */ -#define PRU_SENSE 12 /* return status into m */ -#define PRU_RCVOOB 13 /* retrieve out of band data */ -#define PRU_SENDOOB 14 /* send out of band data */ -#define PRU_SOCKADDR 15 /* fetch socket's address */ -#define PRU_PEERADDR 16 /* fetch peer's address */ -#define PRU_CONNECT2 17 /* connect two sockets */ -/* begin for protocols internal use */ -#define PRU_FASTTIMO 18 /* 200ms timeout */ -#define PRU_SLOWTIMO 19 /* 500ms timeout */ -#define PRU_PROTORCV 20 /* receive from below */ -#define PRU_PROTOSEND 21 /* send to below */ -#define PRU_PEEREID 22 /* get local peer eid */ - -#define PRU_NREQ 22 - -/* - * The arguments to the ctlinput routine are - * (*protosw[].pr_ctlinput)(cmd, sa, arg); - * where cmd is one of the commands below, sa is a pointer to a sockaddr, - * and arg is an optional caddr_t argument used within a protocol family. - */ -#define PRC_IFDOWN 0 /* interface transition */ -#define PRC_ROUTEDEAD 1 /* select new route if possible ??? */ -#define PRC_MTUINC 2 /* increase in mtu to host */ -#define PRC_QUENCH2 3 /* DEC congestion bit says slow down */ -#define PRC_QUENCH 4 /* some one said to slow down */ -#define PRC_MSGSIZE 5 /* message size forced drop */ -#define PRC_HOSTDEAD 6 /* host appears to be down */ -#define PRC_HOSTUNREACH 7 /* deprecated (use PRC_UNREACH_HOST) */ -#define PRC_UNREACH_NET 8 /* no route to network */ -#define PRC_UNREACH_HOST 9 /* no route to host */ -#define PRC_UNREACH_PROTOCOL 10 /* dst says bad protocol */ -#define PRC_UNREACH_PORT 11 /* bad port # */ -/* was PRC_UNREACH_NEEDFRAG 12 (use PRC_MSGSIZE) */ -#define PRC_UNREACH_SRCFAIL 13 /* source route failed */ -#define PRC_REDIRECT_NET 14 /* net routing redirect */ -#define PRC_REDIRECT_HOST 15 /* host routing redirect */ -#define PRC_REDIRECT_TOSNET 16 /* redirect for type of service & net */ -#define PRC_REDIRECT_TOSHOST 17 /* redirect for tos & host */ -#define PRC_TIMXCEED_INTRANS 18 /* packet lifetime expired in transit */ -#define PRC_TIMXCEED_REASS 19 /* lifetime expired on reass q */ -#define PRC_PARAMPROB 20 /* header incorrect */ - -#define PRC_NCMDS 21 - -#define PRC_IS_REDIRECT(cmd) \ - ((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST) - - -/* Network stack defines... */ -// struct protosw *protocols; - -enum { - NET_LAYER1 = 1, - NET_LAYER2, - NET_LAYER3, - NET_LAYER4 - }; - -//XXX conflicts with src/add-ons/kernel/network/core/core.c:69 -// void add_protosw (struct protosw *prt[], int); -void add_protocol (struct protosw *, int); -void remove_protocol (struct protosw *); - -struct protosw *pffindproto(int domain, int protocol, int type); -struct protosw *pffindtype(int domain, int type); - -#endif /* _SYS_PROTOSW_H */ diff --git a/headers/private/net/sys/socketvar.h b/headers/private/net/sys/socketvar.h deleted file mode 100644 index 976c524310..0000000000 --- a/headers/private/net/sys/socketvar.h +++ /dev/null @@ -1,155 +0,0 @@ -/* socketvar.h */ - - -#ifndef _SYS_SOCKETVAR_H -#define _SYS_SOCKETVAR_H - -#include -#include -#include - -struct mbuf; - -struct sockbuf { - int32 sb_cc; /* actual chars in buffer */ - int32 sb_hiwat; /* max actual char count (high water mark) */ - int32 sb_mbcnt; /* chars of mbufs used */ - int32 sb_mbmax; /* max chars of mbufs to use */ - int32 sb_lowat; /* low water mark */ - struct mbuf *sb_mb; /* the mbuf chain */ - int16 sb_flags; /* flags, see below */ - int32 sb_timeo; /* timeout for read/write */ - sem_id sb_sleep; /* our sleep sem */ - sem_id sb_pop; /* sem to wait on... */ -}; - -#define SB_MAX (256*1024) /* default for max chars in sockbuf */ -#define SB_LOCK 0x01 /* lock on data queue */ -#define SB_WANT 0x02 /* someone is waiting to lock */ -#define SB_WAIT 0x04 /* someone is waiting for data/space */ -#define SB_SEL 0x08 /* someone is selecting */ -#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */ -#define SB_NOINTR 0x40 /* operations not interruptible */ -#define SB_KNOTE 0x80 /* kernel note attached */ -#define SB_NOTIFY (SB_WAIT|SB_SEL|SB_ASYNC) - -typedef void (*socket_event_callback)(void * socket, uint32 event, void * cookie); - -struct socket { - uint16 so_type; /* type of socket */ - uint16 so_options; /* socket options */ - int16 so_linger; /* dreaded linger value */ - int16 so_state; /* socket state */ - char *so_pcb; /* pointer to the control block */ - sem_id so_lock; /* socket lock */ - sem_id so_timeo; /* our wait channel */ - - struct protosw *so_proto; /* pointer to protocol module */ - - struct socket *so_head; - struct socket *so_q0; - struct socket *so_q; - - int16 so_q0len; - int16 so_qlen; - int16 so_qlimit; - int32 so_error; -// pid_t so_pgid; - uint32 so_oobmark; - - /* our send/recv buffers */ - struct sockbuf so_snd; - struct sockbuf so_rcv; - - // event callback - socket_event_callback event_callback; - void * event_callback_cookie; - int sel_ev; -}; - -/* Select event bit mask */ -#define SEL_READ 0x01 -#define SEL_WRITE 0x02 -#define SEL_EX 0x04 - -/* - * Socket state bits. - */ -#define SS_NOFDREF 0x001 /* no file table ref any more */ -#define SS_ISCONNECTED 0x002 /* socket connected to a peer */ -#define SS_ISCONNECTING 0x004 /* in process of connecting to peer */ -#define SS_ISDISCONNECTING 0x008 /* in process of disconnecting */ -#define SS_CANTSENDMORE 0x010 /* can't send more data to peer */ -#define SS_CANTRCVMORE 0x020 /* can't receive more data from peer */ -#define SS_RCVATMARK 0x040 /* at mark on input */ -#define SS_ISDISCONNECTED 0x800 /* socket disconnected from peer */ - -#define SS_PRIV 0x080 /* privileged for broadcast, raw... */ -#define SS_NBIO 0x100 /* non-blocking ops */ -#define SS_ASYNC 0x200 /* async i/o notify */ -#define SS_ISCONFIRMING 0x400 /* deciding to accept connection req */ -#define SS_CONNECTOUT 0x1000 /* connect, not accept, at this end */ - -/* helpful defines... */ - -/* adjust counters in sb reflecting freeing of m */ -#define sbfree(sb, m) { \ - (sb)->sb_cc -= (m)->m_len; \ - (sb)->sb_mbcnt -= MSIZE; \ - if ((m)->m_flags & M_EXT) \ - (sb)->sb_mbcnt -= (m)->m_ext.ext_size; \ -} - -#define sbspace(sb) \ - (abs(min((int)((sb)->sb_hiwat - (sb)->sb_cc), \ - (int)((sb)->sb_mbmax - (sb)->sb_mbcnt)))) - -/* do we have to send all at once on a socket? */ -#define sosendallatonce(so) \ - ((so)->so_proto->pr_flags & PR_ATOMIC) - -/* adjust counters in sb reflecting allocation of m */ -#define sballoc(sb, m) { \ - (sb)->sb_cc += (m)->m_len; \ - (sb)->sb_mbcnt += MSIZE; \ - if ((m)->m_flags & M_EXT) \ - (sb)->sb_mbcnt += (m)->m_ext.ext_size; \ -} - -#define soreadable(so) \ - ((so)->so_rcv.sb_cc >= (so)->so_rcv.sb_lowat || \ - ((so)->so_state & SS_CANTRCVMORE) || \ - (so)->so_qlen || (so)->so_error) - -#define sowriteable(so) \ - ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat) && \ - (((so)->so_state & SS_ISCONNECTED) || \ - (((so)->so_proto->pr_flags & PR_CONNREQUIRED) == 0) || \ - ((so)->so_state & SS_CANTSENDMORE) || (so)->so_error)) - -#define M_WAITOK 0x0000 -#define M_NOWAIT 0x0001 - -/* - * Set lock on sockbuf sb; sleep if lock is already held. - * Unless SB_NOINTR is set on sockbuf, sleep is interruptible. - * Returns error without lock if sleep is interrupted. - */ -#define sblock(sb, wf) ((sb)->sb_flags & SB_LOCK ? \ - (((wf) == M_WAITOK) ? sockbuf_lock(sb) : EWOULDBLOCK) : \ - ((sb)->sb_flags |= SB_LOCK), 0) - -/* release lock on sockbuf sb */ -#define sbunlock(sb) { \ - (sb)->sb_flags &= ~SB_LOCK; \ - if ((sb)->sb_flags & SB_WANT) { \ - (sb)->sb_flags &= ~SB_WANT; \ - wakeup((sb)->sb_sleep); \ - } \ -} - -#define sorwakeup(so) sowakeup((so), &(so)->so_rcv) -/* we don't handle upcall for sockets */ -#define sowwakeup(so) sowakeup((so), &(so)->so_snd) - -#endif /* _SYS_SOCKETVAR_H */ diff --git a/headers/private/net/sys/sockio.h b/headers/private/net/sys/sockio.h deleted file mode 100644 index e0516d493a..0000000000 --- a/headers/private/net/sys/sockio.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _SYS_SOCKIO_H -#define _SYS_SOCKIO_H - -#include - -/* Socket ioctl's. */ -#define SIOCSHIWAT _IOW('s', 0, int) /* set high watermark */ -#define SIOCGHIWAT _IOR('s', 1, int) /* get high watermark */ -#define SIOCSLOWAT _IOW('s', 2, int) /* set low watermark */ -#define SIOCGLOWAT _IOR('s', 3, int) /* get low watermark */ -#define SIOCATMARK _IOR('s', 7, int) /* at oob mark? */ - -#define SIOCADDRT _IOW('r', 10, struct ortentry) /* add route */ -#define SIOCDELRT _IOW('r', 11, struct ortentry) /* delete route */ - -#define SIOCSIFADDR _IOW('i', 12, struct ifreq) /* set ifnet address */ -#define OSIOCGIFADDR _IOWR('i', 13, struct ifreq) /* get ifnet address */ -#define SIOCGIFADDR _IOWR('i', 33, struct ifreq) /* get ifnet address */ -#define SIOCSIFDSTADDR _IOW('i', 14, struct ifreq) /* set p-p address */ -#define OSIOCGIFDSTADDR _IOWR('i', 15, struct ifreq) /* get p-p address */ -#define SIOCGIFDSTADDR _IOWR('i', 34, struct ifreq) /* get p-p address */ -#define SIOCSIFFLAGS _IOW('i', 16, struct ifreq) /* set ifnet flags */ -#define SIOCGIFFLAGS _IOWR('i', 17, struct ifreq) /* get ifnet flags */ -#define OSIOCGIFBRDADDR _IOWR('i', 18, struct ifreq) /* get broadcast addr */ -#define SIOCGIFBRDADDR _IOWR('i', 35, struct ifreq) /* get broadcast addr */ -#define SIOCSIFBRDADDR _IOW('i', 19, struct ifreq) /* set broadcast addr */ -#define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */ -#define SIOCGIFCONF _IOWR('i', 36, struct ifconf) /* get ifnet list */ -#define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */ -#define SIOCGIFNETMASK _IOWR('i', 37, struct ifreq) /* get net addr mask */ -#define SIOCSIFNETMASK _IOW('i', 22, struct ifreq) /* set net addr mask */ -#define SIOCGIFMETRIC _IOWR('i', 23, struct ifreq) /* get IF metric */ -#define SIOCSIFMETRIC _IOW('i', 24, struct ifreq) /* set IF metric */ -#define SIOCDIFADDR _IOW('i', 25, struct ifreq) /* delete IF addr */ -#define SIOCAIFADDR _IOW('i', 26, struct ifaliasreq)/* add/chg IF alias */ -#define SIOCGIFDATA _IOWR('i', 27, struct ifreq) /* get if_data */ - -#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet MTU */ -#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet MTU */ - -#define SIOCADDMULTI _IOW('i', 49, struct ifreq) /* add m'cast addr */ -#define SIOCDELMULTI _IOW('i', 50, struct ifreq) /* del m'cast addr */ - -#endif /* SYS_NET_IOCTL_H */ - diff --git a/headers/private/net/userland_ipc.h b/headers/private/net/userland_ipc.h deleted file mode 100644 index a6d147cd69..0000000000 --- a/headers/private/net/userland_ipc.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef USERLAND_IPC_H -#define USERLAND_IPC_H -/* userland_ipc - Communication between the network driver -** and the userland stack. -** -** Initial version by Axel Dörfler, axeld@pinc-software.de -** This file may be used under the terms of the OpenBeOS License. -*/ - - -#include -#include - -#include "net_stack_driver.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define NET_STACK_PORTNAME "net_server connection" - -enum { - NET_STACK_OPEN = NET_STACK_IOCTL_MAX, - NET_STACK_CLOSE, - NET_STACK_NEW_CONNECTION, -}; - -#define MAX_NET_AREAS 16 - -typedef struct { - area_id id; - uint8 *offset; -} net_area_info; - -typedef struct { - int32 op; -// int32 buffer; - uint8 *data; - int32 length; - int32 result; - net_area_info area[MAX_NET_AREAS]; -} net_command; - -#define CONNECTION_QUEUE_LENGTH 128 -#define CONNECTION_COMMAND_SIZE 2048 - -typedef struct { - port_id port; - area_id area; - thread_id socket_thread; - - sem_id commandSemaphore; // command queue - uint32 numCommands,bufferSize; -} net_connection; - - -extern status_t init_userland_ipc(void); -extern void shutdown_userland_ipc(void); - - -#ifdef __cplusplus -} // end of extern "C" -#endif - -#endif /* USERLAND_IPC_H */ diff --git a/src/add-ons/kernel/drivers/network/stack/Jamfile b/src/add-ons/kernel/drivers/network/stack/Jamfile index d911a10a93..98d2b95a67 100644 --- a/src/add-ons/kernel/drivers/network/stack/Jamfile +++ b/src/add-ons/kernel/drivers/network/stack/Jamfile @@ -14,41 +14,41 @@ UsePrivateHeaders net ; # a) Userland stack version: -KernelAddon net_server_driver : kernel drivers bin : - net_server_driver.c +KernelAddon userland_net_server : kernel drivers bin : + userland_server.cpp ; # b) Kernelland stack version: -KernelAddon net_stack_driver : kernel drivers bin : - net_stack_driver.c +KernelAddon net_stack : kernel drivers bin : + kernel_stack.cpp ; # Installation HaikuInstall install-networking : /boot/home/config/add-ons/kernel/drivers/bin : - net_server_driver - net_stack_driver + userland_net_server + net_stack ; HaikuInstallRelSymLink install-networking : /boot/home/config/add-ons/kernel/drivers/dev/net : - net_server_driver - net_stack_driver : + userland_net_server + net_stack : installed-symlink ; HaikuInstall install-userland-networking : /boot/home/config/add-ons/kernel/drivers/bin : - net_server_driver : + userland_net_server : installed-userland-networking ; HaikuInstallRelSymLink install-userland-networking : /boot/home/config/add-ons/kernel/drivers/dev/net : - net_server_driver : + userland_net_server : installed-userland-networking-symlink ; Package haiku-networkingkit-cvs : - net_stack_driver net_server_driver : + net_stack userland_net_server : boot home config add-ons kernel drivers bin ; -PackageDriverSymLink haiku-networkingkit-cvs : net net_stack_driver ; -PackageDriverSymLink haiku-networkingkit-cvs : net net_server_driver ; +PackageDriverSymLink haiku-networkingkit-cvs : net net_stack ; +PackageDriverSymLink haiku-networkingkit-cvs : net userland_net_server ; diff --git a/src/add-ons/kernel/drivers/network/stack/kernel_stack.cpp b/src/add-ons/kernel/drivers/network/stack/kernel_stack.cpp new file mode 100644 index 0000000000..2ba9e14ab4 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/stack/kernel_stack.cpp @@ -0,0 +1,778 @@ +/* + * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. + * This file may be used under the terms of the MIT License. + */ + +/*! + This file implements a very simple socket driver that is intended to + act as an interface to the networking stack. +*/ + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +// debugging macros +#define LOGID "net_stack_driver: " +#define ERROR(format, args...) dprintf(LOGID "ERROR: " format, ## args) +#define WARN(format, args...) dprintf(LOGID "WARNING: " format, ## args) + +#ifdef DEBUG +# define TRACE(format, args...) dprintf(format, ## args) +#else +# define TRACE(format, args...) +#endif + + +// Local definitions + +// this struct will store one select() event to monitor per thread +typedef struct selecter { + struct selecter *next; + thread_id thread; + uint32 event; + selectsync *sync; + uint32 ref; +} selecter; + +// the cookie we attach to each file descriptor opened on our driver entry +typedef struct net_stack_cookie { + net_socket *socket; // NULL before ioctl(fd, NET_STACK_SOCKET/_ACCEPT) + sem_id selecters_lock; // protect the selecters linked-list + selecter *selecters; // the select()'ers lists (thread-aware) +} net_stack_cookie; + +// TODO: disabled +/* To unload this driver execute + * $ echo unload > /dev/net/stack + * As soon as the last app stops using sockets the netstack will be unloaded. + */ +//static const char *kUnloadCommand = "unload"; + + +// prototypes of device hooks functions +static status_t net_stack_open(const char *name, uint32 flags, void **_cookie); +static status_t net_stack_close(void *cookie); +static status_t net_stack_free_cookie(void *cookie); +static status_t net_stack_control(void *cookie, uint32 op, void *data, size_t length); +static status_t net_stack_read(void *cookie, off_t pos, void *data, size_t *_length); +static status_t net_stack_write(void *cookie, off_t pos, const void *data, size_t *_length); +static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync); +static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync); +static status_t net_stack_readv(void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_length); +static status_t net_stack_writev(void *cookie, off_t pos, const iovec *vecs, size_t count, size_t *_length); + + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +static int32 sOpenCount = 0; +static struct net_socket_module_info *sSocket = NULL; + + +// #pragma mark - internal functions + + +template status_t +return_address(ArgType &args, void *data) +{ + sockaddr_storage *target; + + if (user_memcpy(&target, &((ArgType *)data)->address, sizeof(void *)) < B_OK + || user_memcpy(&((ArgType *)data)->address_length, &args.address_length, sizeof(socklen_t)) < B_OK + || user_memcpy(target, args.address, args.address_length) < B_OK) + return B_BAD_ADDRESS; + + return B_OK; +} + + +template status_t +check_args_and_address(ArgType &args, sockaddr_storage &address, void *data, size_t length, + bool copyAddress = true) +{ + if (data == NULL || length != sizeof(ArgType)) + return B_BAD_VALUE; + + if (user_memcpy(&args, data, sizeof(ArgType)) < B_OK) + return B_BAD_ADDRESS; + + if (args.address_length > sizeof(sockaddr_storage)) + return B_BAD_VALUE; + + if (copyAddress && user_memcpy(&address, args.address, args.address_length) < B_OK) + return B_BAD_ADDRESS; + + args.address = (sockaddr *)&address; + return B_OK; +} + + +template status_t +check_args(ArgType &args, void *data, size_t length) +{ + if (data == NULL || length != sizeof(ArgType)) + return B_BAD_VALUE; + + if (user_memcpy(&args, data, sizeof(ArgType)) < B_OK) + return B_BAD_ADDRESS; + + return B_OK; +} + + +#if 0 +static void +on_socket_event(void * socket, uint32 event, void *_cookie) +{ + net_stack_cookie *cookie = (net_stack_cookie *) _cookie; + selecter *s; + + if (!cookie) + return; + + if (cookie->socket != socket) { + ERROR("on_socket_event(%p, %ld, %p): socket is higly suspect! Aborting.\n", + socket, event, cookie); + return; + } + + TRACE("on_socket_event(%p, %ld, %p)\n", socket, event, cookie); + + // lock the selecters list + if (acquire_sem(cookie->selecters_lock) != B_OK) + return; + + s = cookie->selecters; + while (s) { + if (s->event == event) + // notify this selecter (thread/event pair) +#ifdef COMPILE_FOR_R5 + notify_select_event(s->sync, s->ref); +#else + notify_select_event(s->sync, s->ref, event); +#endif + + s = s->next; + } + + // unlock the selecters list + release_sem(cookie->selecters_lock); + return; +} +#endif + + +#ifdef DEBUG +static const char* +opcode_name(int op) +{ +#define C2N(op) { op, #op } + // op-code to name + struct commands_info { + int op; + const char *name; + } *ci, commands_info[] = { + C2N(NET_STACK_SOCKET), + C2N(NET_STACK_BIND), + C2N(NET_STACK_RECVFROM), + C2N(NET_STACK_RECV), + C2N(NET_STACK_SENDTO), + C2N(NET_STACK_SEND), + C2N(NET_STACK_LISTEN), + C2N(NET_STACK_ACCEPT), + C2N(NET_STACK_CONNECT), + C2N(NET_STACK_SHUTDOWN), + C2N(NET_STACK_GETSOCKOPT), + C2N(NET_STACK_SETSOCKOPT), + C2N(NET_STACK_GETSOCKNAME), + C2N(NET_STACK_GETPEERNAME), + C2N(NET_STACK_SYSCTL), + C2N(NET_STACK_SELECT), + C2N(NET_STACK_DESELECT), + C2N(NET_STACK_GET_COOKIE), + C2N(NET_STACK_NOTIFY_SOCKET_EVENT), + C2N(NET_STACK_CONTROL_NET_MODULE), + + // Userland IPC-specific opcodes + // C2N(NET_STACK_OPEN), + // C2N(NET_STACK_CLOSE), + // C2N(NET_STACK_NEW_CONNECTION), + + // Standard BeOS opcodes + C2N(B_SET_BLOCKING_IO), + C2N(B_SET_NONBLOCKING_IO), + + { 0, "Unknown!" } + }; +#undef C2N + + ci = commands_info; + while(ci && ci->op) { + if (ci->op == op) + return ci->name; + ci++; + } + + return "???"; +} +#endif // DEBUG + + +// #pragma mark - driver + + +/** Do we init ourselves? If we're in safe mode we'll decline so if things + * screw up we can boot and delete the broken driver! + * After my experiences earlier - a good idea! + */ + +status_t +init_hardware(void) +{ + void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); + if (settings != NULL) { + // we got a pointer, now get settings... + bool safemode = get_driver_boolean_parameter(settings, B_SAFEMODE_SAFE_MODE, false, false); + // now get rid of settings + unload_driver_settings(settings); + + if (safemode) { + WARN("init_hardware: declining offer to join the party.\n"); + return B_ERROR; + } + } + + TRACE("init_hardware done.\n"); + return B_OK; +} + + +status_t +init_driver(void) +{ + + return B_OK; +} + + +void +uninit_driver(void) +{ + TRACE("uninit_driver\n"); + + put_module(NET_SOCKET_MODULE_NAME); +} + + +const char ** +publish_devices(void) +{ + static const char *devices[] = { NET_STACK_DRIVER_DEV, NULL }; + + return devices; +} + + +device_hooks* +find_device(const char* device_name) +{ + static device_hooks hooks = { + net_stack_open, + net_stack_close, + net_stack_free_cookie, + net_stack_control, + net_stack_read, + net_stack_write, + net_stack_select, + net_stack_deselect, + net_stack_readv, + net_stack_writev, + }; + + return &hooks; +} + + +// #pragma mark - device + + +static status_t +net_stack_open(const char *name, uint32 flags, void **_cookie) +{ + if (atomic_add(&sOpenCount, 1) == 0) { + // When we're opened for the first time, we'll try to load the + // networking stack + status_t status = get_module(NET_SOCKET_MODULE_NAME, (module_info **)&sSocket); + if (status < B_OK) { + ERROR("Can't load " NET_SOCKET_MODULE_NAME " module: %ld\n", status); + return status; + } + } + + net_stack_cookie *cookie = (net_stack_cookie *)malloc(sizeof(net_stack_cookie)); + if (cookie == NULL) + return B_NO_MEMORY; + + memset(cookie, 0, sizeof(net_stack_cookie)); + cookie->socket = NULL; // the socket will be allocated in NET_STACK_SOCKET ioctl + cookie->selecters_lock = create_sem(1, "socket_selecters_lock"); + + // attach this new net_socket_cookie to file descriptor + *_cookie = cookie; + + TRACE("net_stack_open(%s, %s%s) return this cookie: %p\n", + name, + (((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" : + ((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"), + (flags & O_NONBLOCK) ? " O_NONBLOCK" : "", + cookie); + + return B_OK; +} + + +static status_t +net_stack_close(void *_cookie) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + + TRACE("net_stack_close(%p)\n", cookie); + + if (cookie->socket == NULL) + return B_OK; + + return sSocket->close(cookie->socket); +} + + +static status_t +net_stack_free_cookie(void *_cookie) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + selecter *s; + + TRACE("net_stack_free_cookie(%p)\n", cookie); + + // free the selecters list + delete_sem(cookie->selecters_lock); + s = cookie->selecters; + while (s) { + selecter *tmp = s; + s = s->next; + free(tmp); + } + + if (cookie->socket != NULL) + sSocket->free(cookie->socket); + + // free the cookie + free(cookie); + + if (atomic_add(&sOpenCount, -1) == 1) { + // the last reference to us has been removed, unload the networking + // stack again + put_module(NET_SOCKET_MODULE_NAME); + } + + return B_OK; +} + + +static status_t +net_stack_control(void *_cookie, uint32 op, void *data, size_t length) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + status_t status = B_BAD_VALUE; + + TRACE("net_stack_control(%p, %s (0x%lX), %p, %ld)\n", + _cookie, opcode_name(op), op, data, len); + + if (op < NET_STACK_IOCTL_BASE || op > NET_STACK_IOCTL_END) { + // we only accept networking ioctl()s to get into our stack + return B_BAD_VALUE; + } + + if (cookie->socket == NULL) { + switch (op) { + case NET_STACK_SOCKET: + { + socket_args args; + status = check_args(args, data, length); + if (status < B_OK) + return status; + + return sSocket->socket(args.family, args.type, args.protocol, &cookie->socket); + } + + case NET_STACK_GET_COOKIE: + // This is needed by accept() call, allowing libnet.so accept() to pass back + // in NET_STACK_ACCEPT opcode the cookie (aka the net_stack_cookie!) + // of the file descriptor to use for the new accepted socket + return user_memcpy(data, cookie, sizeof(void *)); + } + } else { + switch (op) { + case NET_STACK_CONNECT: + { + sockaddr_storage address; + sockaddr_args args; + status = check_args_and_address(args, address, data, length); + if (status < B_OK) + return status; + + return sSocket->connect(cookie->socket, args.address, args.address_length); + } + + case NET_STACK_BIND: + { + sockaddr_storage address; + sockaddr_args args; + status = check_args_and_address(args, address, data, length); + if (status < B_OK) + return status; + + return sSocket->bind(cookie->socket, args.address, args.address_length); + } + + case NET_STACK_LISTEN: + // backlog to set + return sSocket->listen(cookie->socket, (int)data); + + case NET_STACK_ACCEPT: + { + sockaddr_storage address; + accept_args args; + status = check_args_and_address(args, address, data, length, false); + if (status < B_OK) + return status; + + // args.cookie is the net_stack_cookie of the already opened socket + // TODO: find a safer way to do this! + + net_stack_cookie *acceptCookie = (net_stack_cookie *)args.cookie; + status = sSocket->accept(cookie->socket, args.address, + &args.address_length, &acceptCookie->socket); + if (status < B_OK) + return status; + + return return_address(args, data); + } + + case NET_STACK_SHUTDOWN: + return sSocket->shutdown(cookie->socket, (int)data); + + case NET_STACK_SEND: + { + transfer_args args; + status = check_args(args, data, length); + if (status < B_OK) + return status; + + return sSocket->send(cookie->socket, args.data, args.data_length, args.flags); + } + case NET_STACK_SENDTO: + { + sockaddr_storage address; + transfer_args args; + status = check_args_and_address(args, address, data, length); + if (status < B_OK) + return status; + + return sSocket->sendto(cookie->socket, args.data, args.data_length, + args.flags, args.address, args.address_length); + } + + case NET_STACK_RECV: + { + transfer_args args; + status = check_args(args, data, length); + if (status < B_OK) + return status; + + return sSocket->recv(cookie->socket, args.data, args.data_length, args.flags); + } + case NET_STACK_RECVFROM: + { + sockaddr_storage address; + transfer_args args; + status = check_args_and_address(args, address, data, length, false); + if (status < B_OK) + return status; + + ssize_t bytesRead = sSocket->recvfrom(cookie->socket, args.data, + args.data_length, args.flags, args.address, &args.address_length); + if (bytesRead < B_OK) + return bytesRead; + + status = return_address(args, data); + if (status < B_OK) + return status; + + return bytesRead; + } + + case NET_STACK_GETSOCKOPT: + { + sockopt_args args; + status = check_args(args, data, length); + if (status < B_OK) + return status; + + char valueBuffer[128]; + if (args.length > (int)sizeof(valueBuffer)) + args.length = (int)sizeof(valueBuffer); + + status = sSocket->getsockopt(cookie->socket, args.level, args.option, + valueBuffer, &args.length); + if (status < B_OK) + return status; + + if (user_memcpy(args.value, valueBuffer, args.length) < B_OK + || user_memcpy(&((sockopt_args *)data)->length, &args.length, sizeof(int)) < B_OK) + return B_BAD_ADDRESS; + + return B_OK; + } + + case NET_STACK_SETSOCKOPT: + { + sockopt_args args; + status = check_args(args, data, length); + if (status < B_OK) + return status; + + char valueBuffer[128]; + if (args.length > (int)sizeof(valueBuffer)) + return B_BAD_VALUE; + if (user_memcpy(valueBuffer, args.value, args.length) < B_OK) + return B_BAD_ADDRESS; + + return sSocket->setsockopt(cookie->socket, args.level, args.option, + valueBuffer, args.length); + } + + case NET_STACK_GETSOCKNAME: + { + sockaddr_storage address; + sockaddr_args args; + status = check_args_and_address(args, address, data, length, false); + if (status < B_OK) + return status; + + status = sSocket->getsockname(cookie->socket, args.address, + &args.address_length); + if (status < B_OK) + return status; + + return return_address(args, data); + } + + case NET_STACK_GETPEERNAME: + { + sockaddr_storage address; + sockaddr_args args; + status = check_args_and_address(args, address, data, length, false); + if (status < B_OK) + return status; + + status = sSocket->getpeername(cookie->socket, args.address, + &args.address_length); + if (status < B_OK) + return status; + + return return_address(args, data); + } + + case FIONBIO: + { + int value = (int)data; + return sSocket->setsockopt(cookie->socket, SOL_SOCKET, SO_NONBLOCK, + &value, sizeof(int)); + } + + case B_SET_BLOCKING_IO: + case B_SET_NONBLOCKING_IO: + { + int value = op == B_SET_NONBLOCKING_IO; + return sSocket->setsockopt(cookie->socket, SOL_SOCKET, SO_NONBLOCK, + &value, sizeof(int)); + } + + default: + return sSocket->control(cookie->socket, op, data, length); + } + } + + return status; +} + + +static status_t +net_stack_read(void *_cookie, off_t /*offset*/, void *buffer, size_t *_length) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + + TRACE("net_stack_read(%p, %p, %ld)\n", cookie, buffer, *_length); + + if (cookie->socket == NULL) + return B_BAD_VALUE; + + ssize_t bytesRead = sSocket->recv(cookie->socket, buffer, *_length, 0); + if (bytesRead < 0) { + *_length = 0; + return bytesRead; + } + + *_length = bytesRead; + return B_OK; +} + + +static status_t +net_stack_readv(void *_cookie, off_t /*offset*/, const struct iovec *vecs, + size_t count, size_t *_length) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + + TRACE("net_stack_readv(%p, (%p, %lu), %ld)\n", cookie, vecs, count, *_length); + + if (cookie->socket == NULL) + return B_BAD_VALUE; + + return sSocket->readv(cookie->socket, vecs, count, _length); +} + + +static status_t +net_stack_write(void *_cookie, off_t /*offset*/, const void *buffer, size_t *_length) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + + TRACE("net_stack_write(%p, %p, %ld)\n", cookie, buffer, *_length); + + if (cookie->socket == NULL) + return B_BAD_VALUE; + + ssize_t bytesWritten = sSocket->send(cookie->socket, buffer, *_length, 0); + if (bytesWritten < 0) { + *_length = 0; + return bytesWritten; + } + + *_length = bytesWritten; + return B_OK; +} + + +static status_t +net_stack_writev(void *_cookie, off_t /*offset*/, const struct iovec *vecs, + size_t count, size_t *_length) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + + TRACE("net_stack_writev(%p, (%p, %lu), %ld)\n", cookie, vecs, count, *_length); + + if (cookie->socket == NULL) + return B_BAD_VALUE; + + return sSocket->writev(cookie->socket, vecs, count, _length); +} + + +static status_t +net_stack_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + status_t status; + + TRACE("net_stack_select(%p, %d, %ld, %p)\n", cookie, event, ref, sync); + + if (cookie->socket == NULL) + return B_BAD_VALUE; + + selecter *s = (selecter *)malloc(sizeof(selecter)); + if (s == NULL) + return B_NO_MEMORY; + + s->thread = find_thread(NULL); + s->event = event; + s->sync = sync; + s->ref = ref; + + // lock the selecters list + status = acquire_sem(cookie->selecters_lock); + if (status != B_OK) { + free(s); + return status; + } + + // add it to selecters list + s->next = cookie->selecters; + cookie->selecters = s; + + // unlock the selecters list + release_sem(cookie->selecters_lock); + + // start (or continue) to monitor for socket event + // TODO: enable select() notification +// return sSocket->socket_set_event_callback(cookie->socket, on_socket_event, cookie, event); + return B_OK; +} + + +static status_t +net_stack_deselect(void *_cookie, uint8 event, selectsync *sync) +{ + net_stack_cookie *cookie = (net_stack_cookie *)_cookie; + + TRACE("net_stack_deselect(%p, %d, %p)\n", cookie, event, sync); + + if (!cookie || !cookie->socket) + return B_BAD_VALUE; + + // lock the selecters list + status_t status = acquire_sem(cookie->selecters_lock); + if (status != B_OK) + return status; + + thread_id currentThread = find_thread(NULL);; + selecter *previous = NULL; + selecter *s = cookie->selecters; + + while (s) { + if (s->thread == currentThread + && s->event == event && s->sync == sync) { + // selecter found! + break; + } + + previous = s; + s = s->next; + } + + if (s != NULL) { + // remove it from selecters list + if (previous) + previous->next = s->next; + else + cookie->selecters = s->next; + free(s); + } + + // TODO: enable deselect() + if (cookie->selecters == NULL) { + // selecters list is empty: no need to monitor socket events anymore + //sSocket->socket_set_event_callback(cookie->socket, NULL, NULL, event); + } + + // unlock the selecters list + return release_sem(cookie->selecters_lock); +} diff --git a/src/add-ons/kernel/drivers/network/stack/net_stack_driver.c b/src/add-ons/kernel/drivers/network/stack/net_stack_driver.c deleted file mode 100644 index 529db082ab..0000000000 --- a/src/add-ons/kernel/drivers/network/stack/net_stack_driver.c +++ /dev/null @@ -1,709 +0,0 @@ -/* net_stack_driver.c - * - * This file implements a very simple socket driver that is intended to - * act as an interface to the networking stack. - */ - -#ifndef _KERNEL_MODE - #error "This module MUST be built as a kernel driver!" -#endif - -// public/system includes -#include -#include - -#include -#include -#include -#include // for get_module()/put_module() - -#include - -// private includes -#include -#include -#include - - -// debugging macros -#define LOGID "net_stack_driver: " -#define ERROR(format, args...) dprintf(LOGID "ERROR: " format, ## args) -#define WARN(format, args...) dprintf(LOGID "WARNING: " format, ## args) -#ifdef DEBUG -#define TRACE(format, args...) dprintf(format, ## args) -#else -#define TRACE(format, args...) -#endif - - -// Local definitions - -// this struct will store one select() event to monitor per thread -typedef struct selecter { - struct selecter *next; - thread_id thread; - uint32 event; - selectsync *sync; - uint32 ref; -} selecter; - -// the cookie we attach to each file descriptor opened on our driver entry -typedef struct net_stack_cookie { - struct socket *socket; // NULL before ioctl(fd, NET_STACK_SOCKET/_ACCEPT) - uint32 open_flags; // the open() flags (mostly for storing O_NONBLOCK mode) - sem_id selecters_lock; // protect the selecters linked-list - selecter *selecters; // the select()'ers lists (thread-aware) -} net_stack_cookie; - -/* To unload this driver execute - * $ echo unload > /dev/net/stack - * As soon as the last app stops using sockets the netstack will be unloaded. - */ -static const char *kUnloadCommand = "unload"; - - -// prototypes of device hooks functions -static status_t net_stack_open(const char *name, uint32 flags, void **cookie); -static status_t net_stack_close(void *cookie); -static status_t net_stack_free_cookie(void *cookie); -static status_t net_stack_control(void *cookie, uint32 msg, void *data, size_t datalen); -static status_t net_stack_read(void *cookie, off_t pos, void *data, size_t *datalen); -static status_t net_stack_write(void *cookie, off_t pos, const void *data, size_t *datalen); -static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync); -static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync); -// static status_t net_stack_readv(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len); -// static status_t net_stack_writev(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len); - -// privates prototypes -static void on_socket_event(void *socket, uint32 event, void *cookie); - -static status_t keep_driver_loaded(); -static status_t unload_driver(); - -static const char *opcode_name(int op); - -/* - * Global variables - * ---------------- - */ - -static const char *sDevices[] = { NET_STACK_DRIVER_DEV, NULL }; - -static device_hooks sDeviceHooks = -{ - net_stack_open, /* -> open entry point */ - net_stack_close, /* -> close entry point */ - net_stack_free_cookie, /* -> free entry point */ - net_stack_control, /* -> control entry point */ - net_stack_read, /* -> read entry point */ - net_stack_write, /* -> write entry point */ - net_stack_select, /* -> select entry point */ - net_stack_deselect, /* -> deselect entry point */ - NULL, /* -> readv entry pint */ - NULL /* ->writev entry point */ -}; - -static struct core_module_info *sCore = NULL; - -static int sStayLoadedFD = -1; - - -// internal functions -static status_t -keep_driver_loaded() -{ - if (sStayLoadedFD != -1) - return B_OK; - - /* force the driver to stay loaded by opening himself */ - TRACE("keep_driver_loaded: opening " NET_STACK_DRIVER_PATH " to stay loaded...\n"); - - sStayLoadedFD = open(NET_STACK_DRIVER_PATH, 0); - - if (sStayLoadedFD < 0) - ERROR("keep_driver_loaded: couldn't open(" NET_STACK_DRIVER_PATH ")!\n"); - - return B_OK; -} - - -static status_t -unload_driver() -{ - if (sStayLoadedFD >= 0) { - int tmp_fd; - - /* we need to set sStayLoadedFD to < 0 if we don't want - * the next close enter again in this case, and so on... - */ - TRACE("unload_driver: unload requested.\n"); - - tmp_fd = sStayLoadedFD; - sStayLoadedFD = -1; - - close(tmp_fd); - } - - return B_OK; -} - - -/* - * Driver API calls - * ---------------- - */ - -_EXPORT int32 api_version = B_CUR_DRIVER_API_VERSION; - - - -/* Do we init ourselves? If we're in safe mode we'll decline so if things - * screw up we can boot and delete the broken driver! - * After my experiences earlier - a good idea! - * - * Also we'll turn on the serial debugger to aid in our debugging - * experience. - */ -_EXPORT status_t -init_hardware(void) -{ - bool safemode = false; - void *sfmptr; - - // get a pointer to the driver settings... - sfmptr = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); - - // only use the pointer if it's valid - if (sfmptr != NULL) { - // we got a pointer, now get settings... - safemode = get_driver_boolean_parameter(sfmptr, B_SAFEMODE_SAFE_MODE, false, false); - // now get rid of settings - unload_driver_settings(sfmptr); - } - - if (safemode) { - WARN("init_hardware: declining offer to join the party.\n"); - return B_ERROR; - } - - TRACE("init_hardware done.\n"); - - return B_OK; -} - - -/* init_driver() - * called every time we're loaded. - */ -_EXPORT status_t -init_driver(void) -{ - // only get the core module if we don't have it loaded already - if (!sCore) { - int rv = 0; - rv = get_module(NET_CORE_MODULE_NAME, (module_info **) &sCore); - if (rv < 0) { - ERROR("init_driver: Can't load " NET_CORE_MODULE_NAME " module: %d\n", rv); - return rv; - } - - TRACE("init_driver: built %s %s, core = %p\n", __DATE__, __TIME__, sCore); - - // start the network stack - sCore->start(); - } - - keep_driver_loaded(); - - return B_OK; -} - - -/* uninit_driver() - * called every time the driver is unloaded - */ -_EXPORT void -uninit_driver(void) -{ - TRACE("uninit_driver\n"); - - if (sCore) { - // shutdown the network stack - sCore->stop(); - - put_module(NET_CORE_MODULE_NAME); - sCore = NULL; - } -} - - -/* publish_devices() - * called to publish our device. - */ -_EXPORT const char** -publish_devices() -{ - return sDevices; -} - - -_EXPORT device_hooks* -find_device(const char* device_name) -{ - return &sDeviceHooks; -} - - -/* - * Device hooks - * ------------ - */ - -// the network stack functions - mainly just pass throughs... -static status_t -net_stack_open(const char *name, uint32 flags, void **cookie) -{ - net_stack_cookie *nsc; - - nsc = (net_stack_cookie *) malloc(sizeof(*nsc)); - if (!nsc) - return B_NO_MEMORY; - - memset(nsc, 0, sizeof(*nsc)); - nsc->socket = NULL; // the socket will be allocated in NET_STACK_SOCKET ioctl - nsc->open_flags = flags; - nsc->selecters_lock = create_sem(1, "socket_selecters_lock"); - nsc->selecters = NULL; - - // attach this new net_socket_cookie to file descriptor - *cookie = nsc; - - TRACE("net_stack_open(%s, %s%s) return this cookie: %p\n", - name, - (((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" : - ((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"), - (flags & O_NONBLOCK) ? " O_NONBLOCK" : "", - *cookie); - - return B_OK; -} - - -static status_t -net_stack_close(void *cookie) -{ - net_stack_cookie *nsc = cookie; - int rv; - - TRACE("net_stack_close(%p)\n", nsc); - - rv = B_ERROR; - if (nsc->socket) { - // if a socket was opened on this fd, close it now. - rv = sCore->socket_close(nsc->socket); - nsc->socket = NULL; - } - - return rv; -} - - -static status_t -net_stack_free_cookie(void *cookie) -{ - net_stack_cookie *nsc = cookie; - selecter *s; - - TRACE("net_stack_free_cookie(%p)\n", cookie); - - // free the selecters list - delete_sem(nsc->selecters_lock); - s = nsc->selecters; - while (s) { - selecter *tmp = s; - s = s->next; - free(tmp); - } - - // free the cookie - free(cookie); - return B_OK; -} - - -static status_t -net_stack_control(void *cookie, uint32 op, void *data, size_t len) -{ - net_stack_cookie *nsc = cookie; - struct stack_driver_args *args = data; - int err = B_BAD_VALUE; - - TRACE("net_stack_control(%p, %s (0x%lX), %p, %ld)\n", - cookie, opcode_name(op), op, data, len); - - if (!nsc->socket) { - switch (op) { - case NET_STACK_SOCKET: { - // okay, now try to open a real socket behind this fd/net_stack_cookie pair - err = sCore->socket_init(&nsc->socket); - if (err == 0) - err = sCore->socket_create(nsc->socket, args->u.socket.family, - args->u.socket.type, args->u.socket.proto); - - // TODO: handle some more open_flags - if(nsc->open_flags & O_NONBLOCK) { - int on = true; - return sCore->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &on); - } - return err; - } - case NET_STACK_GET_COOKIE: { - /* this is needed by accept() call, allowing libnet.so accept() to pass back - * in NET_STACK_ACCEPT opcode the cookie (aka the net_stack_cookie!) - * of the filedescriptor to use for the new accepted socket - */ - - *((void **) data) = cookie; - return B_OK; - } - case NET_STACK_CONTROL_NET_MODULE: { - return sCore->control_net_module(args->u.control.name, - args->u.control.op, args->u.control.data, args->u.control.length); - } - case NET_STACK_SYSCTL: - return sCore->net_sysctl(args->u.sysctl.name, args->u.sysctl.namelen, - args->u.sysctl.oldp, args->u.sysctl.oldlenp, - args->u.sysctl.newp, args->u.sysctl.newlen); - } - } else { - switch (op) { - case NET_STACK_CONNECT: - return sCore->socket_connect(nsc->socket, - (caddr_t) args->u.sockaddr.addr, args->u.sockaddr.addrlen); - - case NET_STACK_SHUTDOWN: - return sCore->socket_shutdown(nsc->socket, args->u.integer); - - case NET_STACK_BIND: - return sCore->socket_bind(nsc->socket, (caddr_t) args->u.sockaddr.addr, - args->u.sockaddr.addrlen); - - case NET_STACK_LISTEN: - // backlog to set - return sCore->socket_listen(nsc->socket, args->u.integer); - - case NET_STACK_ACCEPT: { - /* args->u.accept.cookie == net_stack_cookie of the already opened fd - * in libnet.so accept() call to bind to newly accepted socket - */ - - net_stack_cookie *ansc = args->u.accept.cookie; - return sCore->socket_accept(nsc->socket, &ansc->socket, - (void *)args->u.accept.addr, &args->u.accept.addrlen); - } - case NET_STACK_SEND: - // TODO: flags gets ignored here... - return net_stack_write(cookie, 0, args->u.transfer.data, - &args->u.transfer.datalen); - - case NET_STACK_RECV: - // TODO: flags gets ignored here... - return net_stack_read(cookie, 0, args->u.transfer.data, - &args->u.transfer.datalen); - - case NET_STACK_RECVFROM: { - struct msghdr * mh = (struct msghdr *) data; - int retsize; - - err = sCore->socket_recv(nsc->socket, mh, (caddr_t)&mh->msg_namelen, - &retsize); - if (err == 0) - return retsize; - return err; - } - case NET_STACK_SENDTO: { - struct msghdr * mh = (struct msghdr *) data; - int retsize; - - err = sCore->socket_send(nsc->socket, mh, mh->msg_flags, &retsize); - if (err == 0) - return retsize; - return err; - } - case NET_STACK_GETSOCKOPT: - return sCore->socket_getsockopt(nsc->socket, args->u.sockopt.level, - args->u.sockopt.option, args->u.sockopt.optval, - (size_t *) &args->u.sockopt.optlen); - - case NET_STACK_SETSOCKOPT: - return sCore->socket_setsockopt(nsc->socket, args->u.sockopt.level, - args->u.sockopt.option, (const void *) args->u.sockopt.optval, - args->u.sockopt.optlen); - - case NET_STACK_GETSOCKNAME: - return sCore->socket_getsockname(nsc->socket, args->u.sockaddr.addr, - &args->u.sockaddr.addrlen); - - case NET_STACK_GETPEERNAME: - return sCore->socket_getpeername(nsc->socket, args->u.sockaddr.addr, - &args->u.sockaddr.addrlen); - - case NET_STACK_SOCKETPAIR: { - net_stack_cookie *ansc = args->u.socketpair.cookie; - return sCore->socket_socketpair(nsc->socket, &ansc->socket); - } - case B_SET_BLOCKING_IO: { - int off = false; - nsc->open_flags &= ~O_NONBLOCK; - return sCore->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &off); - } - - case B_SET_NONBLOCKING_IO: { - int on = true; - nsc->open_flags |= O_NONBLOCK; - return sCore->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &on); - } - - default: - return sCore->socket_ioctl(nsc->socket, op, data); - } - } - - return err; -} - - -static status_t -net_stack_read(void *cookie, off_t position, void *buffer, size_t *readlen) -{ - net_stack_cookie *nsc = (net_stack_cookie *) cookie; - struct iovec iov; - int error; - int flags = 0; - - TRACE("net_stack_read(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *readlen); - - if (!nsc->socket) - return B_BAD_VALUE; - - iov.iov_base = buffer; - iov.iov_len = *readlen; - - error = sCore->socket_readv(nsc->socket, &iov, &flags); - *readlen = error; - return error; -} - - -static status_t -net_stack_write(void *cookie, off_t position, const void *buffer, size_t *writelen) -{ - net_stack_cookie *nsc = (net_stack_cookie *) cookie; - struct iovec iov; - int error; - int flags = 0; - - TRACE("net_stack_write(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *writelen); - - if (! nsc->socket) { - if (*writelen >= strlen(kUnloadCommand) - && strncmp(buffer, kUnloadCommand, strlen(kUnloadCommand)) == 0) - return unload_driver(); - // we are told to unload this driver - - return B_BAD_VALUE; - } - - iov.iov_base = (void*) buffer; - iov.iov_len = *writelen; - - error = sCore->socket_writev(nsc->socket, &iov, flags); - *writelen = error; - return error; -} - - -static status_t -net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) -{ - net_stack_cookie * nsc = (net_stack_cookie *) cookie; - selecter *s; - status_t status; - - TRACE("net_stack_select(%p, %d, %ld, %p)\n", cookie, event, ref, sync); - - if (!nsc->socket) - return B_BAD_VALUE; - - s = (selecter *) malloc(sizeof(selecter)); - if (! s) - return B_NO_MEMORY; - - s->thread = find_thread(NULL); // current thread id - s->event = event; - s->sync = sync; - s->ref = ref; - - // lock the selecters list - status = acquire_sem(nsc->selecters_lock); - if (status != B_OK) { - free(s); - return status; - } - - // add it to selecters list - s->next = nsc->selecters; - nsc->selecters = s; - - // unlock the selecters list - release_sem(nsc->selecters_lock); - - // start (or continue) to monitor for socket event - return sCore->socket_set_event_callback(nsc->socket, on_socket_event, nsc, event); -} - - -static status_t -net_stack_deselect(void *cookie, uint8 event, selectsync *sync) -{ - net_stack_cookie *nsc = (net_stack_cookie *) cookie; - selecter *previous; - selecter *s; - thread_id current_thread; - status_t status; - - TRACE("net_stack_deselect(%p, %d, %p)\n", cookie, event, sync); - - if (!nsc || !nsc->socket) - return B_BAD_VALUE; - - current_thread = find_thread(NULL); - - // lock the selecters list - status = acquire_sem(nsc->selecters_lock); - if (status != B_OK) - return status; - - previous = NULL; - s = nsc->selecters; - while (s) { - if (s->thread == current_thread && - s->event == event && s->sync == sync) - // selecter found! - break; - - previous = s; - s = s->next; - } - - if (s != NULL) { - // remove it from selecters list - if (previous) - previous->next = s->next; - else - nsc->selecters = s->next; - free(s); - } - - if (nsc->selecters == NULL) - // selecters list is empty: no need to monitor socket events anymore - sCore->socket_set_event_callback(nsc->socket, NULL, NULL, event); - - // unlock the selecters list - return release_sem(nsc->selecters_lock); -} - - -static void -on_socket_event(void * socket, uint32 event, void *cookie) -{ - net_stack_cookie *nsc = (net_stack_cookie *) cookie; - selecter *s; - - if (!nsc) - return; - - if (nsc->socket != socket) { - ERROR("on_socket_event(%p, %ld, %p): socket is higly suspect! Aborting.\n", - socket, event, cookie); - return; - } - - TRACE("on_socket_event(%p, %ld, %p)\n", socket, event, cookie); - - // lock the selecters list - if (acquire_sem(nsc->selecters_lock) != B_OK) - return; - - s = nsc->selecters; - while (s) { - if (s->event == event) - // notify this selecter (thread/event pair) -#ifdef COMPILE_FOR_R5 - notify_select_event(s->sync, s->ref); -#else - notify_select_event(s->sync, s->ref, event); -#endif - - s = s->next; - } - - // unlock the selecters list - release_sem(nsc->selecters_lock); - return; -} - - -static const char* -opcode_name(int op) -{ -#define C2N(op) { op, #op } - // op-code to name - struct commands_info { - int op; - const char *name; - } *ci, commands_info[] = { - C2N(NET_STACK_SOCKET), - C2N(NET_STACK_BIND), - C2N(NET_STACK_RECVFROM), - C2N(NET_STACK_RECV), - C2N(NET_STACK_SENDTO), - C2N(NET_STACK_SEND), - C2N(NET_STACK_LISTEN), - C2N(NET_STACK_ACCEPT), - C2N(NET_STACK_CONNECT), - C2N(NET_STACK_SHUTDOWN), - C2N(NET_STACK_GETSOCKOPT), - C2N(NET_STACK_SETSOCKOPT), - C2N(NET_STACK_GETSOCKNAME), - C2N(NET_STACK_GETPEERNAME), - C2N(NET_STACK_SYSCTL), - C2N(NET_STACK_SELECT), - C2N(NET_STACK_DESELECT), - C2N(NET_STACK_GET_COOKIE), - C2N(NET_STACK_NOTIFY_SOCKET_EVENT), - C2N(NET_STACK_CONTROL_NET_MODULE), - - // Userland IPC-specific opcodes - // C2N(NET_STACK_OPEN), - // C2N(NET_STACK_CLOSE), - // C2N(NET_STACK_NEW_CONNECTION), - - // Standard BeOS opcodes - C2N(B_SET_BLOCKING_IO), - C2N(B_SET_NONBLOCKING_IO), - - { 0, "Unknown!" } - }; - -#undef C2N - - ci = commands_info; - while(ci && ci->op) { - if (ci->op == op) - return ci->name; - ci++; - } - - return "???"; -} diff --git a/src/add-ons/kernel/drivers/network/stack/net_server_driver.c b/src/add-ons/kernel/drivers/network/stack/userland_server.cpp similarity index 85% rename from src/add-ons/kernel/drivers/network/stack/net_server_driver.c rename to src/add-ons/kernel/drivers/network/stack/userland_server.cpp index 5eb1cab793..0b9b0443e5 100644 --- a/src/add-ons/kernel/drivers/network/stack/net_server_driver.c +++ b/src/add-ons/kernel/drivers/network/stack/userland_server.cpp @@ -1,39 +1,35 @@ -/* net_server_driver - This file implements a very simple socket driver -** that is intended to act as an interface to the networking stack when -** it is loaded in userland, hosted by a net_server-like app. -** The communication is slow, and could probably be much better, but it's -** working, and that should be enough for now. -** -** Initial version by Axel Dörfler, axeld@pinc-software.de -** This file may be used under the terms of the OpenBeOS License. +/* + * Copyright 2002-2006, Haiku, Inc. All Rights Reserved. + * This file may be used under the terms of the MIT License. + */ + +/*! + This file implements a very simple socket driver + that is intended to act as an interface to the networking stack when + it is loaded in userland, hosted by a net_server-like app. + The communication is slow, and could probably be much better, but it's + working, and that should be enough for now. */ #ifndef _KERNEL_MODE +# error "This module MUST be built as a kernel driver!" +#endif -#error "This module MUST be built as a kernel driver!" - -#else - -// Public includes -#include -#include - -#include -#include -#include - -#include - -// Private includes #include #include #include -//*****************************************************/ -// Debug output -//*****************************************************/ +#include +#include +#include -#define DEBUG_PREFIX "net_server_driver: " +#include + +#include +#include + + +#define DEBUG_PREFIX "userland_net_server: " #define __out dprintf #define DEBUG 1 @@ -59,14 +55,7 @@ #define D(x) ; #endif - -//*****************************************************/ -// Structure definitions -//*****************************************************/ - -#ifndef DRIVER_NAME -# define DRIVER_NAME "net_server_driver" -#endif +#define NET_SERVER_DRIVER_DEV "net/userland_server" /* wait one second when waiting on the stack */ #define STACK_TIMEOUT 1000000LL @@ -104,11 +93,6 @@ typedef struct { selecter * selecters; // the select()'ers lists (thread-aware) } net_server_cookie; - -//*****************************************************/ -// Prototypes -//*****************************************************/ - /* device hooks */ static status_t net_server_open(const char *name, uint32 flags, void **cookie); static status_t net_server_close(void *cookie); @@ -118,8 +102,6 @@ static status_t net_server_read(void *cookie, off_t pos, void *data, size_t *dat static status_t net_server_write(void *cookie, off_t pos, const void *data, size_t *datalen); static status_t net_server_select(void *cookie, uint8 event, uint32 ref, selectsync *sync); static status_t net_server_deselect(void *cookie, uint8 event, selectsync *sync); -// static status_t net_server_readv(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len); -// static status_t net_server_writev(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len); /* select() support */ static int32 socket_event_listener(void *data); @@ -132,62 +114,33 @@ static void shutdown_connection(net_server_cookie *nsc); static net_command *get_command(net_server_cookie *nsc, int32 *index); static status_t execute_command(net_server_cookie *nsc, uint32 op, void *data, uint32 length); -/* - * Global variables - * ---------------- - */ -#define NET_SERVER_DRIVER_DEV "net/server" -#define NET_SERVER_DRIVER_PATH "/dev/" ## NET_SERVER_DRIVER_DEV - -const char * g_device_names_list[] = { - "net/server", - NULL -}; - -device_hooks g_net_server_driver_hooks = -{ - net_server_open, /* -> open entry point */ - net_server_close, /* -> close entry point */ - net_server_free_cookie, /* -> free entry point */ - net_server_control, /* -> control entry point */ - net_server_read, /* -> read entry point */ - net_server_write, /* -> write entry point */ - net_server_select, /* -> select entry point */ - net_server_deselect, /* -> deselect entry point */ - NULL, /* -> readv entry pint */ - NULL /* -> writev entry point */ -}; +int32 api_version = B_CUR_DRIVER_API_VERSION; // by default, assert we can use kernel select() support notify_select_event_function g_nse = notify_select_event; -thread_id g_socket_event_listener_thread = -1; -port_id g_socket_event_listener_port = -1; +thread_id sSocketEventThread = -1; +port_id sSocketEventPort = -1; -port_id g_stack_port = -1; +static port_id sUserlandPort = -1; -/* - * Driver API calls - * ---------------- - */ - -_EXPORT int32 api_version = B_CUR_DRIVER_API_VERSION; +// #pragma mark - driver -_EXPORT status_t +status_t init_hardware(void) { return B_OK; } -_EXPORT status_t -init_driver (void) +status_t +init_driver(void) { thread_id thread; port_id port; - + FUNCTION(); port = create_port(32, "socket_event_listener"); @@ -200,40 +153,58 @@ init_driver (void) if (thread < B_OK) { delete_port(port); return thread; - }; - - g_socket_event_listener_thread = thread; - g_socket_event_listener_port = port; - + } + + sSocketEventThread = thread; + sSocketEventPort = port; + return resume_thread(thread); } -_EXPORT void -uninit_driver (void) +void +uninit_driver(void) { - status_t dummy; - FUNCTION(); - delete_port(g_socket_event_listener_port); - wait_for_thread(g_socket_event_listener_thread, &dummy); + delete_port(sSocketEventPort); + + status_t dummy; + wait_for_thread(sSocketEventThread, &dummy); } -_EXPORT const char ** -publish_devices() +const char ** +publish_devices(void) { FUNCTION(); - return g_device_names_list; + static const char *deviceNames[] = { + "net/userland_server", + NULL + }; + + return deviceNames; } -_EXPORT device_hooks * +device_hooks * find_device(const char *deviceName) { FUNCTION(); - return &g_net_server_driver_hooks; + device_hooks hooks = { + net_server_open, + net_server_close, + net_server_free_cookie, + net_server_control, + net_server_read, + net_server_write, + net_server_select, + net_server_deselect, + NULL, + NULL + }; + + return &hooks; } @@ -393,7 +364,7 @@ net_server_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) // Tell the net_server to notify event(s) for this socket memset(&args, 0, sizeof(args)); - args.notify_port = g_socket_event_listener_port; + args.notify_port = sSocketEventPort; args.cookie = cookie;; return execute_command(nsc, NET_STACK_NOTIFY_SOCKET_EVENT, &args, sizeof(args)); @@ -484,7 +455,7 @@ static int32 socket_event_listener(void *data) ssize_t bytes; while(true) { - bytes = read_port(g_socket_event_listener_port, &msg, &sed, sizeof(sed)); + bytes = read_port(sSocketEventPort, &msg, &sed, sizeof(sed)); if (bytes < B_OK) return bytes; @@ -775,11 +746,11 @@ init_connection(void **cookie) } set_port_owner(nsc->local_port, B_SYSTEM_TEAM); - bytes = write_port(g_stack_port, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id)); + bytes = write_port(sUserlandPort, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id)); if (bytes == B_BAD_PORT_ID) { - g_stack_port = find_port(NET_STACK_PORTNAME); - PRINT(("try to get net_server's port id: %ld\n", g_stack_port)); - bytes = write_port(g_stack_port, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id)); + sUserlandPort = find_port(NET_STACK_PORTNAME); + PRINT(("try to get net_server's port id: %ld\n", sUserlandPort)); + bytes = write_port(sUserlandPort, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id)); } if (bytes < B_OK) { FATAL(("open: couldn't contact stack: %s\n",strerror(bytes))); @@ -861,5 +832,3 @@ shutdown_connection(net_server_cookie *nsc) free(nsc); } -#endif // #ifndef _KERNEL_MODE - diff --git a/src/add-ons/kernel/network/Jamfile b/src/add-ons/kernel/network/Jamfile index 1e78038b17..25e6f30907 100644 --- a/src/add-ons/kernel/network/Jamfile +++ b/src/add-ons/kernel/network/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src add-ons kernel network ; -SubInclude HAIKU_TOP src add-ons kernel network core ; -SubInclude HAIKU_TOP src add-ons kernel network interfaces ; +SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ; +SubInclude HAIKU_TOP src add-ons kernel network devices ; SubInclude HAIKU_TOP src add-ons kernel network protocols ; -SubInclude HAIKU_TOP src add-ons kernel network ppp ; +SubInclude HAIKU_TOP src add-ons kernel network stack ; diff --git a/src/add-ons/kernel/network/core/Jamfile b/src/add-ons/kernel/network/core/Jamfile deleted file mode 100644 index 39e2c0b07c..0000000000 --- a/src/add-ons/kernel/network/core/Jamfile +++ /dev/null @@ -1,40 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network core ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FStandardOSHeaders ] : true ; - # Needed for and maybe other stuff. - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - - -UsePrivateHeaders net ; - -KernelAddon core : kernel obos_network : - cksum.c - core.c - if.c - ifq.c - in.c - inpcb.c - mbuf.c - misc.c - net_timer.c - nhash.c - pools.c - radix.c - route.c - sockbuf.c - socket.c -; - -# Installation -HaikuInstall install-networking : /boot/home/config/add-ons/kernel/obos_network - : core ; - -Package haiku-networkingkit-cvs : - core : - boot home config add-ons kernel obos_network ; diff --git a/src/add-ons/kernel/network/core/cksum.c b/src/add-ons/kernel/network/core/cksum.c deleted file mode 100644 index f121ac87c6..0000000000 --- a/src/add-ons/kernel/network/core/cksum.c +++ /dev/null @@ -1,123 +0,0 @@ -#include - -#ifdef _KERNEL_MODE - #include - #define printf dprintf -#endif - -#include -#include - -/* This from Stevens Vol.2 */ -#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) -#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1];ADDCARRY(sum);} - -uint16 in_cksum(struct mbuf *m, int len, int off) -{ - uint16 *w; - int sum = 0; - int mlen = 0; - int byte_swapped = 0; - struct mbuf *orig_m = m; - - union { - uint8 c[2]; - uint16 s; - } s_util; - union { - uint16 s[2]; - uint32 l; - } l_util; - - if (off) { - m->m_len -= off; - m->m_data += off; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len -= off; - } - - for (; m && len; m=m->m_next) { - if (m->m_len == 0) - continue; - w = mtod(m, uint16 *); - if (mlen == -1) { - /* first byte is a continuation of - * a 16 bit word spanning this mbuf - * and the previous one. - * - * s_util.c[0] is already saved. - */ - s_util.c[1] = *(char*)w; - sum += s_util.s; - w = (uint16*) ((char*) w + 1); - mlen = m->m_len - 1; - len--; - } else - mlen = m->m_len; - if (len < mlen) - mlen = len; - len -= mlen; - /* force to even boundry */ - if ((1 & (int)w) && (mlen > 0)) { - REDUCE; - sum <<= 8; - s_util.c[0] = *(char*)w; - w = (uint16*)((char*)w + 1); - mlen--; - byte_swapped = 1; - } - /* unroll the loop to make overhead from branches - * &c small. - */ - while ((mlen -= 32) >= 0) { - sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; - sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; - sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; - sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; - - w += 16; - } - mlen += 32; - while ((mlen -= 8) >= 0) { - sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; - - w += 4; - } - mlen += 8; - if (mlen == 0 && byte_swapped == 0) - continue; - REDUCE; - while ((mlen -= 2) >= 0) { - sum += *w++; - } - if (byte_swapped) { - REDUCE; - sum <<= 8; - byte_swapped = 0; - if (mlen == -1) { - s_util.c[1] = *(char*)w; - sum += s_util.s; - mlen = 0; - } else - mlen = -1; - } else if (mlen == -1) - s_util.c[0] = *(char*)w; - } - if (len) - printf("cksum: out of data!\n"); - if (mlen == -1) { - /* last mbuf was an odd number of bytes! */ - s_util.c[1] = 0; - sum += s_util.s; - } - REDUCE; - - if (off) { - orig_m->m_len += off; - orig_m->m_data -= off; - if (orig_m->m_flags & M_PKTHDR) - orig_m->m_pkthdr.len += off; - } - return (uint16)(~sum & 0xffff); -} - diff --git a/src/add-ons/kernel/network/core/core.c b/src/add-ons/kernel/network/core/core.c deleted file mode 100644 index 5c7cd547b2..0000000000 --- a/src/add-ons/kernel/network/core/core.c +++ /dev/null @@ -1,1117 +0,0 @@ -/* core.c */ - -/* This the heart of network stack - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "core_private.h" -#include "core_module.h" -#include "sys/socket.h" -#include "sys/socketvar.h" -#include "net/if.h" /* for ifnet definition */ -#include "protocols.h" -#include "net_module.h" -#include "net_timer.h" -#include "net_misc.h" -#include "nhash.h" -#include "netinet/in_var.h" -#include "netinet/in_pcb.h" -#include "sys/domain.h" -#include "sys/protosw.h" -#include "net/route.h" -#include "net_malloc.h" -#include "net/if_arp.h" -#include "netinet/if_ether.h" -#include - -/* Defines we need */ -#define NETWORK_INTERFACES NETWORK_MODULES_ROOT "interfaces" -#define NETWORK_PROTOCOLS NETWORK_MODULES_ROOT "protocols" - -/* Variables used in other core modules */ -int ndevs = 0; - -/* Static variables, used only in this file */ -struct ifnet *devices = NULL; -struct ifnet *pdevices = NULL; -static sem_id dev_lock = -1; -static sem_id proto_lock = -1; -static sem_id dom_lock = -1; -static int timer_on = 0; -static int init_done = 0; - -/* Forward prototypes... */ -/* Private for this file */ -status_t std_ops(int32 op, ...); - -static int start_stack(void); -static int stop_stack(void); - -static status_t control_net_module(const char *name, uint32 op, void *data, - size_t length); - -static void add_protosw(struct protosw *[], int layer); -static struct net_module *module_list = NULL; - -static int get_max_hdr(void); -static void set_max_linkhdr(int maxLinkHdr); -static int get_max_linkhdr(void); -static void set_max_protohdr(int maxProtoHdr); -static int get_max_protohdr(void); - -#ifdef SHOW_DEBUG -void walk_protocols(void); -#endif - -/* Wider scoped prototypes */ -int net_sysctl(int *name, uint namelen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen); - -struct protosw * protocols; -struct domain *domains = NULL; - -struct core_module_info core_info = { - { - NET_CORE_MODULE_NAME, - B_KEEP_LOADED, - std_ops - }, - - start_stack, - stop_stack, - control_net_module, - add_domain, - remove_domain, - add_protocol, - remove_protocol, - add_protosw, - start_rx_thread, - start_tx_thread, - - get_max_hdr, - set_max_linkhdr, - get_max_linkhdr, - set_max_protohdr, - get_max_protohdr, - - net_add_timer, - net_remove_timer, - - start_ifq, - stop_ifq, - - pool_init, - pool_get, - pool_put, - pool_destroy, - - sonewconn, - soreserve, - sockbuf_reserve, - sockbuf_append, - sockbuf_appendaddr, - sockbuf_drop, - sockbuf_flush, - sowakeup, - socket_set_connected, - socket_set_connecting, - socket_set_disconnected, - socket_set_disconnecting, - socket_set_hasoutofband, - socket_set_cantrcvmore, - socket_set_cantsendmore, - - in_pcballoc, - in_pcbdetach, - in_pcbbind, - in_pcbconnect, - in_pcbdisconnect, - in_pcblookup, - in_control, - in_losing, - in_canforward, - in_localaddr, - in_pcbrtentry, - in_setsockaddr, - in_setpeeraddr, - in_pcbnotify, - inetctlerr, - in_cksum, - - m_gethdr, - m_get, - m_cat, - m_adj, - m_prepend, - m_pullup, - m_copyback, - m_copydata, - m_copym, - m_free, - m_freem, - m_reserve, - m_devget, - - net_server_add_device, - get_interfaces, - in_broadcast, - - rtalloc, - rtalloc1, - rtfree, - rtrequest, - rn_addmask, - rn_head_search, - get_rt_tables, - rt_setgate, - - ifa_ifwithdstaddr, - ifa_ifwithnet, - if_attach, - if_detach, - ifa_ifwithaddr, - ifa_ifwithroute, - ifaof_ifpforaddr, - ifafree, - - get_primary_addr, - - net_sysctl, - - socket_init, - socket_create, - socket_close, - socket_bind, - socket_listen, - socket_connect, - socket_accept, - socket_recv, - socket_send, - socket_ioctl, - socket_writev, - socket_readv, - socket_setsockopt, - socket_getsockopt, - socket_getpeername, - socket_getsockname, - socket_socketpair, - socket_set_event_callback, - socket_shutdown -}; - - -static -status_t -control_net_module(const char *name, uint32 op, void *data, size_t length) -{ - struct net_module *module = module_list; - - for(; module; module = module->next) { - if(module->name && !strcmp(module->name, name)) - break; - } - - if(!module || !module->ptr->control) - return B_ERROR; - // no module found - - return module->ptr->control(op, data, length); -} - - -static int32 -if_thread(void *data) -{ - struct ifnet *i = (struct ifnet *)data; - status_t status; - char buffer[ETHER_MAX_LEN]; - size_t len = ETHER_MAX_LEN; - - while ((status = read(i->devid, buffer, len)) >= B_OK) { - struct mbuf *mb = m_devget(buffer, status, 0, i, NULL); - if (!(i->if_flags & IFF_UP)) - break; - - if (mb != NULL) { - IFQ_ENQUEUE(i->devq, mb); - atomic_add(&i->if_ipackets, 1); - } - - len = ETHER_MAX_LEN; - } - printf("%s: terminating if_thread\n", i->if_name); - return 0; -} - -/* This is used when we don't have a dev to read/write from as we're using - * a virtual device, e.g. a loopback driver! - * - * It simply queue's the buf's and drags them off as normal in the tx thread. - */ -static int32 rx_thread(void *data) -{ - struct ifnet *i = (struct ifnet *)data; - struct mbuf *m; - - while (1) { - acquire_sem_etc(i->rxq->pop, 1, B_CAN_INTERRUPT|B_DO_NOT_RESCHEDULE, 0); - if (!(i->if_flags & IFF_UP)) - break; - IFQ_DEQUEUE(i->rxq, m); - - if (i->input) - i->input(m); - else - printf("%s: no input function!\n", i->if_name); - } - printf("%s: terminating rx_thread\n", i->if_name); - return 0; -} - -/* This is the same regardless of either method of getting the packets... */ -/* The buffer size is now a variable. Why? - * MTU's vary, but they don't take into account the size of possible media headers, - * so while an ethernet cards mtu is 1500, a valid packet can be up to 1514, mtu + if_hdrlen! - * However, loopback MTU is 16k, so our previous 2k buffer was too small for loopback and wasteful - * for ethernet cards. So, now we make it flexible and correctly sized. - */ -static int32 tx_thread(void *data) -{ - struct ifnet *i = (struct ifnet *)data; - struct mbuf *m; - char *buffer = malloc(i->if_mtu + i->if_hdrlen); //--- mwcc doesn't allow dynamically sized arrays - size_t len = 0, maxlen = i->if_mtu + i->if_hdrlen; - status_t status; -#if SHOW_DEBUG - int txc = 0; -#endif - - while (1) { - acquire_sem_etc(i->txq->pop,1,B_CAN_INTERRUPT|B_DO_NOT_RESCHEDULE, 0); - if (!(i->if_flags & IFF_UP)) - break; - - IFQ_DEQUEUE(i->txq, m); - - if (m) { - if (m->m_flags & M_PKTHDR) - len = m->m_pkthdr.len; - else - len = m->m_len; - - if (len > maxlen) { - printf("%s: tx_thread: packet was too big (%ld bytes vs max size of %ld)!\n", i->if_name, - len, maxlen); - } else { - m_copydata(m, 0, len, buffer); -#if SHOW_DEBUG - dump_buffer(buffer, len); -#endif - status = write(i->devid, buffer, len); - if (status < B_OK) { - printf("Error sending data [%s]!\n", strerror(status)); - /* ??? - should we exit at this point? */ - } - } - m_freem(m); - } - } - printf("%s: terminating tx_thread\n", i->if_name); - free(buffer); - return 0; -} - -/* Start an RX thread and an RX queue if reqd */ -void start_rx_thread(struct ifnet *dev) -{ - int32 priority = B_NORMAL_PRIORITY; - char name[B_OS_NAME_LENGTH]; /* 32 */ - sprintf(name, "%s_rx_thread", dev->if_name); - - if (dev->if_type != IFT_ETHER) { - if (!dev->rxq) - dev->rxq = start_ifq(); - if (!dev->rxq) - return; - dev->rx_thread = spawn_kernel_thread(rx_thread, name, - priority, dev); - } else { - /* don't need an rxq... */ - dev->rx_thread = spawn_kernel_thread(if_thread, name, - priority, dev); - } - - if (dev->rx_thread < 0) { - printf("Failed to start the rx_thread for %s\n", dev->if_name); - dev->rx_thread = -1; - return; - } - resume_thread(dev->rx_thread); -} - -/* Start a TX thread and a TX queue */ -void start_tx_thread(struct ifnet *dev) -{ - int32 priority = B_NORMAL_PRIORITY; - char name[B_OS_NAME_LENGTH]; /* 32 */ - if (!dev->txq) - dev->txq = start_ifq(); - if (!dev->txq) - return; - - sprintf(name, "%s_tx_thread", dev->if_name); - dev->tx_thread = spawn_kernel_thread(tx_thread, name, priority, dev); - if (dev->tx_thread < 0) { - printf("Failed to start the tx_thread for %s\n", dev->if_name); - dev->tx_thread = -1; - return; - } - resume_thread(dev->tx_thread); -} - -static int get_max_hdr(void) -{ - return max_hdr; -} - -static void set_max_linkhdr(int maxLinkHdr) -{ - max_linkhdr = maxLinkHdr; - max_hdr = max_linkhdr + max_protohdr; -} - -static int get_max_linkhdr(void) -{ - return max_linkhdr; -} - -static void set_max_protohdr(int maxProtoHdr) -{ - max_protohdr = maxProtoHdr; - max_hdr = max_linkhdr + max_protohdr; -} - -static int get_max_protohdr(void) -{ - return max_protohdr; -} - -void net_server_add_device(struct ifnet *ifn) -{ - char dname[16]; - - if (!ifn) - return; - - sprintf(dname, "%s%d", ifn->name, ifn->if_unit); - ifn->if_name = strdup(dname); - - if (ifn->if_type != IFT_ETHER) { - /* pseudo device... */ - if (pdevices) - ifn->if_next = pdevices; - else - ifn->if_next = NULL; - pdevices = ifn; - } else { - if (devices) - ifn->if_next = devices; - else - ifn->if_next = NULL; - ifn->id = ndevs++; - devices = ifn; - } -} - -/* -static void merge_devices(void) -{ - struct ifnet *d = NULL; - - if (!devices && !pdevices) { - printf("No devices!\n"); - return; - } - - acquire_sem(dev_lock); - if (devices) { - for (d = devices; d->if_next != NULL; d = d->if_next) { - continue; - } - } - if (pdevices) { - if (d) { - d->if_next = pdevices; - d = d->if_next; - } else { - devices = pdevices; - d = devices; - } - while (d) { - d->id = ndevs++; - d = d->if_next; - } - } - release_sem(dev_lock); -} -*/ - -/* Hmm, we should do this via the ioctl for the device/module to tell it that - * the card is going down... - * XXX - implement this correctly. - */ -static void close_devices(void) -{ - struct ifnet *d = devices; - while (d) { - d->if_flags &= ~IFF_UP; - kill_thread(d->rx_thread); - kill_thread(d->tx_thread); - close(d->devid); - d = d->if_next; - } - devices = NULL; -} - -static struct domain af_inet_domain = { - AF_INET, - "internet", - NULL, - NULL, - NULL, - rn_inithead, - 32, - sizeof(struct sockaddr_in) -}; - -/* Domain support */ -void add_domain(struct domain *dom, int fam) -{ - struct domain *dm = domains; - struct domain *ndm; - - for(; dm; dm = dm->dom_next) { - if (dm->dom_family == fam) - /* already done */ - return; - } - - acquire_sem_etc(dom_lock, 1, B_CAN_INTERRUPT, 0); - if (dom == NULL) { - /* we're trying to add a builtin domain! */ - - switch (fam) { - case AF_INET: - /* ok, add it... */ - ndm = (struct domain*)malloc(sizeof(*ndm)); - *ndm = af_inet_domain; - if (dm) - dm->dom_next = ndm; - else - domains = ndm; - /* avoids too many release_sem_etc... */ - goto domain_done; - default: - printf("Don't know how to add domain %d\n", fam); - } - } else { - /* find the end of the chain and add ourselves there */ - for (dm = domains; dm->dom_next;dm = dm->dom_next) - continue; - if (dm) - dm->dom_next = dom; - else - domains = dom; - } -domain_done: - release_sem_etc(dom_lock, 1, B_CAN_INTERRUPT); - return; -} - -#ifdef SHOW_DEBUG -void walk_protocols(void) -{ - struct protosw *pr = protocols; - printf("Protocols:\n"); - for (;pr;pr = pr->pr_next) { - printf(" Protocol %s (%p)->(%p)\n", pr->name, pr, pr->pr_next); - } - printf("End of Protocol list\n"); -} -#endif - -void add_protocol(struct protosw *pr, int fam) -{ - struct protosw *psw = protocols; - struct domain *dm = domains; - - /* first find the correct domain... */ - for (;dm; dm = dm->dom_next) { - if (dm->dom_family == fam) - break; - } - - if (dm == NULL) { - printf("Unable to add protocol due to no domain available!\n"); - return; - } - - acquire_sem_etc(proto_lock, 1, B_CAN_INTERRUPT, 0); - /* OK, we can add it... */ - for (;psw;psw = psw->pr_next) { - if (psw->pr_type == pr->pr_type && - psw->pr_protocol == pr->pr_protocol && - psw->pr_domain == dm) { - release_sem_etc(proto_lock, 1, B_CAN_INTERRUPT); - printf("Duplicate protocol detected (%s)!!\n", pr->name); - return; - } - } - - pr->pr_next = NULL; - pr->dom_next = NULL; - pr->pr_domain = NULL; - /* find last entry in protocols list */ - if (protocols) { - for (psw = protocols;psw->pr_next; psw = psw->pr_next) - continue; - psw->pr_next = pr; - } else - protocols = pr; - - release_sem_etc(proto_lock, 1, B_CAN_INTERRUPT); - - pr->pr_domain = dm; - - /* Now add to domain */ - acquire_sem_etc(dom_lock, 1, B_CAN_INTERRUPT, 0); - if (dm->dom_protosw) { - psw = dm->dom_protosw; - for (;psw->dom_next;psw = psw->dom_next) - continue; - psw->dom_next = pr; - } else - dm->dom_protosw = pr; - release_sem_etc(dom_lock, 1, B_CAN_INTERRUPT); - return; -} - -void remove_protocol(struct protosw *pr) -{ - struct protosw *psw = protocols, *opr = NULL; - struct domain *dm; - - acquire_sem_etc(proto_lock, 1, B_CAN_INTERRUPT, 0); - for (;psw;psw = psw->pr_next) { - if (psw == pr) { - if (opr) { - opr->pr_next = psw->pr_next; - } else { - /* first entry */ - protocols = psw->pr_next; - } - break; - } - opr = psw; - } - pr->pr_next = NULL; - - dm = pr->pr_domain; - opr = NULL; - - acquire_sem_etc(dom_lock, 1, B_CAN_INTERRUPT, 0); - - for (psw = dm->dom_protosw; psw; psw = psw->dom_next) { - if (psw == pr) { - if (opr) - opr->dom_next = psw->dom_next; - else - dm->dom_protosw = psw->dom_next; - break; - } - opr = psw; - } - - release_sem_etc(dom_lock, 1, B_CAN_INTERRUPT); - release_sem_etc(proto_lock, 1, B_CAN_INTERRUPT); - - pr->dom_next = NULL; - pr->pr_domain = NULL; -} - -static void walk_domains(void) -{ - struct domain *d; - struct protosw *p; - - for (d = domains;d;d = d->dom_next) { - p = d->dom_protosw; - for (;p;p = p->dom_next) { - printf("\t%s provided by %s\n", p->name, p->mod_path); - } - } -} - -void remove_domain(int fam) -{ - struct domain *dmp = domains, *opr = NULL; - - for (; dmp; dmp = dmp->dom_next) { - if (dmp->dom_family == fam) - break; - opr = dmp; - } - if (!dmp || dmp->dom_protosw != NULL) - return; - - acquire_sem_etc(dom_lock, 1, B_CAN_INTERRUPT, 0); - /* we're ok to remove it! */ - if (opr) - opr->dom_next = dmp->dom_next; - else - domains = dmp->dom_next; - dmp->dom_next = NULL; - if (dmp->dom_family == AF_INET) - free(dmp); - release_sem_etc(dom_lock, 1, B_CAN_INTERRUPT); - - return; -} - -static void add_protosw(struct protosw *prt[], int layer) -{ - struct protosw *p; - - for (p = protocols; p; p = p->pr_next) { - if (p->layer == layer) - prt[p->pr_protocol] = p; - if (layer == NET_LAYER3 && p->layer == NET_LAYER2) - prt[p->pr_protocol] = p; - if (layer == NET_LAYER1 && p->layer == NET_LAYER2) - prt[p->pr_protocol] = p; - if (layer == NET_LAYER2 && p->layer == NET_LAYER3) - prt[p->pr_protocol] = p; - } -} - -static void domain_init(void) -{ - struct domain *d; - struct protosw *p; - - for (d = domains;d;d = d->dom_next) { - if (d->dom_init) - d->dom_init(); - - for (p = d->dom_protosw;p;p = p->dom_next) { - if (p->pr_init) - p->pr_init(); - } - } -} - - -/* Add protocol modules. Each module is loaded and this triggers - * the init routine which should call the add_domain and add_protocol - * functions to make sure we know what it does! - * NB these don't have any additional functions so we just use the - * system defined module_info structures - */ - -static void -find_protocol_modules(void) -{ - void *ml; - char name[B_FILE_NAME_LENGTH]; - size_t bufferSize = sizeof(name); - struct net_module *nm = NULL; - int rv; - - ml = open_module_list(NETWORK_PROTOCOLS); - - if (ml == NULL) { - printf("failed to open the %s directory\n", - NETWORK_PROTOCOLS); - return; - } - - while (read_next_module_name(ml, name, &bufferSize) == B_OK) { - nm = (struct net_module *)malloc(sizeof(struct net_module)); - if (!nm) - return; - memset(nm, 0, sizeof(*nm)); - nm->name = strdup(name); - printf("module: %s\n", name); - rv = get_module(name, (module_info **)&nm->ptr); - if (rv == 0) { - nm->next = module_list; - module_list = nm; - } else { - free(nm); - } - bufferSize = sizeof(name); - } - - close_module_list(ml); - - /* we call these here as we want to load all modules ourselves first - */ - for (nm = module_list; nm; nm = nm->next) { - nm->ptr->start(NULL); - nm->status = 1; - } -} - - -/* This is a little misnamed. This goes through and tries to - * load all the interface modules it finds and calls each one's - * init function. The init functions should build a lit of devices - * that can be used and add each one to the stack. Until we run - * start_devices() they'll not do anything and other apps can use - * them (AFAIK), so this shouldn't be an issue. - */ -static void -find_interface_modules(void) -{ - void *ml = open_module_list(NETWORK_INTERFACES); - char name[B_FILE_NAME_LENGTH]; - size_t bufferSize = sizeof(name); - struct net_module *nm = NULL; - int rv; - - if (ml == NULL) { - printf("failed to open the %s directory\n", - NETWORK_INTERFACES); - return; - } - - while (read_next_module_name(ml, name, &bufferSize) == B_OK) { - nm = (struct net_module *)malloc(sizeof(struct net_module)); - if (!nm) - return; - memset(nm, 0, sizeof(*nm)); - nm->name = strdup(name); - printf("module: %s\n", name); - rv = get_module(name, (module_info**)&nm->ptr); - if (rv == 0) { - nm->next = module_list; - module_list = nm; - nm->ptr->start(NULL); - nm->status = 1; - } else { - free(nm); - } - - bufferSize = sizeof(name); - } - - close_module_list(ml); -} - -/* TODO: userland modules support is now moved in - src/servers/net/userland_modules.cpp - These two hacks are no more needed, should be removed soon... -*/ - -#if 0 - -static void _find_interface_modules(char *dirpath) -{ - char path[PATH_MAX]; - DIR *dir; - struct dirent *fe; - struct net_module *nm = NULL; - status_t status; - - dir = opendir(dirpath); - if (!dir) - return; - - while ((fe = readdir(dir)) != NULL) { - /* last 2 entries are only valid for development... */ - if (strcmp(fe->d_name, ".") == 0 || strcmp(fe->d_name, "..") == 0 - || strcmp(fe->d_name, ".cvsignore") == 0 - || strcmp(fe->d_name, "CVS") == 0) - continue; - sprintf(path, "%s/%s", dirpath, fe->d_name); - - nm = (struct net_module*)malloc(sizeof(struct net_module)); - if (!nm) - return; - nm->name = strdup(fe->d_name); - nm->iid = load_add_on(path); - if (nm->iid > 0) { - status = get_image_symbol(nm->iid, "device_info", - B_SYMBOL_TYPE_DATA, (void**)&nm->ptr); - if (status == B_OK) { - nm->next = module_list; - module_list = nm; - nm->ptr->start(&core_info); - nm->status = 1; - printf("\t%s\n", path); - } else { - free(nm); - } - } - } -} - -static void find_interface_modules(void) -{ - char cdir[PATH_MAX], path[PATH_MAX]; - getcwd(cdir, PATH_MAX); - sprintf(path, "%s/modules/interface", cdir); - _find_interface_modules(path); - sprintf(path, "%s/modules/ppp/devices", cdir); - _find_interface_modules(path); -} - -static void find_protocol_modules(void) -{ - char path[PATH_MAX], cdir[PATH_MAX]; - DIR *dir; - struct dirent *m; - struct net_module *nm = NULL; - status_t status; - -printf("userland: find_protocol_modules...\n"); - - getcwd(cdir, PATH_MAX); - sprintf(cdir, "%s/modules/protocol", cdir); - - dir = opendir(cdir); - if (!dir) - return; - - while ((m = readdir(dir)) != NULL) { - /* last 2 entries are only valid for development... */ - if (strcmp(m->d_name, ".") == 0 || strcmp(m->d_name, "..") == 0 - || strcmp(m->d_name, ".cvsignore") == 0 - || strcmp(m->d_name, "CVS") == 0) - continue; - /* ok so we try it... */ - sprintf(path, "%s/%s", cdir, m->d_name); - - nm = (struct net_module*)malloc(sizeof(struct net_module)); - if (!nm) - return; - nm->name = strdup(m->d_name); - nm->iid = load_add_on(path); - if (nm->iid > 0) { - status = get_image_symbol(nm->iid, "protocol_info", - B_SYMBOL_TYPE_DATA, (void**)&nm->ptr); - if (status == B_OK) { - nm->next = module_list; - module_list = nm; - nm->ptr->start(&core_info); - nm->status = 1; - } else { - free(nm); - } - } - } - - printf("\n"); -} - -#endif - -struct protosw *pffindtype(int domain, int type) -{ - struct domain *d; - struct protosw *p; - - for (d = domains; d; d = d->dom_next) { - if (d->dom_family == domain) - goto found; - } - return NULL; -found: - for (p=d->dom_protosw; p; p = p->dom_next) { - if (p->pr_type && p->pr_type == type) { - return p; - } - } - return NULL; -} - -struct protosw *pffindproto(int domain, int protocol, int type) -{ - struct domain *d; - struct protosw *p, *maybe = NULL; - - if (domain == 0) - return NULL; - - for (d = domains; d; d = d->dom_next) { - if (d->dom_family == domain) - goto found; - } - return NULL; - -found: - for (p=d->dom_protosw;p;p = p->dom_next) { - if (p->pr_protocol == protocol && p->pr_type == type) - return p; - /* deal with SOCK_RAW and AF_UNSPEC */ - if (type == SOCK_RAW && p->pr_type == SOCK_RAW && - p->pr_protocol == AF_UNSPEC && maybe == NULL) - maybe = p; - } - return maybe; -} - -int net_sysctl(int *name, uint namelen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen) -{ - struct domain *dp; - struct protosw *pr; - int family, protocol; - - if (namelen < 3) { - printf("net_sysctl: EINVAL (namelen < 3, %d)\n", namelen); - return EINVAL; // EISDIR?? - } - family = name[0]; - protocol = name[1]; - - if (family == 0) - return 0; - - for (dp=domains; dp; dp= dp->dom_next) - if (dp->dom_family == family) - goto found; - return EINVAL; //EPROTOOPT; -found: - for (pr=dp->dom_protosw; pr; pr = pr->dom_next) { - if (pr->pr_protocol == protocol && pr->pr_sysctl) { - return ((*pr->pr_sysctl)(name+2, namelen -2, oldp, oldlenp, newp, newlen)); - } - } - return EINVAL;//EPROTOOPT; -} - -static int start_stack(void) -{ - if (init_done) - return 0; - - if (timer_on == 0) { - net_init_timer(); - timer_on = 1; - } - - domains = NULL; - protocols = NULL; - - find_protocol_modules(); - - walk_domains(); - - domain_init(); - - mbinit(); - sockets_init(); - inpcb_init(); - route_init(); - if_init(); - - if (dev_lock == -1) - dev_lock = create_sem(1, "device_lock"); - if (proto_lock == -1) - proto_lock = create_sem(1, "protocol_lock"); - if (dom_lock == -1) - dom_lock = create_sem(1, "domain_lock"); - -#ifdef _KERNEL_MODE - set_sem_owner(dev_lock, B_SYSTEM_TEAM); - set_sem_owner(proto_lock, B_SYSTEM_TEAM); - set_sem_owner(dom_lock, B_SYSTEM_TEAM); -#endif - - find_interface_modules(); - - init_done = 1; - - return 0; -} - -static int stop_stack(void) -{ - struct net_module *nm = module_list, *onm = NULL; - - printf("core network module: Stopping network stack!\n"); - - close_devices(); - - /* unload all modules... */ - printf("trying to stop modules\n"); - for (;nm; nm = nm->next) { - printf("stopping %s\n", nm->name); - if (nm->ptr->stop) - nm->ptr->stop(); - } - printf("trying to unload modules\n"); - nm = module_list; - do { - put_module(nm->name); - onm = nm; - nm = nm->next; - onm->next = NULL; - free(onm); - } while (nm); - - /* This is more likely the correct place for this... - * can't call it at the moment due to the way we call this function! - sockets_shutdown(); - */ - - delete_sem(dev_lock); - delete_sem(proto_lock); - delete_sem(dom_lock); - dev_lock = proto_lock = dom_lock = -1; - init_done = 0; - module_list = NULL; - ndevs = 0; - - return 0; -} - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - printf("core: B_MODULE_INIT\n"); - break; - - case B_MODULE_UNINIT: - // the stack is keeping loaded, so don't stop it - printf("core: B_MODULE_UNINIT\n"); - break; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info *) &core_info, - NULL -}; - diff --git a/src/add-ons/kernel/network/core/core_private.h b/src/add-ons/kernel/network/core/core_private.h deleted file mode 100644 index f0287afd03..0000000000 --- a/src/add-ons/kernel/network/core/core_private.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _CORE_PRIVATE__H -#define _CORE_PRIVATE__H - - -struct iovec; - -enum uio_rw { UIO_READ, UIO_WRITE }; - -/* Segment flag values. */ -enum uio_seg { - UIO_USERSPACE, /* from user data space */ - UIO_SYSSPACE /* from system space */ -}; - -struct uio { - struct iovec *uio_iov; /* pointer to array of iovecs */ - int uio_iovcnt; /* number of iovecs in array */ - off_t uio_offset; /* offset into file this uio corresponds to */ - size_t uio_resid; /* residual i/o count */ - enum uio_seg uio_segflg; /* see above */ - enum uio_rw uio_rw; /* see above */ -// struct proc *uio_procp; /* process if UIO_USERSPACE */ -}; - -struct ifnet; - - -int uiomove(char *cp, int n, struct uio *uio); - -void in_if_detach(struct ifnet *ifp); - // this removes all IP related references for this interface (route, address) - -extern struct pool_ctl *mbpool; -extern struct pool_ctl *clpool; - -extern int max_hdr; /* largest link+protocol header */ -extern int max_linkhdr; /* largest link level header */ -extern int max_protohdr; /* largest protocol header */ - -#endif diff --git a/src/add-ons/kernel/network/core/if.c b/src/add-ons/kernel/network/core/if.c deleted file mode 100644 index cd9b6f6fba..0000000000 --- a/src/add-ons/kernel/network/core/if.c +++ /dev/null @@ -1,499 +0,0 @@ -/* if helper functions */ - -#include -#include -#include -#include - -#ifdef _KERNEL_MODE - #include - #define printf dprintf -#endif - -#include "core_private.h" -#include "netinet/in.h" -#include "sys/socketvar.h" -#include "net/if.h" -#include "net/if_dl.h" -#include "sys/sockio.h" -#include "netinet/in_var.h" -#include "net/route.h" -#include "sys/protosw.h" - -extern struct ifnet *devices; -extern int ndevs; - -/* Variables used outside this file */ -struct ifaddr **ifnet_addrs; - -/* Private variables */ -static int if_index; -static int if_indexlim; - -void dump_sockaddr(void *ptr); -void *protocol_address(struct ifnet *ifa, int family); - - -static inline bool -equal(struct sockaddr *addr1, struct sockaddr *addr2) -{ - return !memcmp(addr1, addr2, addr1->sa_len); -} - - -struct ifnet * -get_interfaces(void) -{ - return devices; -} - - -void -if_init(void) -{ - ifnet_addrs = NULL; - if_index = 0; - if_indexlim = 8; /* initial value */ -} - - -int -ifioctl(struct socket *so, ulong cmd, caddr_t data) -{ - struct ifnet *ifp; - struct ifreq *ifr; - -#if DEBUG - printf("ifioctl(0x%lX)\n", cmd); -#endif - - if (cmd == SIOCGIFCONF) - return (ifconf(cmd, data)); - - ifr = (struct ifreq*) data; - ifp = ifunit(ifr->ifr_name); - if (ifp == NULL) - return ENXIO; - - switch(cmd) { - case SIOCGIFFLAGS: - /* get interface flags */ - ifr->ifr_flags = ifp->if_flags; - break; - case SIOCGIFMETRIC: - /* get interface metric */ - ifr->ifr_metric = ifp->if_metric; - break; - case SIOCGIFMTU: - /* get interface MTU */ - ifr->ifr_mtu = ifp->if_mtu; - break; - case SIOCSIFFLAGS: - ifp->if_flags = ifr->ifr_flags; - /* restart card with new settings... */ - break; - case SIOCSIFMETRIC: - /* set interface metric */ - ifp->if_metric = ifr->ifr_metric; - break; - default: -#if DEBUG - printf("ifioctl: Unknown cmd!\n"); -#endif - if (so->so_proto == NULL) - return EOPNOTSUPP; - return (*so->so_proto->pr_userreq)(so, PRU_CONTROL, - (struct mbuf*)cmd, (struct mbuf*)data, (struct mbuf*)ifp); - - } - -#if DEBUG - printf("ifioctl: done\n"); -#endif - - return 0; -} - - -struct ifnet * -ifunit(char *name) -{ - struct ifnet *d = devices; - - for (d=devices;d;d = d->if_next) - if (strcmp(d->if_name, name) == 0) - return d; - return NULL; -} - - -void -dump_sockaddr(void *ptr) -{ - struct sockaddr *sa = (struct sockaddr *)ptr; - uint8 *d = NULL; - int i; - - switch (sa->sa_family) { - case AF_LINK: { - struct sockaddr_dl *sdl = (struct sockaddr_dl *)ptr; - if (sdl->sdl_type == IFT_ETHER) { - printf("\t\tETHERNET: "); - printf("Interface "); - d = (unsigned char *)&sdl->sdl_data[0]; - for (i=0;isdl_nlen;i++, d++) { - printf("%c", *d); - } - printf(" -> "); - for (i=0;isdl_alen;i++, d++) { - printf("%02x", *d); - if (i< 5) - printf(":"); - } - printf("\n"); - } - break; - } - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)ptr; - struct in_addr ho; - ho.s_addr = sin->sin_addr.s_addr; - printf("\t\tIPv4: "); - d = (uint8*)&ho.s_addr; - for (i=0;i<4;i++, d++) { - printf("%d", *d); - if (i < 3) - printf("."); - } - printf("\n"); - break; - } - default: - printf("Unknown type... %d\n", sa->sa_family); - } -} - - -void * -protocol_address(struct ifnet *ifa, int family) -{ - struct ifaddr *a = ifa->if_addrlist; - - for (; a != NULL; a = a->ifa_next) { - if (a->ifa_addr->sa_family == family) { - if (family == AF_INET) { - return &((struct sockaddr_in*)a->ifa_addr)->sin_addr; - } else { - return &a->ifa_addr->sa_data; - } - } - } - return NULL; -} - - -/* - * Find an interface address specific to an interface best matching - * a given address. - */ -struct ifaddr * -ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp) -{ - struct ifaddr *ifa; - char *cp, *cp2, *cp3; - char *cplim; - struct ifaddr *ifa_maybe = 0; - uint af = addr->sa_family; - - if (af >= AF_MAX) - return (NULL); - - for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != af) - continue; - ifa_maybe = ifa; - if (ifa->ifa_netmask == 0) { - if (equal(addr, ifa->ifa_addr) || - (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) - return (ifa); - continue; - } - cp = (char *)addr->sa_data; - cp2 = (char *)ifa->ifa_addr->sa_data; - cp3 = (char *)ifa->ifa_netmask->sa_data; - cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; - for (; cp3 < cplim; cp3++) - if ((*cp++ ^ *cp2++) & *cp3) - break; - if (cp3 == cplim) - return (ifa); - } - return (ifa_maybe); -} - - -struct ifaddr * -ifa_ifwithdstaddr(struct sockaddr *addr) -{ - struct ifnet *ifp; - struct ifaddr *ifa; - - for (ifp = devices; ifp != NULL; ifp = ifp->if_next) - if (ifp->if_flags & IFF_POINTOPOINT) - for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != addr->sa_family || - ifa->ifa_dstaddr == NULL) - continue; - if (equal(addr, ifa->ifa_dstaddr)) - return (ifa); - } - return (NULL); -} - - -struct ifaddr * -ifa_ifwithaddr(struct sockaddr *addr) -{ - struct ifnet *ifp; - struct ifaddr *ifa; - - for (ifp = devices; ifp != NULL; ifp = ifp->if_next) { - for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family != addr->sa_family) - continue; - if (equal(addr, ifa->ifa_addr)) - return (ifa); - if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && - /* IPv6 doesn't have broadcast */ - ifa->ifa_broadaddr->sa_len != 0 && - equal(ifa->ifa_broadaddr, addr)) - return (ifa); - } - } - return (NULL); -} - - -/* - * Find an interface on a specific network. If many, choice - * is most specific found. - */ - -struct ifaddr * -ifa_ifwithnet(struct sockaddr *addr) -{ - struct ifnet *ifp; - struct ifaddr *ifa; - struct ifaddr *ifa_maybe = NULL; - uint af = addr->sa_family; - char *addr_data = (char *)addr->sa_data, *cplim; - - if (af == AF_LINK) { - struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; - if (sdl->sdl_index && sdl->sdl_index <= ndevs) - return (ifnet_addrs[sdl->sdl_index]); - } - for (ifp = devices; ifp != NULL; ifp = ifp->if_next) - for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) { - register char *cp, *cp2, *cp3; - - if (ifa->ifa_addr->sa_family != af || - ifa->ifa_netmask == 0) -next: - continue; - cp = addr_data; - cp2 = (char *)ifa->ifa_addr->sa_data; - cp3 = (char *)ifa->ifa_netmask->sa_data; - cplim = (char *)ifa->ifa_netmask + - ifa->ifa_netmask->sa_len; - while (cp3 < cplim) - if ((*cp++ ^ *cp2++) & *cp3++) - /* want to continue for() loop */ - goto next; - if (ifa_maybe == 0 || - rn_refines((caddr_t)ifa->ifa_netmask, - (caddr_t)ifa_maybe->ifa_netmask)) - ifa_maybe = ifa; - } - return (ifa_maybe); -} - -/* XXX - we have a memory leak here! When we clean up we need to free the memory - * that is malloc'd here - */ -void if_attach(struct ifnet *ifp) -{ - uint socksize, ifasize; - int namelen, masklen; - struct ifnet **p = &devices; - struct sockaddr_dl *sdl; - struct ifaddr *ifa; - char dname[IFNAMSIZ]; - - if (!ifp) - return; - - sprintf(dname, "%s%d", ifp->name, ifp->if_unit); - ifp->if_name = strdup(dname); - - while (*p) - p = &((*p)->if_next); - - *p = ifp; - ifp->if_index = ++if_index; /* atomic add ? */ - - /* allocate memory for ifnet_addrs if required... */ - if (ifnet_addrs == NULL || if_index >= if_indexlim) { - uint n = (if_indexlim <<= 1) * sizeof(*ifa); - struct ifaddr **q = (struct ifaddr**)malloc(n); - if (ifnet_addrs) { - memcpy((caddr_t)q, (caddr_t)ifnet_addrs, n / 2); - free(ifnet_addrs); - } - ifnet_addrs = q; - } - - /* get the unit # as a string */ - namelen = strlen(ifp->if_name); - - /* memory: we need to allocate enough memory for the following... - * struct ifaddr - * struct sockaddr_dl that will hold the link level address and name - * struct sockaddr_dl that will hold the mask - */ - -#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) - masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; - socksize = masklen + ifp->if_addrlen; -#define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(int32) -1))) - socksize = ROUNDUP(socksize); - - if (socksize < sizeof(*sdl)) - socksize = sizeof(*sdl); - ifasize = sizeof(*ifa) + 2 * socksize; - if ((ifa = (struct ifaddr*)malloc(ifasize))) { - memset(ifa, 0, ifasize); - - sdl = (struct sockaddr_dl *)(ifa + 1); - sdl->sdl_len = socksize; - sdl->sdl_family = AF_LINK; - memcpy(&sdl->sdl_data, ifp->if_name, namelen); - sdl->sdl_nlen = namelen; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = ifp->if_type; - ifnet_addrs[if_index - 1] = ifa; - ifa->ifa_ifp = ifp; - ifa->ifa_next = ifp->if_addrlist; - ifp->if_addrlist = ifa; - ifa->ifa_addr = (struct sockaddr*)sdl; - - /* now do mask... */ - sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); - ifa->ifa_netmask = (struct sockaddr*)sdl; - sdl->sdl_len = masklen; - /* build the mask */ - while (namelen != 0) - sdl->sdl_data[--namelen] = 0xff; - } -} - -void if_detach(struct ifnet *ifp) -{ - struct ifnet *p = devices, *q = NULL; - int32 index; - bool found = false; - - for(; p && p != ifp; p = p->if_next) - q = p; - - if(!p) - return; - - // XXX: this is a hack, but we don't want to invest too much work into this stack - in_if_detach(ifp); - // this should also remove all remaining routes - - // remove the ifa entry from ifnet_addrs and reduce all following ifnet indices - for(index = 0; index < if_index; index++) { - if(found) { - --ifnet_addrs[index]->ifa_ifp->if_index; - ifnet_addrs[index - 1] = ifnet_addrs[index]; - } - - if(ifnet_addrs[index]->ifa_ifp == ifp) { - found = true; - free(ifnet_addrs[index]); - } - } - - if(found) - --if_index; - - if(q) - q->if_next = p->if_next; - else - devices = p->if_next; - - free(p->if_name); -} - -/* XXX - memcpy used as copyin / copyout not available. I did look - * for the source for them but was unable to find them in the - * code jungle that is OpenBSD and FreeBSD! - * - * copyin / copyout should maybe be added if they'd add a speed improvement as - * they're used in a lot of other places as well - */ -int ifconf(int cmd, caddr_t data) -{ - struct ifconf *ifc = (struct ifconf*)data; - struct ifnet *ifp = devices; - struct ifaddr *ifa = NULL; - char *cp, *ep; - struct ifreq ifr, *ifrp; - int space = ifc->ifc_len; /* how big the buffer is */ - void *copyptr = NULL; - - ifrp = ifc->ifc_req; - ep = ifr.ifr_name + sizeof(ifr.ifr_name) - 2; - - for (; space > (int) sizeof(ifr) && ifp; ifp = ifp->if_next) { - strncpy(ifr.ifr_name, ifp->if_name, sizeof(ifr.ifr_name) - 2); - for (cp = ifr.ifr_name;cp < ep && *cp; cp++) - continue; - *cp = '\0'; - if ((ifa = ifp->if_addrlist) == NULL) { - memset((caddr_t)&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); - copyptr = memcpy((caddr_t) ifrp, (caddr_t) &ifr, sizeof(ifr)); - if (copyptr == NULL) - break; - space -= sizeof(ifr), ifrp++; - } else { - for (; space > (int) sizeof(ifr) && ifa; ifa = ifa->ifa_next) { - struct sockaddr *sa = ifa->ifa_addr; - if (sa->sa_len <= sizeof(*sa)) { - printf("sa->sa_len = %d compared to %ld, sa->sa_family = %d\n", - sa->sa_len, sizeof(*sa), sa->sa_family); - - ifr.ifr_addr = *sa; - copyptr = memcpy((caddr_t)ifrp, (caddr_t)&ifr, sizeof(ifr)); - ifrp++; - } else { - space -= sa->sa_len - sizeof(*sa); - if (space < (int) sizeof(ifr)) - break; - copyptr = memcpy((caddr_t)ifrp, (caddr_t)&ifr, sizeof(ifr.ifr_name)); - if (copyptr != NULL) - copyptr = memcpy((caddr_t)&ifrp->ifr_addr, (caddr_t)sa, sa->sa_len); - ifrp = (struct ifreq*)(sa->sa_len + (caddr_t)&ifrp->ifr_addr); - } - if (copyptr == NULL) - break; - space -= sizeof(ifr); - } - } - } - ifc->ifc_len -= space; - /* Yuck! */ - return (copyptr == NULL ? -1 : 0); -} diff --git a/src/add-ons/kernel/network/core/ifq.c b/src/add-ons/kernel/network/core/ifq.c deleted file mode 100644 index 8e70a57b8a..0000000000 --- a/src/add-ons/kernel/network/core/ifq.c +++ /dev/null @@ -1,55 +0,0 @@ -/* some misc functions... */ - -#include -#include -#include - -#ifdef _KERNEL_MODE -#include -#endif - -#include -#include - -struct ifq *start_ifq(void) -{ - struct ifq *nifq = (struct ifq*)malloc(sizeof(*nifq)); - - if (!nifq) - return NULL; - - memset(nifq, 0, sizeof(*nifq)); - - nifq->lock = create_sem(1, "ifq_lock"); - nifq->pop = create_sem(0, "ifq_pop"); -#ifdef _KERNEL_MODE - set_sem_owner(nifq->lock, B_SYSTEM_TEAM); - set_sem_owner(nifq->pop, B_SYSTEM_TEAM); -#endif - - if (nifq->lock < B_OK || nifq->pop < B_OK) - return NULL; - - nifq->len = 0; - nifq->maxlen = 50; - nifq->head = nifq->tail = NULL; - return nifq; -} - -void stop_ifq(struct ifq *q) -{ - struct mbuf *m = NULL; - - acquire_sem_etc(q->lock, 1, B_CAN_INTERRUPT, 0); - while (q->head) { - m = q->head; - q->head = m->m_nextpkt; - m->m_nextpkt = NULL; - m_freem(m); - } - q->len = 0; - delete_sem(q->pop); - release_sem_etc(q->lock, 1, B_CAN_INTERRUPT); - delete_sem(q->lock); - free(q); -} diff --git a/src/add-ons/kernel/network/core/in.c b/src/add-ons/kernel/network/core/in.c deleted file mode 100644 index 56eb29bdec..0000000000 --- a/src/add-ons/kernel/network/core/in.c +++ /dev/null @@ -1,537 +0,0 @@ -/* in.c */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core_private.h" - -#ifdef _KERNEL_MODE - #include - #define printf dprintf -#endif - -extern struct ifnet **ifnet_addrs; - -struct in_ifaddr *in_ifaddr = NULL; //XXX is this ever initialized correctly? - -struct in_ifaddr *get_primary_addr(void) -{ - return in_ifaddr; -} - - -/* - * Trim a mask in a sockaddr - */ -void in_socktrim(struct sockaddr_in *ap) -{ - char *cplim = (char *) &ap->sin_addr; - char *cp = (char *) (&ap->sin_addr + 1); - - ap->sin_len = 0; - while (--cp >= cplim) - if (*cp) { - (ap)->sin_len = cp - (char *) (ap) + 1; - break; - } -} - - -#define rtinitflags(x) \ - ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \ - ? RTF_HOST : 0) - -void -in_if_detach(struct ifnet *ifp) -{ - // remove all references to this ifnet - struct in_ifaddr *ia = NULL, *previous = NULL; - struct ifaddr *ifa; - - if(!ifp || !in_ifaddr) - return; - - if(in_ifaddr->ia_ifp == ifp) - ia = in_ifaddr; - else { - for(previous = in_ifaddr; previous && previous->ia_next; - previous = previous->ia_next) - if(previous->ia_next->ia_ifp == ifp) { - ia = previous->ia_next; - break; - } - } - - if(!ia) - return; - - if(rtinit(&(ia->ia_ifa), RTM_DELETE, rtinitflags(ia))) - printf("core.c.: in_if_detach(): Could not delete route!\n"); - - if(ifp->if_addrlist) { - ifa = ifp->if_addrlist; - if(ifa->ifa_addr->sa_family == AF_INET) - ifp->if_addrlist = ifa->ifa_next; - else - for(; ifa; ifa = ifa->ifa_next) - if(ifa->ifa_next && ifa->ifa_next->ifa_addr->sa_family == AF_INET) { - struct ifaddr *tmp = ifa; - ifa = ifa->ifa_next; - tmp->ifa_next = ifa->ifa_next; - } - - if(ifa) - free(ifa); - } - - if(previous) - previous->ia_next = ia->ia_next; - else - in_ifaddr = ia->ia_next; -} - -/* - * remove a route to prefix ("connected route" in cisco terminology). - * re-installs the route by using another interface address, if there's one - * with the same prefix (otherwise we lose the route mistakenly). - */ -static int in_scrubprefix(struct in_ifaddr *target) -{ - struct in_ifaddr *ia; - struct in_addr prefix, mask, p; - int error; - - if ((target->ia_flags & IFA_ROUTE) == 0) - return 0; - - if (rtinitflags(target)) - prefix = target->ia_dstaddr.sin_addr; - else - prefix = target->ia_addr.sin_addr; - mask = target->ia_sockmask.sin_addr; - prefix.s_addr &= mask.s_addr; - - for (ia = in_ifaddr; ia; ia = ia->ia_next) { - /* easy one first */ - if (mask.s_addr != ia->ia_sockmask.sin_addr.s_addr) - continue; - - if (rtinitflags(ia)) - p = ia->ia_dstaddr.sin_addr; - else - p = ia->ia_addr.sin_addr; - p.s_addr &= ia->ia_sockmask.sin_addr.s_addr; - if (prefix.s_addr != p.s_addr) - continue; - - /* - * if we got a matching prefix route, move IFA_ROUTE to him - */ - if ((ia->ia_flags & IFA_ROUTE) == 0) { - rtinit(&(target->ia_ifa), (int)RTM_DELETE, - rtinitflags(target)); - target->ia_flags &= ~IFA_ROUTE; - - error = rtinit(&ia->ia_ifa, (int)RTM_ADD, - rtinitflags(ia) | RTF_UP); - if (error == 0) - ia->ia_flags |= IFA_ROUTE; - return error; - } - } - - /* - * noone seem to have prefix route. remove it. - */ - rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); - target->ia_flags &= ~IFA_ROUTE; - return 0; -} - -#undef rtinitflags - -int in_ifinit(struct ifnet *dev, struct in_ifaddr *ia, struct sockaddr_in *sin, - int scrub) -{ - uint32 i = sin->sin_addr.s_addr; - struct sockaddr_in oldsin; - int error; - int flags = RTF_UP; - - oldsin = ia->ia_addr; - ia->ia_addr = *sin; - - if (dev && dev->ioctl) { - error = (*dev->ioctl)(dev, SIOCSIFADDR, (caddr_t)ia); - if (error) { - ia->ia_addr = oldsin; - return error; - } - } - - if (dev->if_type == IFT_ETHER) { - ia->ia_ifa.ifa_flags |= RTF_CLONING; - } - - if (scrub) { - ia->ia_ifa.ifa_addr = (struct sockaddr*)&oldsin; - in_scrubprefix(ia); - ia->ia_ifa.ifa_addr = (struct sockaddr*)&ia->ia_addr; - } - - if (IN_CLASSA(i)) - ia->ia_netmask = IN_CLASSA_NET; - else if (IN_CLASSB(i)) - ia->ia_netmask = IN_CLASSB_NET; - else - ia->ia_netmask = IN_CLASSC_NET; - - if (ia->ia_subnetmask == 0) { - ia->ia_subnetmask = ia->ia_netmask; - ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask; - } else - ia->ia_netmask &= ia->ia_subnetmask; - - ia->ia_net = i & ia->ia_netmask; - ia->ia_subnet = i & ia->ia_subnetmask; - in_socktrim(&ia->ia_sockmask); - - ia->ia_ifa.ifa_metric = dev->if_metric; - if (dev->if_flags & IFF_BROADCAST) { - ia->ia_broadaddr.sin_addr.s_addr = ia->ia_subnet | ~ia->ia_subnetmask; - ia->ia_netbroadcast.s_addr = ia->ia_net | ~ia->ia_netmask; - } else if (dev->if_flags & IFF_LOOPBACK) { - ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; - flags |= RTF_HOST; - } else if (dev->if_flags & IFF_POINTOPOINT) { - if (ia->ia_dstaddr.sin_family != AF_INET) - return 0; - flags |= RTF_HOST; - } - - /* This is really useful debugging code, but not needed at the moment... */ -#if 0 - printf("in_ifaddr:\n"); - printf(" : ia_net : %08lx\n", ia->ia_net); - printf(" : ia_netmask : %08lx\n", ia->ia_netmask); - printf(" : ia_subnet : %08lx\n", ia->ia_subnet); - printf(" : ia_subnetmask : %08lx\n", ia->ia_subnetmask); - printf(" : ia_netbroadcast : %08lx\n", ia->ia_netbroadcast.s_addr); - printf(" : ia_addr : %08lx\n", ia->ia_addr.sin_addr.s_addr); - printf(" : ia_dstaddr : %08lx\n", ia->ia_dstaddr.sin_addr.s_addr); - printf(" : ia_sockmask : %08lx\n", ia->ia_sockmask.sin_addr.s_addr); -#endif - - error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags); - if (error == 0) - ia->ia_flags |= IFA_ROUTE; - - /* XXX - Multicast address list */ - - return error; -} - -int in_control(struct socket *so, int cmd, caddr_t data, struct ifnet *ifp) -{ - struct ifreq *ifr = (struct ifreq*)data; - struct in_ifaddr *ia = NULL; - struct ifaddr *ifa; - struct in_ifaddr *oia; - struct in_aliasreq *ifra = (struct in_aliasreq*)data; - struct sockaddr_in oldaddr; - int error = 0, hostIsNew, maskIsNew; - long i; - - if (ifp) /* we need to find the in_ifaddr */ - for (ia = in_ifaddr; ia; ia = ia->ia_next) - if (ia->ia_ifp == ifp) - break; - - switch (cmd) { - case SIOCAIFADDR: - printf("SIOCAIFADDR\n"); - /* add an address */ - case SIOCDIFADDR: - printf("SIODIFADDR\n"); - /* delete an address */ - if (ifra->ifra_addr.sin_family == AF_INET) - for (oia = ia; ia; ia = ia->ia_next) { - if (ia->ia_ifp == ifp && - ia->ia_addr.sin_addr.s_addr == ifra->ifra_addr.sin_addr.s_addr) - break; - } - if (cmd == (int) SIOCDIFADDR && ia == NULL) - return EADDRNOTAVAIL; - case SIOCSIFADDR: - printf("SIOCSIFADDR\n"); - /* set an address */ - case SIOCSIFNETMASK: - printf("SIOCSIFNETMASK #1 (%d)\n", cmd); - /* set a net mask */ - case SIOCSIFDSTADDR: - /* set the destination address of a point to point link */ - if (!ifp) { - printf("No interface pointer!\n"); - return EINVAL; - } - if (ia == NULL) { - oia = (struct in_ifaddr*)malloc(sizeof(struct in_ifaddr)); - if (oia == NULL) - return ENOMEM; - memset(oia, 0, sizeof(*oia)); - if ((ia = in_ifaddr)) { - /* we've got other structures - add at end */ - for (; ia->ia_next; ia = ia->ia_next) - continue; - ia->ia_next = oia; - } else - in_ifaddr = oia; - - ia = oia; - if ((ifa = ifp->if_addrlist)) { - for (; ifa->ifa_next; ifa = ifa->ifa_next) - continue; - ifa->ifa_next = (struct ifaddr*)ia; - } else - ifp->if_addrlist = (struct ifaddr*)ia; - - ia->ia_ifa.ifa_addr = (struct sockaddr*) &ia->ia_addr; - ia->ia_ifa.ifa_dstaddr = (struct sockaddr*) &ia->ia_dstaddr; - ia->ia_ifa.ifa_netmask = (struct sockaddr*) &ia->ia_sockmask; - ia->ia_sockmask.sin_len = 8; - if (ifp->if_flags & IFF_BROADCAST) { - ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); - ia->ia_broadaddr.sin_family = AF_INET; - } - ia->ia_ifp = ifp; - } - break; - case SIOCSIFBRDADDR: - case SIOCGIFADDR: - case SIOCGIFNETMASK: - case SIOCGIFDSTADDR: - case SIOCGIFBRDADDR: - if (ia == NULL) - return EADDRNOTAVAIL; - break; - - } - - printf("loop #2 : %d [%ld]\n", cmd, SIOCSIFNETMASK); - - switch(cmd) { - case SIOCGIFADDR: - /* get interface address */ - *((struct sockaddr_in*) &ifr->ifr_addr) = ia->ia_addr; - break; - case SIOCGIFDSTADDR: - /* get interface point to point destination address */ - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - /* we're not a point to point interface */ - return EINVAL; - *((struct sockaddr_in*) &ifr->ifr_dstaddr) = ia->ia_dstaddr; - break; - case SIOCGIFBRDADDR: - /* get interface broadcast address */ - if ((ifp->if_flags & IFF_BROADCAST) == 0) - /* we're not a broadcast capable interface */ - return EINVAL; - *((struct sockaddr_in*) &ifr->ifr_dstaddr) = ia->ia_broadaddr; - break; - case SIOCGIFNETMASK: - /* get interface netmask */ - *((struct sockaddr_in*) &ifr->ifr_addr) = ia->ia_sockmask; - break; - case SIOCSIFADDR: - printf("SIOCSIFADDR #2\n"); - return in_ifinit(ifp, ia, (struct sockaddr_in*)&ifr->ifr_addr, 1); - case SIOCSIFNETMASK: - printf("Setting netmask\n"); - /* set the netmask for the interface... */ - /* set i to the network netmask (network host order) */ - i = ifra->ifra_addr.sin_addr.s_addr; - /* set the host byte order netmask into ia_subnetmask */ - ia->ia_subnetmask = ntohl((ia->ia_sockmask.sin_addr.s_addr = i)); -printf("ia->ia_subnetmask: %08lx\n", ia->ia_subnetmask); - break; - case SIOCSIFDSTADDR: - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - return EINVAL; - oldaddr = ia->ia_dstaddr; - ia->ia_dstaddr = *(struct sockaddr_in*)&ifr->ifr_dstaddr; - /* update the interface if required */ - if (ifp->ioctl) { - error = ifp->ioctl(ifp, SIOCSIFDSTADDR, (caddr_t) ia); - if (error) { - ia->ia_dstaddr = oldaddr; - return error; - } - } - /* change the routing info if it's been set */ - if (ia->ia_flags & IFA_ROUTE) { - ia->ia_ifa.ifa_dstaddr = (struct sockaddr*)&oldaddr; - rtinit(&(ia->ia_ifa), RTM_DELETE, RTF_HOST); - ia->ia_ifa.ifa_dstaddr = (struct sockaddr*)&ia->ia_dstaddr; - rtinit(&(ia->ia_ifa), RTM_ADD, RTF_HOST|RTF_UP); - } - break; - - case SIOCSIFBRDADDR: - /* set the broadcast address if interface supports it */ - if ((ifp->if_flags & IFF_BROADCAST) == 0) - /* we don't support broadcast on that interface */ - return EINVAL; - ia->ia_broadaddr = *(struct sockaddr_in*) &ifr->ifr_broadaddr; - break; - case SIOCAIFADDR: - maskIsNew = 0; - hostIsNew = 1; - error = 0; - if (ia->ia_addr.sin_family == AF_INET) { - if (ifra->ifra_addr.sin_len == 0) { - ifra->ifra_addr = ia->ia_addr; - hostIsNew = 0; - } else if (ifra->ifra_addr.sin_addr.s_addr == - ia->ia_addr.sin_addr.s_addr) - hostIsNew = 0; - } - if (ifra->ifra_mask.sin_len) { - in_scrubprefix(ia); - ia->ia_sockmask = ifra->ifra_mask; - ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr; - maskIsNew = 1; - } - if ((ifp->if_flags & IFF_POINTOPOINT) && - (ifra->ifra_dstaddr.sin_family == AF_INET)) { - in_scrubprefix(ia); - ia->ia_dstaddr = ifra->ifra_dstaddr; - maskIsNew = 1; - } - if (ifra->ifra_addr.sin_family == AF_INET && - (hostIsNew || maskIsNew)) - error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); - if ((ifp->if_flags & IFF_BROADCAST) && - (ifra->ifra_broadaddr.sin_family == AF_INET)) - ia->ia_broadaddr = ifra->ifra_broadaddr; - return error; - default: - printf("2nd iteration: default (%d)\n", cmd); - /* if we don't have enough to do the default, return */ - if (ifp == NULL || ifp->ioctl == NULL) - return EINVAL; /* XXX - should be EOPNOTSUPP */ - /* send to the card and let it process it */ - return ifp->ioctl(ifp, cmd, data); - } - return 0; -} - - - -/* - * Return 1 if the address might be a local broadcast address. - */ -int in_broadcast(struct in_addr in, struct ifnet *ifp) -{ - struct ifnet *ifn, *if_first, *if_target; - struct ifaddr *ifa; - - if (in.s_addr == INADDR_BROADCAST || - in.s_addr == INADDR_ANY) - return 1; - if (ifp && ((ifp->if_flags & IFF_BROADCAST) == 0)) - return 0; - - if (ifp == NULL) { - if_first = *ifnet_addrs; - if_target = 0; - } else { - if_first = ifp; - if_target = ifp->if_next; - } - -#define ia (ifatoia(ifa)) - /* - * Look through the list of addresses for a match - * with a broadcast address. - * If ifp is NULL, check against all the interfaces. - */ - for (ifn = if_first; ifn != if_target; ifn = ifn->if_next) { - for (ifa = ifn->if_addrlist; ifa; ifa = ifa->ifa_next) { - if (!ifp) { - if (ifa->ifa_addr->sa_family == AF_INET && - ((ia->ia_subnetmask != 0xffffffff && - (((ifn->if_flags & IFF_BROADCAST) && - in.s_addr == ia->ia_broadaddr.sin_addr.s_addr) || - in.s_addr == ia->ia_subnet)) || - /* - * Check for old-style (host 0) broadcast. - */ - (in.s_addr == ia->ia_netbroadcast.s_addr || - in.s_addr == ia->ia_net))) - return 1; - else - if (ifa->ifa_addr->sa_family == AF_INET && - (((ifn->if_flags & IFF_BROADCAST) && - in.s_addr == ia->ia_broadaddr.sin_addr.s_addr) || - in.s_addr == ia->ia_netbroadcast.s_addr || - /* - * Check for old-style (host 0) broadcast. - */ - in.s_addr == ia->ia_subnet || - in.s_addr == ia->ia_net)) - return 1; - } - } - } - return (0); -#undef ia -} - -#ifndef SUBNETSARELOCAL -#define SUBNETSARELOCAL 0 -#endif -int subnetsarelocal = SUBNETSARELOCAL; -/* - * Return 1 if an internet address is for a ``local'' host - * (one to which we have a connection). If subnetsarelocal - * is true, this includes other subnets of the local net. - * Otherwise, it includes only the directly-connected (sub)nets. - */ -int in_localaddr(struct in_addr in) -{ - struct in_ifaddr *ia; - - if (subnetsarelocal) { - for (ia = in_ifaddr; ia != 0; ia = ia->ia_next) - if ((in.s_addr & ia->ia_netmask) == ia->ia_net) - return (1); - } else { - for (ia = in_ifaddr; ia != 0; ia = ia->ia_next) - if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet) - return (1); - } - return (0); -} - -int in_canforward(struct in_addr in) -{ - uint32 i = ntohl(in.s_addr); - uint32 net; - - if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) - return 0; - if (IN_CLASSA(i)) { - net = i & IN_CLASSA_NET; - if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) - return 0; - } - return 1; -} - - diff --git a/src/add-ons/kernel/network/core/inpcb.c b/src/add-ons/kernel/network/core/inpcb.c deleted file mode 100644 index 9309b03143..0000000000 --- a/src/add-ons/kernel/network/core/inpcb.c +++ /dev/null @@ -1,469 +0,0 @@ -/* inpcb.c - * - * implementation of internet control blocks code - */ - -#include - -#ifdef _KERNEL_MODE - #include - #define printf dprintf -#endif - -#include "pools.h" -#include "sys/socketvar.h" -#include "netinet/in.h" -#include "netinet/in_pcb.h" -#include "net/if.h" -#include "netinet/in_var.h" -#include "sys/protosw.h" -#include - -extern struct in_ifaddr *in_ifaddr; - -static struct pool_ctl *pcbpool = NULL; -static struct in_addr zeroin_addr; - -int inetctlerrmap[PRC_NCMDS] = { - 0, 0, 0, 0, - 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, - EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, - EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT -}; - -int inpcb_init(void) -{ - in_ifaddr = NULL; - - if (!pcbpool) - pool_init(&pcbpool, sizeof(struct inpcb)); - - if (!pcbpool) { - printf("inpcb_init: ENOMEM\n"); - return ENOMEM; - } - - zeroin_addr.s_addr = 0; - return 0; -} - -int in_pcballoc(struct socket *so, struct inpcb *head) -{ - struct inpcb *inp; - - inp = (struct inpcb *)pool_get(pcbpool); - - if (!inp) { - printf("in_pcballoc: ENOMEM\n"); - return ENOMEM; - } - - memset(inp, 0, sizeof(*inp)); - - inp->inp_head = head; - /* associate ourselves with the socket */ - inp->inp_socket = so; - insque(inp, head); - so->so_pcb = (caddr_t)inp; - return 0; -} - -void in_pcbdetach(struct inpcb *inp) -{ - struct socket *so = inp->inp_socket; - - so->so_pcb = NULL; - /* BSD sockets would call sofree here - we can't. - * The first thing that sofree does in BSD is check whether - * there are still file system references to the socket - * (SS_NOFDREF) and if there are it doesn't free. We don't have - * the same relationship to our sockets, as we use the socket for - * the kernel cookie, and freeing it here would lead to real problems, - * so we leave the socket until we call socket_close() - * This may need to be reviewed and an extra layer of abstraction - * added at some point if we find it's using too much system resource. - */ - - if (inp->inp_options) - m_free(inp->inp_options); - if (inp->inp_route.ro_rt) - rtfree(inp->inp_route.ro_rt); - - remque(inp); - pool_put(pcbpool, inp); -} - -int in_pcbbind(struct inpcb *inp, struct mbuf *nam) -{ - struct socket *so = inp->inp_socket; - struct inpcb *head = inp->inp_head; - struct sockaddr_in *sin; - uint16 lport = 0; - int wild = 0; - int reuseport = (so->so_options & SO_REUSEPORT); - - if (inp->lport || inp->laddr.s_addr != INADDR_ANY) { - printf("in_pcbbind: EINVAL (%08lx:%d)\n", inp->laddr.s_addr, inp->lport); - return EINVAL; - } - - /* XXX - yuck! Try to format this better */ - /* This basically checks all the options that might be set that allow - * us to use wildcard searches. - */ - if (((so->so_options & (SO_REUSEADDR | SO_REUSEPORT)) == 0) && - ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || - (so->so_options & SO_ACCEPTCONN) == 0)) - wild = INPLOOKUP_WILDCARD; - - if (nam) { - sin = mtod(nam, struct sockaddr_in *); - if (nam->m_len != sizeof(*sin)) { - printf("in_pcbind: EINVAL (m_len = %ld vs %ld)\n", - nam->m_len, sizeof(*sin)); - /* whoops, too much data! */ - return EINVAL; - } - - /* Apparently this may not be correctly - * in older programs, so this may need - * to be commented out... - */ - if (sin->sin_family != AF_INET) { - printf("in_pcbbind: EAFNOSUPPORT\n"); - return EAFNOSUPPORT; - } - - lport = sin->sin_port; - - if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { - /* need special case for multicast. We'll - * allow the complete binding to be duplicated if - * SO_REUSEPORT is set, or if we have - * SO_REUSEADDR set and both sockets have - * a multicast address bound. - * We'll exit with the reuseport variable set - * correctly. - */ - if (so->so_options & SO_REUSEADDR) - reuseport = SO_REUSEADDR | SO_REUSEPORT; - } else if (sin->sin_addr.s_addr != INADDR_ANY) { - sin->sin_port = 0; /* must be zero for next step */ - if (ifa_ifwithaddr((struct sockaddr*)sin) == NULL) { - printf("in_pcbbind: EADDRNOTAVAIL\n"); - return EADDRNOTAVAIL; - } - - } - if (lport) { - struct inpcb *t; - /* we have something to work with... */ - /* XXX - reserved ports have no meaning for us */ - /* XXX - fix me if we ever have multi-user */ - t = in_pcblookup(head, zeroin_addr, 0, - sin->sin_addr, lport, wild); - if (t && (reuseport & t->inp_socket->so_options) == 0) { - printf("in_pcbbind: EADDRINUSE\n"); - return EADDRINUSE; - } - } - inp->laddr = sin->sin_addr; - } - /* if we have an ephemereal port, find a suitable port to use */ - if (lport == 0) { - /* ephemereal port!! */ - do { - if (head->lport++ < IPPORT_RESERVED || - head->lport > IPPORT_USERRESERVED) { - head->lport = IPPORT_RESERVED; - } - lport = htons(head->lport); - } while (in_pcblookup(head, zeroin_addr, 0, - inp->laddr, lport, wild)); - } - - inp->lport = lport; - return 0; -} - -struct inpcb *in_pcblookup(struct inpcb *head, struct in_addr faddr, - uint16 fport_a, struct in_addr laddr, - uint16 lport_a, int flags) -{ - struct inpcb *inp; - struct inpcb *match = NULL; - int matchwild = 3; - int wildcard; - uint16 fport = fport_a; - uint16 lport = lport_a; - - for (inp = head->inp_next; inp != head; inp = inp->inp_next) { - if (inp->lport != lport) - continue; /* local ports don't match */ - wildcard = 0; - /* Here we try to find the best match. wildcard is set to 0 - * and bumped by one every time we find something that doesn't match - * so we can have a suitable match at the end - */ - if (inp->laddr.s_addr != INADDR_ANY) { - if (laddr.s_addr == INADDR_ANY) - wildcard++; - else if (inp->laddr.s_addr != laddr.s_addr) - continue; - } else { - if (laddr.s_addr != INADDR_ANY) - wildcard++; - } - - if (inp->faddr.s_addr != INADDR_ANY) { - if (faddr.s_addr == INADDR_ANY) - wildcard++; - else if (inp->faddr.s_addr != faddr.s_addr || - inp->fport != fport) - continue; - } else { - if (faddr.s_addr != INADDR_ANY) - wildcard++; - } - if (wildcard && ((flags & INPLOOKUP_WILDCARD) == 0)) { - continue; /* wildcard match is not allowed!! */ - } - - if (wildcard < matchwild) { - match = inp; - matchwild = wildcard; - if (matchwild == 0) - break; /* exact match!! */ - } - } - return match; -} - -int in_pcbconnect(struct inpcb *inp, struct mbuf *nam) -{ - struct in_ifaddr *ia = NULL; - struct sockaddr_in *ifaddr = NULL; - struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); - - if (nam->m_len != sizeof(*sin)) { - printf("in_pcbconnect: EINVAL: is %ld should be %ld\n", nam->m_len, - sizeof(*sin)); - return EINVAL; - } - if (sin->sin_family != AF_INET) { - printf("in_pcbconnect: EAFNOSUPPORT (sin_family = %d, not %d)\n", - sin->sin_family, AF_INET); - return EAFNOSUPPORT; - } - if (sin->sin_port == 0) { - printf("in_pcbconnect: EADDRNOTAVAIL\n"); - return EADDRNOTAVAIL; - } - - if (in_ifaddr) { - if (sin->sin_addr.s_addr == INADDR_ANY) - sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; - - /* we need to handle INADDR_BROADCAST here as well */ - - } - - if (inp->laddr.s_addr == INADDR_ANY) { - struct route *ro; - - ro = &inp->inp_route; - - if (ro && ro->ro_rt && - (satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr - || inp->inp_socket->so_options & SO_DONTROUTE)) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } - if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 - && (ro->ro_rt == NULL - || ro->ro_rt->rt_ifp == NULL)) { - /* we don't have a route, try to get one */ - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); - ro->ro_dst.sa_family = AF_INET; - ro->ro_dst.sa_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in*)&ro->ro_dst)->sin_addr = sin->sin_addr; - rtalloc(ro); - } - /* did we find a route?? */ - if (ro->ro_rt && (ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) - ia = ifatoia(ro->ro_rt->rt_ifa); - - if (ia == NULL) { - uint16 fport = sin->sin_port; - - sin->sin_port = 0; - ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin))); - if (ia == NULL) - ia = ifatoia(ifa_ifwithnet(sintosa(sin))); - sin->sin_port = fport; - if (ia == NULL) - ia = in_ifaddr; - if (ia == NULL) { - printf("in_pcbconnect: EADDRNOTAVAIL\n"); - return EADDRNOTAVAIL; - } - } - /* XXX - handle multicast */ - ifaddr = (struct sockaddr_in*) &ia->ia_addr; - } - - if (in_pcblookup(inp->inp_head, sin->sin_addr, sin->sin_port, - inp->laddr.s_addr ? inp->laddr : ifaddr->sin_addr, - inp->lport, 0)) { - printf("in_pcbconnect: EADDRINUSE\n"); - return EADDRINUSE; - } - - if (inp->laddr.s_addr == INADDR_ANY) { - if (inp->lport == 0) - in_pcbbind(inp, NULL); - inp->laddr = ifaddr->sin_addr; - } - inp->faddr = sin->sin_addr; - inp->fport = sin->sin_port; - return 0; -} - -/* XXX - why is this an int? */ -int in_pcbdisconnect(struct inpcb *inp) -{ - inp->faddr.s_addr = INADDR_ANY; - inp->fport = 0; - if (inp->inp_socket->so_state & SS_NOFDREF) - in_pcbdetach(inp); - return 0; -} - -void in_losing(struct inpcb *inp) -{ - struct rtentry *rt; - struct rt_addrinfo info; - - if ((rt = inp->inp_route.ro_rt)) { - inp->inp_route.ro_rt = NULL; - memset(&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = (struct sockaddr*)&inp->inp_route.ro_dst; - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - //rt_missmsg - - if (rt->rt_flags & RTF_DYNAMIC) - rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), - rt->rt_flags, NULL); - else - rtfree(rt); - } -} - -struct rtentry *in_pcbrtentry(struct inpcb *inp) -{ - struct route *ro; - - ro = &inp->inp_route; - - /* - * No route yet, so try to acquire one. - */ - if (ro->ro_rt == NULL) { - memset(ro, 0, sizeof(struct route)); - - if (inp->faddr.s_addr != INADDR_ANY) { - /* this probably isn't needed, but better safe than sorry */ - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); - ro->ro_dst.sa_family = AF_INET; - ro->ro_dst.sa_len = sizeof(ro->ro_dst); - satosin(&ro->ro_dst)->sin_addr = inp->faddr; - rtalloc(ro); - } - } - return (ro->ro_rt); -} - -int inetctlerr(int cmd) -{ - return inetctlerrmap[cmd]; -} - -/* remove the route associated with a control block (if there is one) - * forcing the route to be allocated next time it's used - */ -static void in_rtchange(struct inpcb *inp, int err) -{ - if (inp->inp_route.ro_rt) { - rtfree(inp->inp_route.ro_rt); - inp->inp_route.ro_rt = NULL; - } -} - -void in_pcbnotify(struct inpcb *head, struct sockaddr *dst, - uint16 fport_arg, struct in_addr laddr, - uint16 lport_arg, int cmd, - void (*notify)(struct inpcb *, int)) -{ - struct inpcb *inp, *oinp; - struct in_addr faddr; - uint16 fport = fport_arg, lport = lport_arg; - int err = 0; - - if ((uint)cmd > PRC_NCMDS || dst->sa_family != AF_INET) - return; - faddr = satosin(dst)->sin_addr; - if (faddr.s_addr == INADDR_ANY) - return; - - if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { - fport = lport = 0; - laddr.s_addr = 0; - if (cmd != PRC_HOSTDEAD) - notify = in_rtchange; - } - err = inetctlerrmap[cmd]; - for (inp = head->inp_next; inp != head;) { - if (inp->faddr.s_addr != faddr.s_addr || - inp->inp_socket == NULL || - inp->fport != fport || - inp->lport != lport || - (laddr.s_addr && inp->laddr.s_addr != laddr.s_addr)) { - inp = inp->inp_next; - continue; - } - oinp = inp; - inp = inp->inp_next; - if (notify) - (*notify)(oinp, err); - } -} - -void in_setsockaddr(struct inpcb *inp, struct mbuf *nam) -{ - struct sockaddr_in *sin; - - nam->m_len = sizeof(*sin); - sin = mtod(nam, struct sockaddr_in *); - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_port = inp->lport; - sin->sin_addr = inp->laddr; -} - -void in_setpeeraddr(struct inpcb *inp, struct mbuf *nam) -{ - struct sockaddr_in *sin; - - nam->m_len = sizeof(*sin); - sin = mtod(nam, struct sockaddr_in *); - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_port = inp->fport; - sin->sin_addr = inp->faddr; -} - diff --git a/src/add-ons/kernel/network/core/mbuf.c b/src/add-ons/kernel/network/core/mbuf.c deleted file mode 100644 index b670dbef44..0000000000 --- a/src/add-ons/kernel/network/core/mbuf.c +++ /dev/null @@ -1,530 +0,0 @@ -/* mbuf.c - * network buffer implementation - */ - -#ifndef _KERNEL_MODE -#include -#endif - -#include -#include -#include - -#include "net_misc.h" -#include "pools.h" - -#ifdef _KERNEL_MODE -#include -#endif - -#define MBUF_ALLOCSIZE 4096 - - -struct pool_ctl *mbpool; -struct pool_ctl *clpool; - -int max_hdr = 0; /* largest link+protocol header */ -int max_linkhdr = 0; /* largest link level header */ -int max_protohdr = 0; /* largest protocol header */ - - -void dump_freelist(void) -{ - pool_debug_walk(mbpool); -} - -/* init the mbuf data structures */ -void mbinit(void) -{ - if (!mbpool) - pool_init(&mbpool, sizeof(struct mbuf)); - if (!clpool) - pool_init(&clpool, MCLBYTES); - max_linkhdr = 14; - max_protohdr = 40; - max_hdr = max_linkhdr + max_protohdr; -} - -struct mbuf *m_get(int type) -{ - struct mbuf *mnew; - MGET(mnew, type); - return mnew; -} - -struct mbuf *m_getclr(int type) -{ - struct mbuf *mnew; - MGET(mnew, type); - if (!mnew) - return NULL; - memset(mtod(mnew, char *), 0, MLEN); - return mnew; -} - -struct mbuf *m_gethdr(int type) -{ - struct mbuf *mnew; - MGETHDR(mnew, type); - return mnew; -} - -struct mbuf *m_free(struct mbuf *mfree) -{ - struct mbuf *succ; /* successor if there is one! */ - MFREE(mfree, succ); - return succ; -} - -/* Free the entire chain */ -void m_freem(struct mbuf *m) -{ - struct mbuf *n = NULL; - - if (!m) - return; - do { - MFREE(m, n); -//printf("m_freem(%p, %p)\n", m, n); - } while ((m = n) != NULL); -} - -struct mbuf *m_prepend(struct mbuf *m, int len) -{ - struct mbuf *mnew; - - if (M_LEADINGSPACE(m) >= len) { - m->m_data -= len; - m->m_len += len; - } else { - MGET(mnew, m->m_type); - if (!mnew) { - /* free chain */ - return NULL; - } - if (m->m_flags & M_PKTHDR) - M_MOVE_PKTHDR(mnew, m); - mnew->m_next = m; - m = mnew; - if (len < (int) MHLEN) - MH_ALIGN(m, len); - m->m_len = len; - } - if (m && m->m_flags & M_PKTHDR) - m->m_pkthdr.len += len; - - return m; -} - - -struct mbuf *m_devget(char *buf, int totlen, int off0, - struct ifnet *ifp, - void (*copy)(const void *, void *, size_t)) -{ - struct mbuf *m; - struct mbuf *top = NULL, **mp = ⊤ - int off = off0, len; - char *cp; - char *epkt; - - cp = buf; - epkt = cp + totlen; - if (off) { - /* - * If 'off' is non-zero, packet is trailer-encapsulated, - * so we have to skip the type and length fields. - */ - cp += off + 2 * sizeof(uint16); - totlen -= 2 * sizeof(uint16); - } - MGETHDR(m, MT_DATA); - if (m == NULL) - return (NULL); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = totlen; - m->m_len = MHLEN; - - while (totlen > 0) { - if (top != NULL) { - MGET(m, MT_DATA); - if (m == NULL) { - m_freem(top); - return (NULL); - } - m->m_len = MLEN; - } - len = min(totlen, epkt - cp); - if (len >= (int) MINCLSIZE) { - MCLGET(m); - if (m->m_flags & M_EXT) - m->m_len = len = min(len, MCLBYTES); - else - len = m->m_len; - } else { - /* - * Place initial small packet/header at end of mbuf. - */ - if (len < (int) m->m_len) { - if (top == NULL && - len + max_linkhdr <= (int) m->m_len) - m->m_data += max_linkhdr; - m->m_len = len; - } else - len = m->m_len; - } - if (copy) - copy(cp, mtod(m, void *), (size_t)len); - else - memmove(mtod(m, void *), cp, (size_t)len); - cp += len; - *mp = m; - mp = &m->m_next; - totlen -= len; - if (cp == epkt) - cp = buf; - } - return (top); -} - -void m_reserve(struct mbuf *mp, int len) -{ - if (mp->m_len == 0) { - /* empty buffer! */ - if (mp->m_flags & M_PKTHDR) { - if (len < (int) MHLEN) { - mp->m_data += len; - mp->m_len -= len; - mp->m_pkthdr.len -= len; - return; - } - /* ?? */ - } else { - if (len <= (int) MLEN) { - mp->m_data += len; - mp->m_len -= len; - return; - } - } - } - - if (len > 0) { - if (len <= (int) mp->m_len) { - mp->m_data += len; - mp->m_len -= len; - } - } - if (mp->m_flags & M_PKTHDR) - mp->m_pkthdr.len -= len; -} - -void m_cat(struct mbuf *m, struct mbuf *n) -{ - while (m->m_next) - m = m->m_next; - - while (n) { - if (m->m_flags & M_EXT || - m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { - /* just join them :) */ - m->m_next = n; - return; - } - memcpy((void*)(mtod(m, char *) + m->m_len), mtod(n, void*), n->m_len); - m->m_len += n->m_len; - n = m_free(n); - } -} - -void m_adj(struct mbuf *mp, int req_len) -{ - struct mbuf *m; - int len = req_len, count = 0; - - if ((m = mp) == NULL) - return; - - if (len >= 0) { - /* trim from the head */ - while (m!= NULL && len > 0) { - if ((int) m->m_len <= len) { - /* this whole mbuf isn't enough... */ - len -= m->m_len; - m->m_len = 0; - m = m->m_next; - } else { - /* this mbuf just needs trimming */ - m->m_len -= len; - m->m_data += len; - len = 0; - } - } - m = mp; - if (mp->m_flags & M_PKTHDR) - m->m_pkthdr.len -= (req_len - len); - } else { - /* trim from tail... */ - len = -len; - count = 0; - for (;;) { - count += m->m_len; - if (m->m_next == NULL) - break; - m = m->m_next; - } - if ((int) m->m_len >= len) { - m->m_len -= len; - if (mp->m_flags & M_PKTHDR) - mp->m_pkthdr.len -= len; - return; - } - count -= len; - if (count < 0) - count = 0; - /* The correct length for the chain is now "count". - * find the last mbuf, adjust it's length and toss - * remaining mbufs... - */ - m = mp; /* first mbuf */ - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len = count; - for (; m; m= m->m_next) { - if ((int) m->m_len >= count) { - m->m_len = count; - break; - } - count -= m->m_len; - } - while (m->m_next) - (m = m->m_next)->m_len = 0; - } -} - -void m_copydata(struct mbuf *m, int off, int len, caddr_t cp) -{ - uint count = 0; - - if (off < 0) { - printf("m_copydata: off %d < 0\n", off); - return; - } - if (len < 0) { - printf("m_copydata: len %d < 0\n", len); - return; - } - while (off > 0) { - if (m == NULL) { - printf("m_copydata: null mbuf in skip\n"); - return; - } - if (off < (int) m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - while (len > 0) { - if (m == NULL) { - printf("m_copydata: null mbuf\n"); - return; - } - count = min((int) m->m_len - off, len); - memcpy(cp, (void*)(mtod(m, char *) + off), count); - len -= count; - cp += count; - off = 0; - m = m->m_next; - } -} - -struct mbuf *m_copym(struct mbuf *m, int off0, int len) -{ - struct mbuf *n, **np; - int off = off0; - struct mbuf *top; - int copyhdr = 0; - - if (off < 0 || len < 0) { - printf("PANIC: m_copym: m: off %d, len %d\n", off, len); - return NULL; - } - if (off == 0 && m->m_flags & M_PKTHDR) - copyhdr = 1; - while (off > 0) { - if (!m) { - printf("PANIC: m_copym: null mbuf\n"); - return NULL; - } - if (off < (int) m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - np = ⊤ - top = NULL; - while (len > 0) { - if (!m) { - if (len != M_COPYALL) { - printf("PANIC: m_copym: m == NULL and not COPYALL\n"); - return NULL; - } - break; - } - MGET(n, m->m_type); - *np = n; - if (!n) - goto nospace; - if (copyhdr) { - M_DUP_PKTHDR(n, m); - if (len == M_COPYALL) - n->m_pkthdr.len -= off0; - else - n->m_pkthdr.len = len; - copyhdr = 0; - } - n->m_len = min(len, (int) m->m_len - off); - if (m->m_flags & M_EXT) { - /* - * we are unsure about the way m was allocated. - * copy into multiple MCLBYTES cluster mbufs. - */ - MCLGET(n); - n->m_len = 0; - n->m_len = M_TRAILINGSPACE(n); - n->m_len = min((int) n->m_len, len); - n->m_len = min(n->m_len, m->m_len - off); - memcpy(mtod(n, caddr_t), (void *)(mtod(m, char *) + off), - (unsigned)n->m_len); - } else - memcpy(mtod(n, caddr_t), (void*)(mtod(m, char *)+off), - (unsigned)n->m_len); - if (len != M_COPYALL) - len -= n->m_len; - off += n->m_len; - if (off == (int) m->m_len) { - m = m->m_next; - off = 0; - } - np = &n->m_next; - } - return (top); -nospace: - m_freem(top); - return (NULL); -} - -/* Rearrange an mbuf chain so that len bytes are contiguous - * and in the data area of an mbuf (so that mtod and dtom - * will work for a structure of size len). Returns the resulting - * mbuf chain on success, frees it and returns null on failure. - * If there is room, it will add up to max_protohdr-len extra bytes to the - * contiguous region in an attempt to avoid being called next time. - */ -int MPFail = 0; -struct mbuf *m_pullup(struct mbuf *n, int len) -{ - struct mbuf *m; - int count; - int space; - - if ((int) n->m_len <= len) - return n; - - /* - * If first mbuf has no cluster, and has room for len bytes - * without shifting current data, pullup into it, - * otherwise allocate a new mbuf to prepend to the chain. - */ - if ((n->m_flags & M_EXT) == 0 && - n->m_data + len < &n->m_dat[MLEN] && n->m_next) { - if ((int) n->m_len >= len) - return (n); - m = n; - n = n->m_next; - len -= m->m_len; - } else { - if (len > (int) MHLEN) - goto bad; - MGET(m, n->m_type); - if (m == NULL) - goto bad; - m->m_len = 0; - if (n->m_flags & M_PKTHDR) { - M_MOVE_PKTHDR(m, n); - } - } - space = &m->m_dat[MLEN] - (m->m_data + m->m_len); - do { - count = min(min(max(len, max_protohdr), space), (int) n->m_len); - memcpy((void *)(mtod(m, caddr_t) + m->m_len), mtod(n, void *), (uint)count); - len -= count; - m->m_len += count; - n->m_len -= count; - space -= count; - if (n->m_len) - n->m_data += count; - else - n = m_free(n); - } while (len > 0 && n); - - if (len > 0) { -printf("m_pullup: failed: len = %d\n", len); - (void)m_free(m); - goto bad; - } - m->m_next = n; - return (m); -bad: - m_freem(n); - MPFail++; - return (NULL); -} - -/* - * Copy data from a buffer back into the indicated mbuf chain, - * starting "off" bytes from the beginning, extending the mbuf - * chain if necessary. The mbuf needs to be properly initalized - * including the setting of m_len. - */ -void m_copyback(struct mbuf *m0, int off, int len, caddr_t cp) -{ - int mlen; - struct mbuf *m = m0, *n; - int totlen = 0; - - if (m0 == 0) - return; - while (off > (mlen = m->m_len)) { - off -= mlen; - totlen += mlen; - if (m->m_next == 0) { - n = m_getclr(m->m_type); - if (n == 0) - goto out; - n->m_len = min((int) MLEN, len + off); - m->m_next = n; - } - m = m->m_next; - } - while (len > 0) { - mlen = min ((int) m->m_len - off, len); - memcpy(off + mtod(m, caddr_t), cp, (unsigned)mlen); - cp += mlen; - len -= mlen; - mlen += off; - off = 0; - totlen += mlen; - if (len == 0) - break; - if (m->m_next == 0) { - n = m_get(m->m_type); - if (n == 0) - break; - n->m_len = min((int) MLEN, len); - m->m_next = n; - } - m = m->m_next; - } -out: - if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) - m->m_pkthdr.len = totlen; -} - diff --git a/src/add-ons/kernel/network/core/misc.c b/src/add-ons/kernel/network/core/misc.c deleted file mode 100644 index 27d96dc2b0..0000000000 --- a/src/add-ons/kernel/network/core/misc.c +++ /dev/null @@ -1,60 +0,0 @@ -/* some misc functions... */ - -#include -#include - -#ifdef _KERNEL_MODE -#include -#endif - -#include "net_misc.h" -#include - -/* Basically use dump_ to see the address plus message on a line, - * print_ to simply have the address printed with nothing else... - */ - -void dump_ipv4_addr(char *msg, void *ad) -{ - uint8 *b = (uint8*)ad; - printf("%s %d.%d.%d.%d\n", msg, b[0], b[1], b[2], b[3]); -} - -void print_ipv4_addr(void *ad) -{ - uint8 *b = (uint8*)ad; - printf("%d.%d.%d.%d", b[0], b[1], b[2], b[3]); -} - -void dump_ether_addr(char *msg, void *ea) -{ - uint8 *b = (uint8*)ea; - printf("%s %02x:%02x:%02x:%02x:%02x:%02x\n", msg, - b[0], b[1], b[2], - b[3], b[4], b[5]); -} - -void print_ether_addr(void *ea) -{ - uint8 *b = (uint8*)ea; - printf("%02x:%02x:%02x:%02x:%02x:%02x", - b[0], b[1], b[2], - b[3], b[4], b[5]); -} - -void dump_buffer(char *buffer, int len) -{ - uint8 *b = (uint8 *)buffer; - int i; - - printf (" "); - for (i=0;i -#include -#include - -#include "net_timer.h" - - - -struct timer_entry { - struct timer_entry *te_next; - net_timer_hook te_hook; - void *te_data; - bigtime_t te_interval; - bigtime_t te_until; - net_timer_id te_id; -}; - -struct timer_info { - struct timer_entry *ti_first; - - sem_id ti_lock; - sem_id ti_wait; - int32 ti_counter; - volatile int32 ti_inUse; -}; - -int32 net_timer(void *_data); - -struct timer_info gTimerInfo; - -status_t -net_init_timer(void) -{ - thread_id thread; - - memset(&gTimerInfo,0,sizeof(struct timer_info)); - - gTimerInfo.ti_lock = create_sem(1,"net timer lock"); - if (gTimerInfo.ti_lock < B_OK) - return B_ERROR; - - gTimerInfo.ti_wait = create_sem(0,"net timer wait"); - if (gTimerInfo.ti_wait < B_OK) - return B_ERROR; - -#ifdef _KERNEL_MODE - set_sem_owner(gTimerInfo.ti_lock, B_SYSTEM_TEAM); - set_sem_owner(gTimerInfo.ti_wait, B_SYSTEM_TEAM); -#endif - - thread = spawn_kernel_thread(net_timer, "net timer", B_NORMAL_PRIORITY, &gTimerInfo); - if (thread < B_OK) - return thread; - - return resume_thread(thread); -} - - -void -net_shutdown_timer(void) -{ - struct timer_entry *te,*next; - int32 tries = 20; - - delete_sem(gTimerInfo.ti_wait); - delete_sem(gTimerInfo.ti_lock); - gTimerInfo.ti_wait = -1; - gTimerInfo.ti_lock = -1; - - // make sure the structure isn't used anymore - while (gTimerInfo.ti_inUse != 0 && tries-- > 0) - snooze(1000); - - // free the remaining timer entries - for (te = gTimerInfo.ti_first;te;te = next) { - next = te->te_next; - free(te); - } -} - - -int32 -net_timer(void *_data) -{ - struct timer_info *timer = (struct timer_info *)_data; - status_t status = B_OK; - - do { - bigtime_t timeout = B_INFINITE_TIMEOUT; - struct timer_entry *te; - - // get access to the info structure - if (status == B_TIMED_OUT || status == B_OK) { - if (acquire_sem(timer->ti_lock) == B_OK) { - for (te = timer->ti_first;te;te = te->te_next) { - // new entry? - if (te->te_until == -1) - te->te_until = system_time() + te->te_interval; - - // execute timer? - if (te->te_until < system_time()) { - te->te_until += te->te_interval; - te->te_hook(te->te_data); - } - - // calculate new timeout - if (te->te_until < timeout) - timeout = te->te_until; - } - - release_sem(timer->ti_lock); - } - } - - status = acquire_sem_etc(timer->ti_wait,1,B_ABSOLUTE_TIMEOUT,timeout); - // the wait sem normally can't be acquired, so we - // have to look at the status value the call returns: - // - // B_OK - someone wanted to notify us - // B_TIMED_OUT - look for timers to be executed - // B_BAD_SEM_ID - our sem got deleted - - } while (status != B_BAD_SEM_ID); - - return 0; -} - - -net_timer_id -net_add_timer(net_timer_hook hook,void *data,bigtime_t interval) -{ - struct timer_entry *te; - status_t status; - - if (interval < 100) - return B_BAD_VALUE; - - atomic_add(&gTimerInfo.ti_inUse,1); - - // get access to the timer info structure - status = acquire_sem(gTimerInfo.ti_lock); - if (status < B_OK) { - atomic_add(&gTimerInfo.ti_inUse,-1); - return status; - } - - te = (struct timer_entry *)malloc(sizeof(struct timer_entry)); - if (te == NULL) { - atomic_add(&gTimerInfo.ti_inUse,-1); - release_sem(gTimerInfo.ti_lock); - return B_NO_MEMORY; - } - - te->te_hook = hook; - te->te_data = data; - te->te_interval = interval; - te->te_until = -1; - te->te_id = ++gTimerInfo.ti_counter; - - // add the new entry - te->te_next = gTimerInfo.ti_first; - gTimerInfo.ti_first = te; - - atomic_add(&gTimerInfo.ti_inUse,-1); - release_sem(gTimerInfo.ti_lock); - - // notify timer about the change - release_sem(gTimerInfo.ti_wait); - - return te->te_id; -} - - -status_t -net_remove_timer(net_timer_id id) -{ - struct timer_entry *te,*last; - status_t status; - - if (id <= B_OK) - return B_BAD_VALUE; - - atomic_add(&gTimerInfo.ti_inUse,1); - - // get access to the timer info structure - status = acquire_sem(gTimerInfo.ti_lock); - if (status < B_OK) { - atomic_add(&gTimerInfo.ti_inUse,-1); - return status; - } - - // search the list for the right timer - - // little hack that relies on ti_first being on the same position - // in the structure as te_next - last = (struct timer_entry *)&gTimerInfo; - for (te = gTimerInfo.ti_first;te;te = te->te_next) { - if (te->te_id == id) { - last->te_next = te->te_next; - free(te); - break; - } - last = te; - } - atomic_add(&gTimerInfo.ti_inUse,-1); - release_sem(gTimerInfo.ti_lock); - - if (te == NULL) - return B_ENTRY_NOT_FOUND; - - // notify timer about the change - release_sem(gTimerInfo.ti_wait); - - return B_OK; -} - diff --git a/src/add-ons/kernel/network/core/nhash.c b/src/add-ons/kernel/network/core/nhash.c deleted file mode 100644 index 08f234bb43..0000000000 --- a/src/add-ons/kernel/network/core/nhash.c +++ /dev/null @@ -1,157 +0,0 @@ -/* nhash.c - * net hash - */ - -#include -#include - -#include "net_malloc.h" -#include "nhash.h" - -#define MAX_INITIAL 15; - - -net_hash_index *nhash_next(net_hash_index *hi); -net_hash_index *nhash_first(net_hash *nh); -void nhash_this(net_hash_index *hi, const void **key, ssize_t *klen, - void **val); - - -net_hash *nhash_make(void) -{ - net_hash *nn; - - nn = (net_hash *)malloc(sizeof(net_hash)); - - if (!nn) - return NULL; - - nn->count = 0; - nn->max = MAX_INITIAL; - - nn->array = (net_hash_entry **)malloc(sizeof(net_hash_entry) * (nn->max + 1)); - memset(nn->array, 0, sizeof(net_hash_entry) * (nn->max +1)); - pool_init(&nn->pool, sizeof(net_hash_entry)); - if (!nn->pool) - return NULL; - return nn; -} - -net_hash_index *nhash_next(net_hash_index *hi) -{ - hi->this = hi->next; - while (!hi->this) { - if (hi->index > hi->nh->max) - return NULL; - hi->this = hi->nh->array[hi->index++]; - } - hi->next = hi->this->next; - return hi; -} - -net_hash_index *nhash_first(net_hash *nh) -{ - net_hash_index *hi = &nh->iterator; - hi->nh = nh; - hi->index = 0; - hi->this = hi->next = NULL; - return nhash_next(hi); -} - -static void expand_array(net_hash *nh) -{ - net_hash_index *hi; - net_hash_entry **new_array; - int new_max = nh->max * 2 +1; - int i; - - new_array = (net_hash_entry **)malloc(sizeof(net_hash_entry) * new_max); - memset(new_array, 0, sizeof(net_hash_entry) * new_max); - for (hi = nhash_first(nh); hi; hi = nhash_next(hi)) { - i = hi->this->hash & new_max; - hi->this->next = new_array[i]; - new_array[i] = hi->this; - } - free(nh->array); - nh->array = new_array; - nh->max = new_max; -} - -void nhash_this(net_hash_index *hi, const void **key, ssize_t *klen, - void **val) -{ - if (key) *key = hi->this->key; - if (klen) *klen = hi->this->klen; - if (val) *val = (void*)hi->this->val; -} - -static net_hash_entry **find_entry(net_hash *nh, const void *key, - ssize_t klen, const void *val) -{ - net_hash_entry **hep; - net_hash_entry *he; - const unsigned char *p; - int hash = 0; - ssize_t i; - - if (!nh) - return NULL; - - for (p=key, i=klen; i; i--, p++) - hash = hash * 33 + *p; - - for (hep = &nh->array[hash & nh->max], he = *hep; he; - hep = &he->next, he = *hep) { - if (he->hash == hash && he->klen == klen - && memcmp(he->key, key, klen) == 0) { - break; - } - } - - if (he || !val) - return hep; - - /* add a new linked-list entry */ - he = (net_hash_entry *)pool_get(nh->pool); - he->next = NULL; - he->hash = hash; - he->key = key; - he->klen = klen; - he->val = val; - *hep = he; - nh->count++; - return hep; -} - -void *nhash_get(net_hash *nh, const void *key, ssize_t klen) -{ - net_hash_entry *he; - he = *find_entry(nh, key, klen, NULL); - if (he) - return (void*)he->val; - else - return NULL; -} - -void nhash_set(net_hash *nh, const void *key, ssize_t klen, const void *val) -{ - net_hash_entry **hep; - net_hash_entry *old; - hep = find_entry(nh, key, klen, val); - - if (*hep) { - if (!val) { - /* delete it */ - old = *hep; - *hep = (*hep)->next; - --nh->count; - pool_put(nh->pool, old); - } else { - /* replace it */ - (*hep)->val = val; - if (nh->count > nh->max) - expand_array(nh); - } - } -} - diff --git a/src/add-ons/kernel/network/core/pools.c b/src/add-ons/kernel/network/core/pools.c deleted file mode 100644 index 398ab8518d..0000000000 --- a/src/add-ons/kernel/network/core/pools.c +++ /dev/null @@ -1,324 +0,0 @@ -/* pools.c */ - -#include -#include -#include -#include "pools.h" -#include "net_misc.h" -#include "net_malloc.h" - -#ifdef _KERNEL_MODE -#include -#define AREA_ADDR_FLAG B_ANY_KERNEL_ADDRESS -#define AREA_FLAGS B_NO_LOCK -#else -#define AREA_ADDR_FLAG B_ANY_ADDRESS -#define AREA_FLAGS B_FULL_LOCK -#endif - -static sem_id init_sem = -1; - -#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) - -#ifdef WALK_POOL_LIST -void walk_pool_list(struct pool_ctl *p) -{ - struct pool_mem *pb = p->list; - - printf("Pool: %p\n", p); - printf(" -> list = %p\n", pb); - while (pb) { - printf(" -> mem_block %p, %p\n", pb, pb->next); - pb = pb->next; - } -} -#endif - -void pool_debug_walk(struct pool_ctl *p) -{ - char *ptr; - int i = 1; - - printf("%ld byte blocks allocated, but now free:\n\n", p->alloc_size); - - #if POOL_USES_BENAPHORES - ACQUIRE_BENAPHORE(p->lock); - #else - ACQUIRE_READ_LOCK(p->lock); - #endif - ptr = p->freelist; - while (ptr) { - printf(" %02d: %p\n", i++, ptr); - ptr = ((struct free_blk*)ptr)->next; - } - #if POOL_USES_BENAPHORES - RELEASE_BENAPHORE(p->lock); - #else - RELEASE_READ_LOCK(p->lock); - #endif -} - -void pool_debug(struct pool_ctl *p, char *name) -{ - p->debug = 1; - if (strlen(name) < POOL_DEBUG_NAME_SZ) - strncpy(p->name, name, strlen(name)); - else - strncpy(p->name, name, POOL_DEBUG_NAME_SZ); -} - -static struct pool_mem *get_mem_block(struct pool_ctl *pool) -{ - struct pool_mem *block; - - block = (struct pool_mem *)malloc(sizeof(struct pool_mem)); - if (block == NULL) - return NULL; - - memset(block, 0, sizeof(*block)); - - block->aid = create_area("net_stack_pools_block", - (void**)&block->base_addr, - AREA_ADDR_FLAG, pool->block_size, - AREA_FLAGS, - B_READ_AREA|B_WRITE_AREA); - if (block->aid < B_OK) { - free(block); - return NULL; - } - - block->mem_size = block->avail = pool->block_size; - block->ptr = block->base_addr; - INIT_BENAPHORE(block->lock, "pool_mem_lock"); - - if (CHECK_BENAPHORE(block->lock) >= B_OK) { - #if POOL_USES_BENAPHORES - ACQUIRE_BENAPHORE(pool->lock); - #else - ACQUIRE_WRITE_LOCK(pool->lock); - #endif - - // insert block at the beginning of the pools - if (pool->list) - block->next = pool->list; - - pool->list = block; - -#ifdef WALK_POOL_LIST - walk_pool_list(pool); -#endif - - #if POOL_USES_BENAPHORES - RELEASE_BENAPHORE(pool->lock); - #else - RELEASE_WRITE_LOCK(pool->lock); - #endif - - return block; - } - UNINIT_BENAPHORE(block->lock); - - delete_area(block->aid); - free(block); - - return NULL; -} - - -status_t pool_init(struct pool_ctl **_newPool, size_t size) -{ - struct pool_ctl *pool = NULL; - - if (init_sem == -1) - create_sem(1, "pool_init_sem"); - - /* minimum block size is sizeof the free_blk structure */ - if (size < sizeof(struct free_blk)) - return B_BAD_VALUE; - -// acquire_sem_etc(init_sem, 1, B_CAN_INTERRUPT, 0); - - pool = (struct pool_ctl*)malloc(sizeof(struct pool_ctl)); - if (pool == NULL) - return B_NO_MEMORY; - - memset(pool, 0, sizeof(*pool)); - - #if POOL_USES_BENAPHORES - INIT_BENAPHORE(pool->lock, "pool_lock"); - if (CHECK_BENAPHORE(pool->lock) < B_OK) { - free(pool); - return B_ERROR; - } - #else - INIT_RW_LOCK(pool->lock, "pool_lock"); - if (CHECK_RW_LOCK(pool->lock) < B_OK) { - free(pool); - return B_ERROR; - } - #endif - - // 4 puddles will always fit in one pool - pool->block_size = ROUND_TO_PAGE_SIZE(size * 8); - pool->alloc_size = size; - pool->list = NULL; - pool->freelist = NULL; - - /* now add a first block */ - get_mem_block(pool); - if (!pool->list) { - #if POOL_USES_BENAPHORES - UNINIT_BENAPHORE(pool->lock); - #else - UNINIT_RW_LOCK(pool->lock); - #endif - free(pool); - return B_NO_MEMORY; - } - - *_newPool = pool; - -// release_sem_etc(init_sem, 1, B_CAN_INTERRUPT); - return B_OK; -} - - -char *pool_get(struct pool_ctl *p) -{ - /* ok, so now we look for a suitable block... */ - struct pool_mem *mp = p->list; - char *rv = NULL; - - #if POOL_USES_BENAPHORES - ACQUIRE_BENAPHORE(p->lock); - #else - ACQUIRE_WRITE_LOCK(p->lock); - #endif - - if (p->freelist) { - /* woohoo, just grab a block! */ - - rv = p->freelist; - - if (p->debug) - printf("%s: allocating %p, setting freelist to %p\n", - p->name, p->freelist, - ((struct free_blk*)rv)->next); - - p->freelist = ((struct free_blk*)rv)->next; - - #if POOL_USES_BENAPHORES - RELEASE_BENAPHORE(p->lock); - #else - RELEASE_WRITE_LOCK(p->lock); - #endif - - memset(rv, 0, p->alloc_size); - return rv; - } - #if !POOL_USES_BENAPHORES - RELEASE_WRITE_LOCK(p->lock); - ACQUIRE_READ_LOCK(p->lock); - #endif - - /* no free blocks, try to allocate of the top of the memory blocks - ** we must hold the global pool lock while iterating through the list! - */ - - do { - ACQUIRE_BENAPHORE(mp->lock); - - if (mp->avail >= p->alloc_size) { - rv = mp->ptr; - mp->ptr += p->alloc_size; - mp->avail -= p->alloc_size; - RELEASE_BENAPHORE(mp->lock); - break; - } - RELEASE_BENAPHORE(mp->lock); - } while ((mp = mp->next) != NULL); - - #if POOL_USES_BENAPHORES - RELEASE_BENAPHORE(p->lock); - #else - RELEASE_READ_LOCK(p->lock); - #endif - - if (rv) { - memset(rv, 0, p->alloc_size); - return rv; - } - - mp = get_mem_block(p); - if (mp == NULL) - return NULL; - - ACQUIRE_BENAPHORE(mp->lock); - - if (mp->avail >= p->alloc_size) { - rv = mp->ptr; - mp->ptr += p->alloc_size; - mp->avail -= p->alloc_size; - } - RELEASE_BENAPHORE(mp->lock); - - memset(rv, 0, p->alloc_size); - return rv; -} - - -void pool_put(struct pool_ctl *p, void *ptr) -{ - #if POOL_USES_BENAPHORES - ACQUIRE_BENAPHORE(p->lock); - #else - ACQUIRE_WRITE_LOCK(p->lock); - #endif - - memset(ptr, 0, p->alloc_size); - ((struct free_blk*)ptr)->next = p->freelist; - - if (p->debug) { - printf("%s: adding %p, setting next = %p\n", - p->name, ptr, p->freelist); - } - - p->freelist = ptr; - - if (p->debug) - printf("%s: freelist = %p\n", p->name, p->freelist); - - #if POOL_USES_BENAPHORES - RELEASE_BENAPHORE(p->lock); - #else - RELEASE_WRITE_LOCK(p->lock); - #endif -} - - -void pool_destroy(struct pool_ctl *p) -{ - struct pool_mem *mp,*temp; - - if (p == NULL) - return; - - /* the semaphore will be deleted, so we don't have to unlock */ - ACQUIRE_WRITE_LOCK(p->lock); - - mp = p->list; - while (mp != NULL) { - delete_area(mp->aid); - temp = mp; - mp = mp->next; - UNINIT_BENAPHORE(mp->lock); - free(temp); - } - - #if POOL_USES_BENAPHORES - UNINIT_BENAPHORE(p->lock); - #else - UNINIT_RW_LOCK(p->lock); - #endif - free(p); -} diff --git a/src/add-ons/kernel/network/core/radix.c b/src/add-ons/kernel/network/core/radix.c deleted file mode 100644 index 3cd6e61bea..0000000000 --- a/src/add-ons/kernel/network/core/radix.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * Copyright (c) 1988, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)radix.c 8.4 (Berkeley) 11/2/94 - * $FreeBSD: src/sys/net/radix.c,v 1.20.2.2 2001/03/06 00:56:50 obrien Exp $ - */ - -#include -#include -#include -#include - -#include "net_malloc.h" - -#include "netinet/in.h" - -#ifdef _KERNEL_MODE -#include -#endif - -/* - * Routines to build and maintain radix trees for routing lookups. - */ -#ifndef _RADIX_H_ -#define M_DONTWAIT M_NOWAIT -#include -#include "net/radix.h" -#endif - -#include "sys/domain.h" - -static int rn_walktree_from (struct radix_node_head *h, void *a, - void *m, walktree_f_t *f, void *w); -static int rn_walktree (struct radix_node_head *, walktree_f_t *, void *); -static struct radix_node - *rn_insert (void *, struct radix_node_head *, int *, - struct radix_node [2]), - *rn_newpair (void *, int, struct radix_node[2]), - *rn_search (void *, struct radix_node *), - *rn_search_m (void *, struct radix_node *, void *); - -static int max_keylen; -static struct radix_mask *rn_mkfreelist; -static struct radix_node_head *mask_rnhead; -static char *addmask_key; -static char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, -1}; -static char *rn_zeros, *rn_ones; - -#define rn_masktop (mask_rnhead->rnh_treetop) -/* -#undef Bcmp -#define Bcmp(a, b, l) \ - (l == 0 ? 0 : memcpy((caddr_t)(a), (caddr_t)(b), (u_long)l)) -*/ - -static int rn_lexobetter (void *m_arg, void *n_arg); -static struct radix_mask * - rn_new_radix_mask (struct radix_node *tt, - struct radix_mask *next); -static int rn_satsifies_leaf (char *trial, struct radix_node *leaf, - int skip); - -struct radix_node *rn_head_search(void *arg_v) -{ - return rn_search(arg_v, mask_rnhead->rnh_treetop); -} - -/* - * The data structure for the keys is a radix tree with one way - * branching removed. The index rn_bit at an internal node n represents a bit - * position to be tested. The tree is arranged so that all descendants - * of a node n have keys whose bits all agree up to position rn_bit - 1. - * (We say the index of n is rn_bit.) - * - * There is at least one descendant which has a one bit at position rn_bit, - * and at least one with a zero there. - * - * A route is determined by a pair of key and mask. We require that the - * bit-wise logical and of the key and mask to be the key. - * We define the index of a route to associated with the mask to be - * the first bit number in the mask where 0 occurs (with bit number 0 - * representing the highest order bit). - * - * We say a mask is normal if every bit is 0, past the index of the mask. - * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit, - * and m is a normal mask, then the route applies to every descendant of n. - * If the index(m) < rn_bit, this implies the trailing last few bits of k - * before bit b are all 0, (and hence consequently true of every descendant - * of n), so the route applies to all descendants of the node as well. - * - * Similar logic shows that a non-normal mask m such that - * index(m) <= index(n) could potentially apply to many children of n. - * Thus, for each non-host route, we attach its mask to a list at an internal - * node as high in the tree as we can go. - * - * The present version of the code makes use of normal routes in short- - * circuiting an explict mask and compare operation when testing whether - * a key satisfies a normal route, and also in remembering the unique leaf - * that governs a subtree. - */ - -static struct radix_node * -rn_search(v_arg, head) - void *v_arg; - struct radix_node *head; -{ - register struct radix_node *x; - register caddr_t v; - - for (x = head, v = v_arg; x->rn_bit >= 0;) { - if (x->rn_bmask & v[x->rn_offset]) - x = x->rn_right; - else - x = x->rn_left; - } - return (x); -} - -static struct radix_node * -rn_search_m(v_arg, head, m_arg) - struct radix_node *head; - void *v_arg, *m_arg; -{ - register struct radix_node *x; - register caddr_t v = v_arg, m = m_arg; - - for (x = head; x->rn_bit >= 0;) { - if ((x->rn_bmask & m[x->rn_offset]) && - (x->rn_bmask & v[x->rn_offset])) - x = x->rn_right; - else - x = x->rn_left; - } - return x; -} - -int -rn_refines(m_arg, n_arg) - void *m_arg, *n_arg; -{ - register caddr_t m = m_arg, n = n_arg; - register caddr_t lim, lim2 = lim = n + *(u_char *)n; - int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); - int masks_are_equal = 1; - - if (longer > 0) - lim -= longer; - while (n < lim) { - if (*n & ~(*m)) - return 0; - if (*n++ != *m++) - masks_are_equal = 0; - } - while (n < lim2) - if (*n++) - return 0; - if (masks_are_equal && (longer < 0)) - for (lim2 = m - longer; m < lim2; ) - if (*m++) - return 1; - return (!masks_are_equal); -} - -struct radix_node * -rn_lookup(v_arg, m_arg, head) - void *v_arg, *m_arg; - struct radix_node_head *head; -{ - register struct radix_node *x; - caddr_t netmask = 0; - - if (m_arg) { - x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset); - if (x == 0) - return (0); - netmask = x->rn_key; - } - x = rn_match(v_arg, head); - if (x && netmask) { - while (x && x->rn_mask != netmask) - x = x->rn_dupedkey; - } - return x; -} - -static int -rn_satsifies_leaf(trial, leaf, skip) - char *trial; - register struct radix_node *leaf; - int skip; -{ - register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; - char *cplim; - int length = min(*(u_char *)cp, *(u_char *)cp2); - - if (cp3 == 0) - cp3 = rn_ones; - else - length = min(length, *(u_char *)cp3); - cplim = cp + length; cp3 += skip; cp2 += skip; - for (cp += skip; cp < cplim; cp++, cp2++, cp3++) - if ((*cp ^ *cp2) & *cp3) - return 0; - return 1; -} - -struct radix_node * -rn_match(v_arg, head) - void *v_arg; - struct radix_node_head *head; -{ - caddr_t v = v_arg; - register struct radix_node *t = head->rnh_treetop, *x; - register caddr_t cp = v, cp2; - caddr_t cplim; - struct radix_node *saved_t, *top = t; - int off = t->rn_offset, vlen = *(u_char *)cp, matched_off; - register int test, b, rn_bit; - - /* - * Open code rn_search(v, top) to avoid overhead of extra - * subroutine call. - */ - for (; t->rn_bit >= 0; ) { - if (t->rn_bmask & cp[t->rn_offset]) - t = t->rn_right; - else - t = t->rn_left; - } - /* - * See if we match exactly as a host destination - * or at least learn how many bits match, for normal mask finesse. - * - * It doesn't hurt us to limit how many bytes to check - * to the length of the mask, since if it matches we had a genuine - * match and the leaf we have is the most specific one anyway; - * if it didn't match with a shorter length it would fail - * with a long one. This wins big for class B&C netmasks which - * are probably the most common case... - */ - if (t->rn_mask) - vlen = *(u_char *)t->rn_mask; - cp += off; cp2 = t->rn_key + off; cplim = v + vlen; - for (; cp < cplim; cp++, cp2++) - if (*cp != *cp2) - goto on1; - /* - * This extra grot is in case we are explicitly asked - * to look up the default. Ugh! - * - * Never return the root node itself, it seems to cause a - * lot of confusion. - */ - if (t->rn_flags & RNF_ROOT) - t = t->rn_dupedkey; - return t; -on1: - test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */ - for (b = 7; (test >>= 1) > 0;) - b--; - matched_off = cp - v; - b += matched_off << 3; - rn_bit = -1 - b; - /* - * If there is a host route in a duped-key chain, it will be first. - */ - if ((saved_t = t)->rn_mask == 0) - t = t->rn_dupedkey; - for (; t; t = t->rn_dupedkey) - /* - * Even if we don't match exactly as a host, - * we may match if the leaf we wound up at is - * a route to a net. - */ - if (t->rn_flags & RNF_NORMAL) { - if (rn_bit <= t->rn_bit) - return t; - } else if (rn_satsifies_leaf(v, t, matched_off)) - return t; - t = saved_t; - /* start searching up the tree */ - do { - register struct radix_mask *m; - t = t->rn_parent; - m = t->rn_mklist; - /* - * If non-contiguous masks ever become important - * we can restore the masking and open coding of - * the search and satisfaction test and put the - * calculation of "off" back before the "do". - */ - while (m) { - if (m->rm_flags & RNF_NORMAL) { - if (rn_bit <= m->rm_bit) - return (m->rm_leaf); - } else { - off = min(t->rn_offset, matched_off); - x = rn_search_m(v, t, m->rm_mask); - while (x && x->rn_mask != m->rm_mask) - x = x->rn_dupedkey; - if (x && rn_satsifies_leaf(v, x, off)) - return x; - } - m = m->rm_mklist; - } - } while (t != top); - return 0; -} - -#ifdef RN_DEBUG -int rn_nodenum; -struct radix_node *rn_clist; -int rn_saveinfo; -int rn_debug = 1; -#endif - -static struct radix_node * -rn_newpair(v, b, nodes) - void *v; - int b; - struct radix_node nodes[2]; -{ - register struct radix_node *tt = nodes, *t = tt + 1; - t->rn_bit = b; - t->rn_bmask = 0x80 >> (b & 7); - t->rn_left = tt; - t->rn_offset = b >> 3; - tt->rn_bit = -1; - tt->rn_key = (caddr_t)v; - tt->rn_parent = t; - tt->rn_flags = t->rn_flags = RNF_ACTIVE; - tt->rn_mklist = t->rn_mklist = 0; -#ifdef RN_DEBUG - tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; - tt->rn_twin = t; - tt->rn_ybro = rn_clist; - rn_clist = tt; -#endif - return t; -} - -static struct radix_node * -rn_insert(v_arg, head, dupentry, nodes) - void *v_arg; - struct radix_node_head *head; - int *dupentry; - struct radix_node nodes[2]; -{ - caddr_t v = v_arg; - struct radix_node *top = head->rnh_treetop; - int head_off = top->rn_offset, vlen = (int)*((u_char *)v); - register struct radix_node *t = rn_search(v_arg, top); - register caddr_t cp = v + head_off; - register int b; - struct radix_node *tt; - /* - * Find first bit at which v and t->rn_key differ - */ - { - register caddr_t cp2 = t->rn_key + head_off; - register int cmp_res; - caddr_t cplim = v + vlen; - - while (cp < cplim) - if (*cp2++ != *cp++) - goto on1; - *dupentry = 1; - return t; -on1: - *dupentry = 0; - cmp_res = (cp[-1] ^ cp2[-1]) & 0xff; - for (b = (cp - v) << 3; cmp_res; b--) - cmp_res >>= 1; - } - { - register struct radix_node *p, *x = top; - cp = v; - do { - p = x; - if (cp[x->rn_offset] & x->rn_bmask) - x = x->rn_right; - else - x = x->rn_left; - } while (b > x->rn_bit && x->rn_bit >= 0); -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p); -#endif - t = rn_newpair(v_arg, b, nodes); - tt = t->rn_left; - if ((cp[p->rn_offset] & p->rn_bmask) == 0) - p->rn_left = t; - else - p->rn_right = t; - x->rn_parent = t; - t->rn_parent = p; /* frees x, p as temp vars below */ - if ((cp[t->rn_offset] & t->rn_bmask) == 0) { - t->rn_right = x; - } else { - t->rn_right = tt; - t->rn_left = x; - } -#ifdef RN_DEBUG - if (rn_debug) - log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p); -#endif - } - return (tt); -} - -struct radix_node * -rn_addmask(n_arg, search, skip) - int search, skip; - void *n_arg; -{ - caddr_t netmask = (caddr_t)n_arg; - register struct radix_node *x; - register caddr_t cp, cplim; - register int b = 0, mlen, j; - int maskduplicated, m0, isnormal; - struct radix_node *saved_x; - static int last_zeroed = 0; - - if ((mlen = *(u_char *)netmask) > max_keylen) - mlen = max_keylen; - if (skip == 0) - skip = 1; - if (mlen <= skip) - return (mask_rnhead->rnh_nodes); - if (skip > 1) - Bcopy(rn_ones + 1, addmask_key + 1, skip - 1); - - if ((m0 = mlen) > skip) - Bcopy(netmask + skip, addmask_key + skip, mlen - skip); - - /* - * Trim trailing zeroes. - */ - for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;) - cp--; - mlen = cp - addmask_key; - - if (mlen <= skip) { - if (m0 >= last_zeroed) - last_zeroed = mlen; - return (mask_rnhead->rnh_nodes); - } - if (m0 < last_zeroed) - Bzero(addmask_key + m0, last_zeroed - m0); - *addmask_key = last_zeroed = mlen; - - x = rn_search(addmask_key, rn_masktop); - if (memcmp(addmask_key, x->rn_key, mlen) != 0) - x = NULL; - if (x || search) - return (x); - R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x)); - if ((saved_x = x) == 0) - return (0); - Bzero(x, max_keylen + 2 * sizeof (*x)); - netmask = cp = (caddr_t)(x + 2); - Bcopy(addmask_key, cp, mlen); - - x = rn_insert(cp, mask_rnhead, &maskduplicated, x); - if (maskduplicated) { - printf("rn_addmask: mask impossibly already in tree\n"); - Free(saved_x); - return (x); - } - /* - * Calculate index of mask, and check for normalcy. - */ - cplim = netmask + mlen; isnormal = 1; - for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;) - cp++; - if (cp != cplim) { - for (j = 0x80; (j & *cp) != 0; j >>= 1) - b++; - if (*cp != normal_chars[b] || cp != (cplim - 1)) - isnormal = 0; - } - b += (cp - netmask) << 3; - x->rn_bit = -1 - b; - if (isnormal) - x->rn_flags |= RNF_NORMAL; - return (x); -} - -static int /* XXX: arbitrary ordering for non-contiguous masks */ -rn_lexobetter(m_arg, n_arg) - void *m_arg, *n_arg; -{ - register u_char *mp = m_arg, *np = n_arg, *lim; - - if (*mp > *np) - return 1; /* not really, but need to check longer one first */ - if (*mp == *np) - for (lim = mp + *mp; mp < lim;) - if (*mp++ > *np++) - return 1; - return 0; -} - -static struct radix_mask * -rn_new_radix_mask(tt, next) - register struct radix_node *tt; - register struct radix_mask *next; -{ - register struct radix_mask *m; - - MKGet(m); - if (m == 0) { - printf("Mask for route not entered\n"); - return (0); - } - Bzero(m, sizeof *m); - m->rm_bit = tt->rn_bit; - m->rm_flags = tt->rn_flags; - if (tt->rn_flags & RNF_NORMAL) - m->rm_leaf = tt; - else - m->rm_mask = tt->rn_mask; - m->rm_mklist = next; - tt->rn_mklist = m; - return m; -} - -struct radix_node * -rn_addroute(v_arg, n_arg, head, treenodes) - void *v_arg, *n_arg; - struct radix_node_head *head; - struct radix_node treenodes[2]; -{ - caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; - register struct radix_node *t, *x = 0, *tt; - struct radix_node *saved_tt, *top = head->rnh_treetop; - short b = 0, b_leaf = 0; - int keyduplicated; - caddr_t mmask; - struct radix_mask *m, **mp; - - /* - * In dealing with non-contiguous masks, there may be - * many different routes which have the same mask. - * We will find it useful to have a unique pointer to - * the mask to speed avoiding duplicate references at - * nodes and possibly save time in calculating indices. - */ - if (netmask) { - if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0) - return (0); - b_leaf = x->rn_bit; - b = -1 - x->rn_bit; - netmask = x->rn_key; - } - /* - * Deal with duplicated keys: attach node to previous instance - */ - saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes); - if (keyduplicated) { - for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) { - if (tt->rn_mask == netmask) - return (0); - if (netmask == 0 || - (tt->rn_mask && - ((b_leaf < tt->rn_bit) /* index(netmask) > node */ - || rn_refines(netmask, tt->rn_mask) - || rn_lexobetter(netmask, tt->rn_mask)))) - break; - } - /* - * If the mask is not duplicated, we wouldn't - * find it among possible duplicate key entries - * anyway, so the above test doesn't hurt. - * - * We sort the masks for a duplicated key the same way as - * in a masklist -- most specific to least specific. - * This may require the unfortunate nuisance of relocating - * the head of the list. - */ - if (tt == saved_tt) { - struct radix_node *xx = x; - /* link in at head of list */ - (tt = treenodes)->rn_dupedkey = t; - tt->rn_flags = t->rn_flags; - tt->rn_parent = x = t->rn_parent; - t->rn_parent = tt; /* parent */ - if (x->rn_left == t) - x->rn_left = tt; - else - x->rn_right = tt; - saved_tt = tt; x = xx; - } else { - (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; - t->rn_dupedkey = tt; - tt->rn_parent = t; /* parent */ - if (tt->rn_dupedkey) /* parent */ - tt->rn_dupedkey->rn_parent = tt; /* parent */ - } -#ifdef RN_DEBUG - t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; - tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt; -#endif - tt->rn_key = (caddr_t) v; - tt->rn_bit = -1; - tt->rn_flags = RNF_ACTIVE; - } - /* - * Put mask in tree. - */ - if (netmask) { - tt->rn_mask = netmask; - tt->rn_bit = x->rn_bit; - tt->rn_flags |= x->rn_flags & RNF_NORMAL; - } - t = saved_tt->rn_parent; - if (keyduplicated) - goto on2; - b_leaf = -1 - t->rn_bit; - if (t->rn_right == saved_tt) - x = t->rn_left; - else - x = t->rn_right; - /* Promote general routes from below */ - if (x->rn_bit < 0) { - for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) - if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) { - *mp = m = rn_new_radix_mask(x, 0); - if (m) - mp = &m->rm_mklist; - } - } else if (x->rn_mklist) { - /* - * Skip over masks whose index is > that of new node - */ - for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) - if (m->rm_bit >= b_leaf) - break; - t->rn_mklist = m; *mp = 0; - } -on2: - /* Add new route to highest possible ancestor's list */ - if ((netmask == 0) || (b > t->rn_bit )) - return tt; /* can't lift at all */ - b_leaf = tt->rn_bit; - do { - x = t; - t = t->rn_parent; - } while (b <= t->rn_bit && x != top); - /* - * Search through routes associated with node to - * insert new route according to index. - * Need same criteria as when sorting dupedkeys to avoid - * double loop on deletion. - */ - for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) { - if (m->rm_bit < b_leaf) - continue; - if (m->rm_bit > b_leaf) - break; - if (m->rm_flags & RNF_NORMAL) { - mmask = m->rm_leaf->rn_mask; - if (tt->rn_flags & RNF_NORMAL) { - printf( - "Non-unique normal route, mask not entered"); - return tt; - } - } else - mmask = m->rm_mask; - if (mmask == netmask) { - m->rm_refs++; - tt->rn_mklist = m; - return tt; - } - if (rn_refines(netmask, mmask) - || rn_lexobetter(netmask, mmask)) - break; - } - *mp = rn_new_radix_mask(tt, *mp); - return tt; -} - -struct radix_node * -rn_delete(v_arg, netmask_arg, head) - void *v_arg, *netmask_arg; - struct radix_node_head *head; -{ - register struct radix_node *t, *p, *x, *tt; - struct radix_mask *m, *saved_m, **mp; - struct radix_node *dupedkey, *saved_tt, *top; - caddr_t v, netmask; - int b, head_off, vlen; - - v = v_arg; - netmask = netmask_arg; - x = head->rnh_treetop; - tt = rn_search(v, x); - head_off = x->rn_offset; - vlen = *(u_char *)v; - saved_tt = tt; - top = x; - if (tt == 0 || - Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off)) - return (0); - /* - * Delete our route from mask lists. - */ - if (netmask) { - if ((x = rn_addmask(netmask, 1, head_off)) == 0) - return (0); - netmask = x->rn_key; - while (tt->rn_mask != netmask) - if ((tt = tt->rn_dupedkey) == 0) - return (0); - } - if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0) - goto on1; - if (tt->rn_flags & RNF_NORMAL) { - if (m->rm_leaf != tt || m->rm_refs > 0) { - printf("rn_delete: inconsistent annotation\n"); - return 0; /* dangling ref could cause disaster */ - } - } else { - if (m->rm_mask != tt->rn_mask) { - printf("rn_delete: inconsistent annotation\n"); - goto on1; - } - if (--m->rm_refs >= 0) - goto on1; - } - b = -1 - tt->rn_bit; - t = saved_tt->rn_parent; - if (b > t->rn_bit) - goto on1; /* Wasn't lifted at all */ - do { - x = t; - t = t->rn_parent; - } while (b <= t->rn_bit && x != top); - for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) - if (m == saved_m) { - *mp = m->rm_mklist; - MKFree(m); - break; - } - if (m == 0) { - printf("rn_delete: couldn't find our annotation\n"); - if (tt->rn_flags & RNF_NORMAL) - return (0); /* Dangling ref to us */ - } -on1: - /* - * Eliminate us from tree - */ - if (tt->rn_flags & RNF_ROOT) - return (0); -#ifdef RN_DEBUG - /* Get us out of the creation list */ - for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {} - if (t) t->rn_ybro = tt->rn_ybro; -#endif - t = tt->rn_parent; - dupedkey = saved_tt->rn_dupedkey; - if (dupedkey) { - /* - * at this point, tt is the deletion target and saved_tt - * is the head of the dupekey chain - */ - if (tt == saved_tt) { - /* remove from head of chain */ - x = dupedkey; x->rn_parent = t; - if (t->rn_left == tt) - t->rn_left = x; - else - t->rn_right = x; - } else { - /* find node in front of tt on the chain */ - for (x = p = saved_tt; p && p->rn_dupedkey != tt;) - p = p->rn_dupedkey; - if (p) { - p->rn_dupedkey = tt->rn_dupedkey; - if (tt->rn_dupedkey) /* parent */ - tt->rn_dupedkey->rn_parent = p; - /* parent */ - } else printf("rn_delete: couldn't find us\n"); - } - t = tt + 1; - if (t->rn_flags & RNF_ACTIVE) { -#ifndef RN_DEBUG - *++x = *t; - p = t->rn_parent; -#else - b = t->rn_info; - *++x = *t; - t->rn_info = b; - p = t->rn_parent; -#endif - if (p->rn_left == t) - p->rn_left = x; - else - p->rn_right = x; - x->rn_left->rn_parent = x; - x->rn_right->rn_parent = x; - } - goto out; - } - if (t->rn_left == tt) - x = t->rn_right; - else - x = t->rn_left; - p = t->rn_parent; - if (p->rn_right == t) - p->rn_right = x; - else - p->rn_left = x; - x->rn_parent = p; - /* - * Demote routes attached to us. - */ - if (t->rn_mklist) { - if (x->rn_bit >= 0) { - for (mp = &x->rn_mklist; (m = *mp);) - mp = &m->rm_mklist; - *mp = t->rn_mklist; - } else { - /* If there are any key,mask pairs in a sibling - duped-key chain, some subset will appear sorted - in the same order attached to our mklist */ - for (m = t->rn_mklist; m && x; x = x->rn_dupedkey) - if (m == x->rn_mklist) { - struct radix_mask *mm = m->rm_mklist; - x->rn_mklist = NULL;/*XXX*/ - if (--(m->rm_refs) < 0) - MKFree(m); - m = mm; - } - if (m) - printf( - "rn_delete: Orphaned Mask %p at %p\n", - (void *)m, (void *)x); - } - } - /* - * We may be holding an active internal node in the tree. - */ - x = tt + 1; - if (t != x) { -#ifndef RN_DEBUG - *t = *x; -#else - b = t->rn_info; - *t = *x; - t->rn_info = b; -#endif - t->rn_left->rn_parent = t; - t->rn_right->rn_parent = t; - p = x->rn_parent; - if (p->rn_left == x) - p->rn_left = t; - else - p->rn_right = t; - } -out: - tt->rn_flags &= ~RNF_ACTIVE; - tt[1].rn_flags &= ~RNF_ACTIVE; - return (tt); -} - -/* - * This is the same as rn_walktree() except for the parameters and the - * exit. - */ -static int -rn_walktree_from(h, a, m, f, w) - struct radix_node_head *h; - void *a, *m; - walktree_f_t *f; - void *w; -{ - int error; - struct radix_node *base, *next; - u_char *xa = (u_char *)a; - u_char *xm = (u_char *)m; - register struct radix_node *rn, *last = NULL /* shut up gcc */; - int stopping = 0; - int lastb; - - /* - * rn_search_m is sort-of-open-coded here. - */ - /* printf("about to search\n"); */ - for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) { - last = rn; - /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n", - rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */ - if (!(rn->rn_bmask & xm[rn->rn_offset])) { - break; - } - if (rn->rn_bmask & xa[rn->rn_offset]) { - rn = rn->rn_right; - } else { - rn = rn->rn_left; - } - } - /* printf("done searching\n"); */ - - /* - * Two cases: either we stepped off the end of our mask, - * in which case last == rn, or we reached a leaf, in which - * case we want to start from the last node we looked at. - * Either way, last is the node we want to start from. - */ - rn = last; - lastb = rn->rn_bit; - - /* printf("rn %p, lastb %d\n", rn, lastb);*/ - - /* - * This gets complicated because we may delete the node - * while applying the function f to it, so we need to calculate - * the successor node in advance. - */ - while (rn->rn_bit >= 0) - rn = rn->rn_left; - - while (!stopping) { - /* printf("node %p (%d)\n", rn, rn->rn_bit); */ - base = rn; - /* If at right child go back up, otherwise, go right */ - while (rn->rn_parent->rn_right == rn - && !(rn->rn_flags & RNF_ROOT)) { - rn = rn->rn_parent; - - /* if went up beyond last, stop */ - if (rn->rn_bit < lastb) { - stopping = 1; - /* printf("up too far\n"); */ - } - } - - /* Find the next *leaf* since next node might vanish, too */ - for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;) - rn = rn->rn_left; - next = rn; - /* Process leaves */ - while ((rn = base) != NULL) { - base = rn->rn_dupedkey; - /* printf("leaf %p\n", rn); */ - if (!(rn->rn_flags & RNF_ROOT) - && (error = (*f)(rn, w))) - return (error); - } - rn = next; - - if (rn->rn_flags & RNF_ROOT) { - /* printf("root, stopping"); */ - stopping = 1; - } - - } - return 0; -} - -static int -rn_walktree(h, f, w) - struct radix_node_head *h; - walktree_f_t *f; - void *w; -{ - int error; - struct radix_node *base, *next; - register struct radix_node *rn = h->rnh_treetop; - /* - * This gets complicated because we may delete the node - * while applying the function f to it, so we need to calculate - * the successor node in advance. - */ - /* First time through node, go left */ - while (rn->rn_bit >= 0) - rn = rn->rn_left; - for (;;) { - base = rn; - /* If at right child go back up, otherwise, go right */ - while (rn->rn_parent->rn_right == rn - && (rn->rn_flags & RNF_ROOT) == 0) - rn = rn->rn_parent; - /* Find the next *leaf* since next node might vanish, too */ - for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;) - rn = rn->rn_left; - next = rn; - /* Process leaves */ - while ((rn = base)) { - base = rn->rn_dupedkey; - if (!(rn->rn_flags & RNF_ROOT) - && (error = (*f)(rn, w))) - return (error); - } - rn = next; - if (rn->rn_flags & RNF_ROOT) - return (0); - } - /* NOTREACHED */ -} - -int -rn_inithead(head, off) - void **head; - int off; -{ - register struct radix_node_head *rnh; - register struct radix_node *t, *tt, *ttt; - if (*head) - return (1); - R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh)); - if (rnh == 0) - return (0); - Bzero(rnh, sizeof (*rnh)); - *head = rnh; - t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); - ttt = rnh->rnh_nodes + 2; - t->rn_right = ttt; - t->rn_parent = t; - tt = t->rn_left; - tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; - tt->rn_bit = -1 - off; - *ttt = *tt; - ttt->rn_key = rn_ones; - rnh->rnh_addaddr = rn_addroute; - rnh->rnh_deladdr = rn_delete; - rnh->rnh_matchaddr = rn_match; - rnh->rnh_lookup = rn_lookup; - rnh->rnh_walktree = rn_walktree; - rnh->rnh_walktree_from = rn_walktree_from; - rnh->rnh_treetop = t; - return (1); -} - -void -rn_init() -{ - char *cp, *cplim; - struct domain *dom; - - for (dom = domains; dom; dom = dom->dom_next) - if (dom->dom_maxrtkey > max_keylen) - max_keylen = dom->dom_maxrtkey; - - if (max_keylen == 0) { - printf( - "rn_init: radix functions require max_keylen be set\n"); - return; - } - R_Malloc(rn_zeros, char *, 3 * max_keylen); - if (rn_zeros == NULL) - printf("rn_init"); - Bzero(rn_zeros, 3 * max_keylen); - rn_ones = cp = rn_zeros + max_keylen; - addmask_key = cplim = rn_ones + max_keylen; - while (cp < cplim) - *cp++ = -1; - if (rn_inithead((void **)&mask_rnhead, 0) == 0) - printf("rn_init 2"); -} - diff --git a/src/add-ons/kernel/network/core/route.c b/src/add-ons/kernel/network/core/route.c deleted file mode 100644 index e0c3b8256f..0000000000 --- a/src/add-ons/kernel/network/core/route.c +++ /dev/null @@ -1,430 +0,0 @@ -/* route.c */ - -#ifndef _KERNEL_MODE -#include -#endif -#include - -#ifdef _KERNEL_MODE -#include -#endif - -#include "net_malloc.h" - -#include "sys/domain.h" -#include "net/route.h" /* includes net/radix.h */ -#include "protocols.h" -#include "net/if.h" - -int rttrash = 0; /* routes in table that should have been freed but hevn't been */ - -#define SA(p) ((struct sockaddr *)(p)) -#define ROUNDUP(a) (a >0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) - -struct rtstat rtstat; -struct radix_node_head *rt_tables[AF_MAX+1]; - -struct radix_node_head **get_rt_tables(void) -{ - return (struct radix_node_head**)rt_tables; -} - -struct rtentry *rtalloc1(struct sockaddr *dst, int report) -{ - struct radix_node_head *rnh = rt_tables[dst->sa_family]; - struct rtentry *rt; - struct radix_node *rn; - struct rtentry *newrt = NULL; - struct rt_addrinfo info; - int msgtype = RTM_MISS; - int err; - - if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) - && ((rn->rn_flags & RNF_ROOT) == 0)) { - newrt = rt = (struct rtentry*) rn; - if (report && (rt->rt_flags & RTF_CLONING)) { - err = rtrequest(RTM_RESOLVE, dst, NULL, - NULL, 0, &newrt); - if (err) { - newrt = rt; - rt->rt_refcnt++; - goto miss; - } - if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { - msgtype = RTM_RESOLVE; - goto miss; - } - } else - rt->rt_refcnt++; - } - /* XXX - stats? */ - -miss: - if (report) { - memset((caddr_t)&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = dst; - //rt_missmsg(msgtype, &info, 0, err); - } - return (newrt); -} - -void rtalloc(struct route *ro) -{ - /* can we use what we have?? */ - if (ro && ro->ro_rt && ro->ro_rt->rt_ifp && - (ro->ro_rt->rt_flags & RTF_UP)) { - /* yes */ - return; - } - /* no, get a new route */ - ro->ro_rt = rtalloc1(&ro->ro_dst, 1); -} - -void rtfree(struct rtentry *rt) -{ - struct ifaddr *ifa; - - if (!rt) { - printf("rtfree on a NULL pointer!\n"); - return; - } - - rt->rt_refcnt--; - if (rt->rt_refcnt <= 0 && (rt->rt_flags && RTF_UP) == 0) { - if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) { - printf("Trying to free nodes we shouldn't be!\n"); - return; - } - rttrash--; - if (rt->rt_refcnt < 0) { - printf("rtfree: %p not freed as the refcnt is negative!\n", rt); - return; - } - ifa = rt->rt_ifa; - IFAFREE(ifa); - Free(rt_key(rt)); - Free(rt); - } -} - -int rtrequest(int req, struct sockaddr *dst, - struct sockaddr *gateway, - struct sockaddr *netmask, - int flags, - struct rtentry **ret_nrt) -{ - int error = 0; - struct rtentry *rt; - struct radix_node *rn = NULL; - struct radix_node_head *rnh; - struct ifaddr *ifa; - struct sockaddr *ndst; - -#define snderr(x) {error = x; goto bad; } - - if ((rnh = rt_tables[dst->sa_family]) == NULL) - snderr(ESRCH); - if (flags & RTF_HOST) - netmask = NULL; - - switch(req) { - case RTM_DELETE: - if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL) - snderr(ESRCH); - if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) { - /* XXX - should be panic */ - printf("rtrequest: delete: cannot delete route!\n"); - return -1; - } - rt = (struct rtentry *)rn; - rt->rt_flags &= ~RTF_UP; /* mark route as down */ - if (rt->rt_gwroute) { - rt = rt->rt_gwroute; - RTFREE(rt); - (rt = (struct rtentry*)rn)->rt_gwroute = NULL; - } - if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest) - ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); - rttrash++; - if (ret_nrt) - *ret_nrt = rt; - else if (rt->rt_refcnt <= 0) { - rt->rt_refcnt++; - rtfree(rt); - } - break; - case RTM_RESOLVE: - if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) - snderr(EINVAL); - ifa = rt->rt_ifa; - flags = rt->rt_flags & ~RTF_CLONING; - gateway = rt->rt_gateway; - if ((netmask = rt->rt_genmask) == NULL) - flags |= RTF_HOST; - /* fall through */ - goto makeroute; - case RTM_ADD: - /* can we find a route to it? */ - if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == NULL) { - printf("ENETUNREACH!\n"); - snderr(ENETUNREACH); - } -makeroute: - R_Malloc(rt, struct rtentry *, sizeof(*rt)); - if (!rt) - snderr(ENOMEM); - Bzero(rt, sizeof(*rt)); - rt->rt_flags = RTF_UP | flags; - if (rt_setgate(rt, dst, gateway)) { - Free(rt); - snderr(ENOMEM); - } - - ndst = rt_key(rt); - if (netmask) - rt_maskedcopy(dst, ndst, netmask); - else - Bcopy(dst, ndst, dst->sa_len); - - rn = rnh->rnh_addaddr((caddr_t) ndst, (caddr_t) netmask, - rnh, rt->rt_nodes); - - if (!rn) { - if (rt->rt_gwroute) - rtfree(rt->rt_gwroute); - Free(rt_key(rt)); - Free(rt); - snderr(EEXIST); - } - ifa->ifa_refcnt++; - rt->rt_ifa = ifa; - rt->rt_ifp = ifa->ifa_ifp; - /* if we've fallen through - copy metrics */ - if (req == RTM_RESOLVE) - rt->rt_rmx = (*ret_nrt)->rt_rmx; - if (ifa->ifa_rtrequest) - ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0)); - if (ret_nrt) { - *ret_nrt = rt; - rt->rt_refcnt++; - } - break; - } -bad: - return (error); -} - -struct ifaddr *ifa_ifwithroute(int flags, - struct sockaddr *dst, - struct sockaddr *gateway) -{ - struct ifaddr *ifa; - - if ((flags & RTF_GATEWAY) == 0) { - /* - * If we are adding a route to an interface, - * and the interface is a pt to pt link - * we should search for the destination - * as our clue to the interface. Otherwise - * we can use the local address. - */ - ifa = NULL; - if (flags & RTF_HOST) - ifa = ifa_ifwithdstaddr(dst); - if (ifa == NULL) - ifa = ifa_ifwithaddr(gateway); - } else { - /* - * If we are adding a route to a remote net - * or host, the gateway may still be on the - * other end of a pt to pt link. - */ - ifa = ifa_ifwithdstaddr(gateway); - } - if (ifa == NULL) - ifa = ifa_ifwithnet(gateway); - if (ifa == NULL) { - struct rtentry *rt = rtalloc1(gateway, 0); - if (rt == NULL) - return (NULL); - rt->rt_refcnt--; - /* The gateway must be local if the same address family. */ - if ((rt->rt_flags & RTF_GATEWAY) && - rt_key(rt)->sa_family == dst->sa_family) - return (0); - if ((ifa = rt->rt_ifa) == NULL) - return (NULL); - } - if (ifa->ifa_addr->sa_family != dst->sa_family) { - struct ifaddr *oifa = ifa; - ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); - if (ifa == NULL) - ifa = oifa; - } - return (ifa); -} - -int rt_setgate(struct rtentry *rt0, - struct sockaddr *dst, - struct sockaddr *gate) -{ - caddr_t new, old = NULL; - int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); - struct rtentry *rt = rt0; - - - if (rt->rt_gateway == NULL || glen > (int) ROUNDUP(rt->rt_gateway->sa_len)) { - old = (caddr_t)rt_key(rt); - R_Malloc(new, caddr_t, dlen + glen); - if (new == NULL) - return 1; - rt->rt_nodes->rn_key = new; - } else { - new = rt->rt_nodes->rn_key; - old = NULL; - } - - Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); - if (old) { - Bcopy(dst, new, dlen); - Free(old); - } - - if (rt->rt_gwroute != NULL) { - rt = rt->rt_gwroute; - RTFREE(rt); - rt = rt0; - rt->rt_gwroute = NULL; - } - - if (rt->rt_flags & RTF_GATEWAY) { - rt->rt_gwroute = rtalloc1(gate, 1); - /* - * If we switched gateways, grab the MTU from the new - * gateway route if the current MTU is 0 or greater - * than the MTU of gateway. - */ - if (rt->rt_gwroute && !(rt->rt_rmx.rmx_locks & RTV_MTU) && - (rt->rt_rmx.rmx_mtu == 0 || - rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu)) { - rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; - } - } - - return 0; -} - -void rt_maskedcopy(struct sockaddr *src, - struct sockaddr *dst, - struct sockaddr *netmask) -{ - uchar *cp1 = (uchar *)src; - uchar *cp2 = (uchar *)dst; - uchar *cp3 = (uchar *)netmask; - uchar *cplim = cp2 + *cp3; - uchar *cplim2 = cp2 + *cp1; - - *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ - cp3 += 2; - if (cplim > cplim2) - cplim = cplim2; - while (cp2 < cplim) - *cp2++ = *cp1++ & *cp3++; - if (cp2 < cplim2) - memset((caddr_t)cp2, 0, (unsigned)(cplim2 - cp2)); -} - -void ifafree(struct ifaddr *ifa) -{ - if (ifa == NULL) { - printf("ifafree"); - return; - } - if (ifa->ifa_refcnt == 0) - free(ifa); - else - ifa->ifa_refcnt--; -} - -/* - * Set up a routing table entry, normally - * for an interface. - */ -int rtinit(struct ifaddr *ifa, int cmd, int flags) -{ - struct rtentry *rt; - struct sockaddr *dst; - struct sockaddr *deldst; - struct mbuf *m = NULL; - struct rtentry *nrt = NULL; - int error; - - dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; - if (cmd == RTM_DELETE) { - if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { - m = m_get(MT_SONAME); - if (m == NULL) - return(ENOBUFS); - deldst = mtod(m, struct sockaddr *); - rt_maskedcopy(dst, deldst, ifa->ifa_netmask); - dst = deldst; - } - if ((rt = rtalloc1(dst, 0)) != NULL) { - rt->rt_refcnt--; - if (rt->rt_ifa != ifa) { - if (m != NULL) - (void) m_free(m); - return (flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); - } - } - } - - error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask, - flags | ifa->ifa_flags, &nrt); - - if (cmd == RTM_DELETE && error == 0 && (rt = nrt) != NULL) { - /* XXX - add this when we have routing sockets! - rt_newaddrmsg(cmd, ifa, error, nrt); - */ - if (rt->rt_refcnt <= 0) { - rt->rt_refcnt++; - rtfree(rt); - } - } - if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) { - rt->rt_refcnt--; - if (rt->rt_ifa != ifa) { - printf("rtinit: wrong ifa (%p) was (%p)\n", ifa, rt->rt_ifa); - - if (rt->rt_ifa->ifa_rtrequest) - rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); - IFAFREE(rt->rt_ifa); - rt->rt_ifa = ifa; - rt->rt_ifp = ifa->ifa_ifp; - rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; - ifa->ifa_refcnt++; - if (ifa->ifa_rtrequest) - ifa->ifa_rtrequest(RTM_ADD, rt, NULL); - } - /* XXX - add this when we have routing sockets! - rt_newaddrmsg(cmd, ifa, error, nrt); - */ - } - return (error); -} - -static void rtable_init(void **table) -{ - struct domain *dom; - - for (dom = domains; dom; dom = dom->dom_next) - if (dom->dom_rtattach) - dom->dom_rtattach(&table[dom->dom_family], dom->dom_rtoffset); -} - -void route_init(void) -{ - rn_init(); - - rtable_init((void**)rt_tables); -} diff --git a/src/add-ons/kernel/network/core/sockbuf.c b/src/add-ons/kernel/network/core/sockbuf.c deleted file mode 100644 index a40944325b..0000000000 --- a/src/add-ons/kernel/network/core/sockbuf.c +++ /dev/null @@ -1,308 +0,0 @@ -/* socket "server" */ - -#include -#include - -#ifdef _KERNEL_MODE -#include -#endif - -#include "core_private.h" -#include -#include -#include -#include -#include -#include - -uint32 sb_max = SB_MAX; /* hard value, recompile needed to alter :( */ - -/* - * Allot mbufs to a sockbuf. - * Attempt to scale mbmax so that mbcnt doesn't become limiting - * if buffering efficiency is near the normal case. - */ -int sockbuf_reserve(struct sockbuf *sb, uint32 cc) -{ - uint64 dd = (uint64)cc; - uint64 ee = (sb_max * MCLBYTES) / ((MSIZE) + (MCLBYTES)); - - if (cc == 0) - return 0; - if (dd > ee) - return 0; - - sb->sb_hiwat = cc; - sb->sb_mbmax = min((cc * 2), sb_max); - if (sb->sb_lowat > sb->sb_hiwat) - sb->sb_lowat = sb->sb_hiwat; - return (1); -} - -void sockbuf_drop(struct sockbuf *sb, int len) -{ - struct mbuf *m, *mn; - struct mbuf *next; - - next = (m = sb->sb_mb) ? m->m_nextpkt : NULL; - while (len > 0) { - if (m == NULL) { - if (next == NULL) - return; - - m = next; - next = m->m_nextpkt; - continue; - } - if ((int) m->m_len > len) { - m->m_len -= len; - m->m_data += len; - sb->sb_cc -= len; - break; - } - len -= m->m_len; - sbfree(sb, m); - MFREE(m, mn); - m = mn; - } - while (m && m->m_len == 0) { - sbfree(sb, m); - MFREE(m, mn); - m = mn; - } - if (m) { - sb->sb_mb = m; - m->m_nextpkt = next; - } else - sb->sb_mb = next; -} - -/* - * Free all mbufs in a sockbuf. - * Check that all resources are reclaimed. - */ -void sockbuf_flush(struct sockbuf *sb) -{ - if (sb->sb_flags & SB_LOCK) { - return; - } - while (sb->sb_mbcnt) - sockbuf_drop(sb, (int)sb->sb_cc); - if (sb->sb_cc || sb->sb_mb) - return; -} - -/* - * Free mbufs held by a socket, and reserved mbuf space. - */ -void sockbuf_release(struct sockbuf *sb) -{ - sockbuf_flush(sb); - sb->sb_hiwat = sb->sb_mbmax = 0; -} - -void sockbuf_append(struct sockbuf *sb, struct mbuf *m) -{ - struct mbuf *n; - - if (!m) - return; - if ((n = sb->sb_mb) != NULL) { - while (n->m_nextpkt) - n = n->m_nextpkt; - do { - if (n->m_flags & M_EOR) { - sockbuf_appendrecord(sb, m); /* XXXXXX!!!! */ - return; - } - } while (n->m_next && (n = n->m_next)); - } - sockbuf_compress(sb, m, n); -} - -void sockbuf_appendrecord(struct sockbuf *sb, struct mbuf *m0) -{ - struct mbuf *m; - - if (!m0) - return; - if ((m = sb->sb_mb) != NULL) - while (m->m_nextpkt) - m = m->m_nextpkt; - /* - * Put the first mbuf on the queue. - * Note this permits zero length records. - */ - sballoc(sb, m0); - if (m) - m->m_nextpkt = m0; - else - sb->sb_mb = m0; - m = m0->m_next; - m0->m_next = 0; - if (m && (m0->m_flags & M_EOR)) { - m0->m_flags &= ~M_EOR; - m->m_flags |= M_EOR; - } - sockbuf_compress(sb, m, m0); -} - -int sockbuf_appendaddr(struct sockbuf *sb, struct sockaddr *asa, - struct mbuf *m0, struct mbuf *control) -{ - struct mbuf *m, *n; - int space = asa->sa_len; - - if (m0 && (m0->m_flags & M_PKTHDR) == 0) - return(-1); - - if (m0) - space += m0->m_pkthdr.len; - for (n = control; n; n = n->m_next) { - space += n->m_len; - if (n->m_next == 0) /* keep pointer to last control buf */ - break; - } - if (space > (int) sbspace(sb)) - return (0); - if (asa->sa_len > MLEN) - return (0); - MGET(m, MT_SONAME); - if (m == NULL) - return (0); - m->m_len = asa->sa_len; - memcpy(mtod(m, caddr_t), (caddr_t)asa, asa->sa_len); - if (n) - n->m_next = m0; /* concatenate data to control */ - else - control = m0; - m->m_next = control; - for (n = m; n; n = n->m_next) - sballoc(sb, n); - if ((n = sb->sb_mb) != NULL) { - while (n->m_nextpkt) - n = n->m_nextpkt; - n->m_nextpkt = m; - } else - sb->sb_mb = m; - - return (1); -} - -void sockbuf_compress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n) -{ - int eor = 0; - struct mbuf *o; - - while (m) { - eor |= m->m_flags & M_EOR; - if (m->m_len == 0 && - (eor == 0 || - (((o = m->m_next) || (o = n)) && - o->m_type == m->m_type))) { - m = m_free(m); - continue; - } - if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && - (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && - n->m_type == m->m_type) { - memcpy(mtod(n, caddr_t) + n->m_len, mtod(m, caddr_t), - (unsigned)m->m_len); - n->m_len += m->m_len; - sb->sb_cc += m->m_len; - m = m_free(m); - continue; - } - if (n) - n->m_next = m; - else - sb->sb_mb = m; - sballoc(sb, m); - n = m; - m->m_flags &= ~M_EOR; - m = m->m_next; - n->m_next = 0; - } - if (eor) { - if (n) - n->m_flags |= eor; - else - printf("semi-panic: sockbuf_compress\n"); - } -} - -void sockbuf_droprecord(struct sockbuf *sb) -{ - struct mbuf *m, *mn; - - m = sb->sb_mb; - if (m) { - sb->sb_mb = m->m_nextpkt; - do { - sbfree(sb, m); - MFREE(m, mn); - } while ((m = mn) != NULL); - } -} - -int sockbuf_wait(struct sockbuf *sb) -{ - if (sb->sb_cc > 0) - return 0; - sb->sb_flags |= SB_WAIT; - return nsleep(sb->sb_pop, "sockbuf_wait", sb->sb_timeo); -} - -void sockbuf_insertoob(struct sockbuf *sb, struct mbuf *m0) -{ - struct mbuf *m; - struct mbuf **mp; - - if (m0 == NULL) - return; - for (mp = &sb->sb_mb; (m = *mp) != NULL; mp = &((*mp)->m_nextpkt)) { -again: - switch (m->m_type) { - case MT_OOBDATA: - continue; /* WANT next train */ - case MT_CONTROL: - if ((m = m->m_next) != NULL) - goto again; /* inspect THIS - * train further */ - } - break; - } - /* - * Put the first mbuf on the queue. - * Note this permits zero length records. - */ - sballoc(sb, m0); - m0->m_nextpkt = *mp; - *mp = m0; - m = m0->m_next; - m0->m_next = 0; - if (m && (m0->m_flags & M_EOR)) { - m0->m_flags &= ~M_EOR; - m->m_flags |= M_EOR; - } - sockbuf_compress(sb, m, m0); -} - -/* - * Lock a sockbuf already known to be locked; - * return any error returned from sleep (EINTR). - */ -int sockbuf_lock(struct sockbuf *sb) // XXX never called at all -{ - int error; - - while (sb->sb_flags & SB_LOCK) { - sb->sb_flags |= SB_WANT; - error = nsleep(sb->sb_sleep, "sockbuf_lock", 0); - if (error) - return (error); - } - sb->sb_flags |= SB_LOCK; - return (0); -} - diff --git a/src/add-ons/kernel/network/core/socket.c b/src/add-ons/kernel/network/core/socket.c deleted file mode 100644 index df1f5dbbce..0000000000 --- a/src/add-ons/kernel/network/core/socket.c +++ /dev/null @@ -1,1589 +0,0 @@ -/* socket "server" */ - -#include -#include -#include -#include -#include - -#include "core_private.h" -#include "sys/socket.h" -#include "sys/socketvar.h" -#include "sys/sockio.h" -#include "sys/protosw.h" -#include "pools.h" -#include "net/if.h" -#include "netinet/in.h" -#include "netinet/in_pcb.h" -#include "net_misc.h" -#include "protocols.h" -#include "sys/uio.h" -#include - -#ifdef _KERNEL_MODE -#include -#include "core_module.h" -#endif - -// R5 & BONE do no define this, but we need it, so we copy haiku's own definition: -#ifndef EDESTADDRREQ -#define EDESTADDRREQ (B_POSIX_ERROR_BASE + 48) -#endif - -#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) - -/* Private prototypes */ -static int checkevent(struct socket *so); -static void sofree(struct socket *); -static void soqinsque (struct socket *head, struct socket *so, int q); -static int soqremque (struct socket *so, int q); -static int sosend(struct socket *so, struct mbuf *addr, struct uio *uio, - struct mbuf *top, struct mbuf *control, int flags); -static int soreceive (struct socket *so, struct mbuf **paddr, struct uio *uio, - struct mbuf **mp0, struct mbuf **controlp, int *flagsp); - -/* Static global objects... */ -static pool_ctl *spool; -static benaphore sockets_lock; - -/* OpenBSD sets this at 128??? */ -static int somaxconn = SOMAXCONN; - -/* The BeOS R5 kernel doesn't have abs(). */ -#ifdef COMPILE_FOR_R5 -int abs(int num) -{ - return (int)labs(num); -} -#endif - -int sockets_init(void) -{ - if (!spool) - pool_init(&spool, sizeof(struct socket)); - - if (!spool) - return ENOMEM; - - INIT_BENAPHORE(sockets_lock, "sockets_lock"); - return CHECK_BENAPHORE(sockets_lock); -} - - -void sockets_shutdown(void) -{ - pool_destroy(spool); - - UNINIT_BENAPHORE(sockets_lock); -} - - -/* uiomove! */ - -int uiomove(caddr_t cp, int n, struct uio *uio) -{ - struct iovec *iov; - int cnt; - int error = 0; - void *ptr = NULL; - - while (n > 0 && uio->uio_resid) { - iov = uio->uio_iov; - cnt = iov->iov_len; - - if (cnt == 0) { - uio->uio_iov++; - uio->uio_iovcnt--; - continue; - } - if (cnt > n) - cnt = n; - - switch (uio->uio_segflg) { - /* XXX - once "properly" in kernel space, revisit and - * fix this for kernel moves... - */ - case UIO_USERSPACE: - case UIO_SYSSPACE: - if (uio->uio_rw == UIO_READ) - ptr = memcpy(iov->iov_base, cp, cnt); - else - ptr = memcpy(cp, iov->iov_base, cnt); - -// if (!ptr) -// return (errno); - break; - } - iov->iov_base = (caddr_t)iov->iov_base + cnt; - iov->iov_len -= cnt; - uio->uio_resid -= cnt; - uio->uio_offset += cnt; - cp += cnt; - n -= cnt; - } - return (error); -} - -int socket_init(struct socket **nso) -{ - struct socket *so; - - so = (struct socket*)pool_get(spool); - - if (so == NULL) { - printf("socket_init: ENOMEM\n"); - return ENOMEM; - } - - memset(so, 0, sizeof(*so)); - - *nso = so; - - return 0; -} - -int socket_create(struct socket *so, int dom, int type, int proto) -{ - struct protosw *prm = NULL; /* protocol module */ - int error; - - if (so == NULL) { - printf("socket_create: EINVAL\n"); - return EINVAL; - } - - if (proto) - prm = pffindproto(dom, proto, type); - else - prm = pffindtype(dom, type); - - if (!prm || !prm->pr_userreq) { - printf("socket_create: EPROTONOSUPPORT\n"); - return EPROTONOSUPPORT; - } - - if (prm->pr_type != type) { - printf("socket_create: EPROTOTYPE\n"); - return EPROTOTYPE; - } - - so->so_type = type; - so->so_proto = prm; - /* Our sem's... don't like using so many here - find another way :( */ - so->so_rcv.sb_pop = create_sem(0, "so_rcv.sb_pop sem"); - so->so_snd.sb_pop = create_sem(0, "so_snd.sb_pop sem"); - so->so_timeo = create_sem(0, "so_timeo sem"); - so->so_rcv.sb_sleep = create_sem(0, "so_rcv.sb_sleep sem"); - so->so_snd.sb_sleep = create_sem(0, "so_snd.sb_sleep sem"); - - if (so->so_rcv.sb_pop < 0 || - so->so_rcv.sb_sleep < 0 || - so->so_snd.sb_pop < 0 || - so->so_snd.sb_sleep < 0 || - so->so_timeo < 0) { - printf("socket_create: ENOMEM\n"); - delete_sem(so->so_rcv.sb_pop); - delete_sem(so->so_rcv.sb_sleep); - delete_sem(so->so_snd.sb_pop); - delete_sem(so->so_snd.sb_sleep); - delete_sem(so->so_timeo); - return ENOMEM; - } - -#ifdef _KERNEL_MODE - set_sem_owner(so->so_rcv.sb_pop, B_SYSTEM_TEAM); - set_sem_owner(so->so_snd.sb_pop, B_SYSTEM_TEAM); - set_sem_owner(so->so_timeo, B_SYSTEM_TEAM); - set_sem_owner(so->so_rcv.sb_sleep, B_SYSTEM_TEAM); - set_sem_owner(so->so_snd.sb_pop, B_SYSTEM_TEAM); -#endif - - error = prm->pr_userreq(so, PRU_ATTACH, NULL, (struct mbuf *)proto, NULL); - if (error) { - so->so_state |= SS_NOFDREF; /* so we free the socket */ - sofree(so); - return error; - } - - return 0; -} - - -int soreserve(struct socket *so, uint32 sndcc, uint32 rcvcc) -{ - if (sockbuf_reserve(&so->so_snd, sndcc) == 0) - goto bad; - if (sockbuf_reserve(&so->so_rcv, rcvcc) == 0) - goto bad2; - - if (so->so_rcv.sb_lowat == 0) - so->so_rcv.sb_lowat = 1; - if (so->so_snd.sb_lowat == 0) - so->so_snd.sb_lowat = MCLBYTES; - if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) - so->so_snd.sb_lowat = so->so_snd.sb_hiwat; - - return (0); - -bad2: - sockbuf_release(&so->so_snd); -bad: - printf("soreserve: ENOBUFS\n"); - return (ENOBUFS); -} - - -int socket_bind(struct socket *so, caddr_t data, int len) -{ - int error; - struct mbuf *nam; - - nam = m_get(MT_SONAME); - if (!nam) { - printf("socket_bind: ENOMEM\n"); - return ENOMEM; - } - - nam->m_len = len; - memcpy(mtod(nam, char*), data, len); - - /* xxx - locking! */ - error = (*so->so_proto->pr_userreq) (so, PRU_BIND, NULL, nam, NULL); - - m_freem(nam); - - return error; -} - -int socket_listen(struct socket *so, int backlog) -{ - int error; - - error = so->so_proto->pr_userreq(so, PRU_LISTEN, NULL, NULL, NULL); - if (error) - return error; - - if (so->so_q == 0) - so->so_options |= SO_ACCEPTCONN; - if (backlog < 0 || backlog > somaxconn) - backlog = somaxconn; - /* OpenBSD defines a minimum of 80...hmmm... */ - if (backlog < 0) - backlog = 0; - so->so_qlimit = backlog; - return 0; -} - -int socket_connect(struct socket *so, caddr_t data, int len) -{ - struct mbuf *nam = m_get(MT_SONAME); - int error; - - if (!nam) - return ENOMEM; - - if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) - return EALREADY; - - if ((so->so_options & SO_ACCEPTCONN)) - return (EOPNOTSUPP); - - nam->m_len = len; - memcpy(mtod(nam, char*), data, len); - - /* - * If protocol is connection-based, can only connect once. - * Otherwise, if connected, try to disconnect first. - * This allows user to disconnect by connecting to, e.g., - * a null address. - */ - if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) && - ((so->so_proto->pr_flags & PR_CONNREQUIRED) || - (error = sodisconnect(so)))) { - error = EISCONN; - } else { - error = so->so_proto->pr_userreq(so, PRU_CONNECT, - NULL, nam, NULL); - } - - if (error) { - goto bad; - } - - if ((so->so_state & SS_NBIO) && (so->so_state && SS_ISCONNECTING)) { - m_freem(nam); - return EINPROGRESS; - } - - while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) - if ((error = nsleep(so->so_timeo, "socket_connect", 0))) - break; - - if (error == 0) { - error = so->so_error; - so->so_error = 0; - } - -bad: - so->so_state &= ~SS_ISCONNECTING; - m_freem(nam); - - return error; -} - -struct socket *sonewconn(struct socket *head, int connstatus) -{ - struct socket *so; - int soqueue = connstatus ? 1 : 0; - - if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) - return NULL; - if (socket_init(&so) < 0) - return NULL; - - so->so_type = head->so_type; - so->so_options = head->so_options & ~SO_ACCEPTCONN; - so->so_linger = head->so_linger; - so->so_state = head->so_state | SS_NOFDREF; - so->so_proto = head->so_proto; - so->so_timeo = head->so_timeo; - - soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); - soqinsque(head, so, soqueue); - - if ((*so->so_proto->pr_userreq)(so, PRU_ATTACH, NULL, NULL, NULL)) { - soqremque(so, soqueue); - pool_put(spool, so); - return NULL; - } - if(connstatus) { - sorwakeup(head); - wakeup(head->so_timeo); - so->so_state |= connstatus; - } - return so; -} - -int socket_shutdown(struct socket *so, int how) -{ - struct protosw *pr = so->so_proto; - - if (how == SHUT_RD || how == SHUT_RDWR) - sorflush(so); - if (how == SHUT_WR || how == SHUT_RDWR) - return pr->pr_userreq(so, PRU_SHUTDOWN, NULL, NULL, NULL); - return 0; -} - -int socket_send(struct socket *so, struct msghdr *mp, int flags, int *retsize) -{ - struct uio auio; - struct iovec *iov; - uint32 i; - struct mbuf *to; - struct mbuf *control; - uint len; - int error; - - auio.uio_iov = mp->msg_iov; - auio.uio_iovcnt = mp->msg_iovlen; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_offset = 0; - auio.uio_resid = 0; - iov = mp->msg_iov; - - /* Make sure we don't exceed max size... */ - for (i=0;i < mp->msg_iovlen;i++, iov++) { - if (iov->iov_len > SSIZE_MAX || - (auio.uio_resid += iov->iov_len) > SSIZE_MAX) - return EINVAL; - } - if (mp->msg_name) { - /* stick msg_name into an mbuf */ - to = m_get(MT_SONAME); - to->m_len = mp->msg_namelen; - memcpy(mtod(to, char*), mp->msg_name, mp->msg_namelen); - } else - to = NULL; - - if (mp->msg_control) { - if (mp->msg_controllen < sizeof(struct cmsghdr)) { - error = EINVAL; - goto bad; - } - control = m_get(MT_CONTROL); - control->m_len = mp->msg_controllen; - memcpy(mtod(control, char*), mp->msg_control, mp->msg_controllen); - } else - control = NULL; - - len = auio.uio_resid; - - error = sosend(so, to, &auio, NULL, control, flags); - if (error) { - /* what went wrong! */ - if (auio.uio_resid != len && (/*error == ERESTART || */ - error == EINTR || error == EWOULDBLOCK)) - error = 0; /* not really an error */ - } - if (error == 0) - *retsize = len - auio.uio_resid; /* tell them how much we did send */ -bad: - if (to) - m_freem(to); - - return error; -} - -int socket_writev(struct socket *so, struct iovec *iov, int flags) -{ - struct uio auio; - int len = iov->iov_len; - int error; - - auio.uio_iov = iov; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_WRITE; - auio.uio_offset = 0; - auio.uio_resid = iov->iov_len; - - error = sosend(so, NULL, &auio, NULL, NULL, flags); - - if (error < 0) - return error; - return (len - auio.uio_resid); -} - -static int sosend(struct socket *so, struct mbuf *addr, struct uio *uio, struct mbuf *top, - struct mbuf *control, int flags) -{ - struct mbuf **mp; - struct mbuf *m; - int32 space; - int32 len; - uint64 resid; - int clen = 0; - int error, dontroute, mlen; - int atomic = sosendallatonce(so) || top; - - if (uio) - resid = uio->uio_resid; - else - resid = top->m_pkthdr.len; - - /* resid shouldn't be below 0 and also a flag of MSG_EOR on a - * SOCK_STREAM isn't allowed (doesn't even make sense!) - */ - if (resid < 0 || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) { - error = EINVAL; - goto release; - } - - dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && - (so->so_proto->pr_flags & PR_ATOMIC); - - if (control) - clen = control->m_len; - -#define snderr(err) { error = err; /* unlock */ goto release; } -restart: - if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags)))) - goto out; - - /* Main Loop! We should loop here until resid == 0 */ - do { - if ((so->so_state & SS_CANTSENDMORE)) - snderr(EPIPE); - if (so->so_error) - snderr(so->so_error); - if ((so->so_state & SS_ISCONNECTED) == 0) { - if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - /* we need to be connected and we're not... */ - if ((so->so_state & SS_ISCONFIRMING) == 0 && - !(resid == 0 && clen != 0)) - /* we're not even trying to connect and we - * have data to send, so it's an error! - * return ENOTCONN - */ - snderr(ENOTCONN); - } else if (addr == NULL) - /* UDP is a connectionless protocol, so it can work - * without being connected as long as we tell it where we - * want to send the data :) - */ - /* Doh! No address to send to (UDP) */ - snderr(EDESTADDRREQ); - } - space = sbspace(&so->so_snd); - - if (flags & MSG_OOB) - space += 1024; - - if ((atomic && resid > (uint64) so->so_snd.sb_hiwat) || clen > so->so_snd.sb_hiwat) - snderr(EMSGSIZE); - - if ((uint64) space < resid + clen && uio && - (atomic || space < so->so_snd.sb_lowat || space < clen)) { - if ((so->so_state & SS_NBIO)) { /* non blocking set */ - printf("so->so_state & SS_NBIO (%d)\n", so->so_state & SS_NBIO); - snderr(EWOULDBLOCK); - } - /* free lock - we're waiting on send buffer space */ - sbunlock(&so->so_snd); - error = sockbuf_wait(&so->so_snd); - if (error) - goto out; - goto restart; - } - mp = ⊤ - space -= clen; - - do { - if (!uio) { - /* data is actually just packaged as top. */ - resid = 0; - if (flags & MSG_EOR) - top->m_flags |= M_EOR; - } else do { - if (!top) { - MGETHDR(m, MT_DATA); - mlen = MHLEN; - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = NULL; - } else { - MGET(m, MT_DATA); - mlen = MLEN; - } - if (resid >= MINCLSIZE && space >= MCLBYTES) { - MCLGET(m); - if ((m->m_flags & M_EXT) == 0) - /* didn't get a cluster */ - goto nopages; - - mlen = MCLBYTES; - if (atomic && !top) { - len = min((uint64) (MCLBYTES - max_hdr), resid); - m->m_data += max_hdr; - } else - len = min(MCLBYTES, resid); - space -= len; - } else { -nopages: - len = min(min((uint64) mlen, resid), (uint64) space); - space -= len; - /* leave room for headers if required */ - if (atomic && !top && len < mlen) - MH_ALIGN(m, len); - } - - error = uiomove(mtod(m, caddr_t), (int)len, uio); - resid = uio->uio_resid; - m->m_len = len; - *mp = m; - top->m_pkthdr.len += len; - if (error) - goto release; - mp = &m->m_next; - if (resid <= 0) { - if (flags & MSG_EOR) - /* we're the last record */ - top->m_flags |= M_EOR; - break; - } - } while (space > 0 && atomic); - - if (dontroute) - so->so_options |= SO_DONTROUTE; - - /* XXX - locking */ - error = (*so->so_proto->pr_userreq)(so, (flags & MSG_OOB) ? PRU_SENDOOB: PRU_SEND, - top, addr, control); - - /* XXX - unlock */ - if (dontroute) - so->so_options &= ~SO_DONTROUTE; - clen = 0; - top = NULL; - control = NULL; - mp = ⊤ - if (error) - goto release; - } while (resid && space > 0); - } while (resid); - -release: - sbunlock(&so->so_snd); -out: - if (top) - m_freem(top); - if (control) - m_freem(control); - return (error); -} - -int socket_readv(struct socket *so, struct iovec *iov, int *flags) -{ - struct uio auio; - int len = iov->iov_len; - int error; - - auio.uio_iov = iov; - auio.uio_iovcnt = 1; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; - auio.uio_resid = iov->iov_len; - - error = soreceive(so, NULL, &auio, NULL, NULL, flags); - if (error != 0) - return error; - return (len - auio.uio_resid); -} - -int socket_recv(struct socket *so, struct msghdr *mp, caddr_t namelenp, int *retsize) -{ - struct uio auio; - struct iovec *iov; - struct mbuf *control = NULL; - struct mbuf *from = NULL; - int error = 0, len = 0; - uint32 i; - - auio.uio_iov = mp->msg_iov; - auio.uio_iovcnt = mp->msg_iovlen; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_rw = UIO_READ; - auio.uio_offset = 0; - auio.uio_resid = 0; - iov = mp->msg_iov; - - for (i=0; i < mp->msg_iovlen; i++, iov++) { - if (iov->iov_len < 0) - return EINVAL; - if ((auio.uio_resid += iov->iov_len) < 0) - return EINVAL; - } - len = auio.uio_resid; - - if ((error = soreceive(so, &from, &auio, - NULL, mp->msg_control ? &control : NULL, - &mp->msg_flags)) != 0) { - if (auio.uio_resid != (uint) len && (error == EINTR || error == EWOULDBLOCK)) - error = 0; - } - - if (error) - goto out; - - *retsize = len - auio.uio_resid; - - if (mp->msg_name) { - len = mp->msg_namelen; - - if (len <= 0 || !from) { - len = 0; - } else { - if (len > (int) from->m_len) - len = from->m_len; - memcpy((caddr_t)mp->msg_name, mtod(from, caddr_t), len); - } - mp->msg_namelen = len; - if (namelenp) - memcpy(namelenp, (caddr_t)&len, sizeof(int)); - } - - /* XXX - add control handling */ -out: - if (from) - m_freem(from); - if (control) - m_freem(control); - - return error; -} - - -static int soreceive(struct socket *so, struct mbuf **paddr, struct uio *uio, struct mbuf**mp0, - struct mbuf **controlp, int *flagsp) -{ - struct mbuf *m, **mp; - int flags = 0; - int len, error = 0, offset; - struct mbuf *nextrecord; - int moff, type = 0; - uint orig_resid = uio->uio_resid; - struct protosw *pr = so->so_proto; - - mp = mp0; - if (paddr) - *paddr = NULL; - if (controlp) - *controlp = NULL; - - /* ensure we don't have MSG_EOR set */ - if (flagsp) - flags = (*flagsp) & ~MSG_EOR; - - if (flags & MSG_OOB) { - m = m_get(MT_DATA); - error = (*pr->pr_userreq)(so, PRU_RCVOOB, m, (struct mbuf*)(flags & MSG_PEEK), NULL); - if (error) - goto bad; - do { - error = uiomove(mtod(m, caddr_t), (int) min(uio->uio_resid, m->m_len), uio); - m = m_free(m); - } while (uio->uio_resid && error == 0 && m); -bad: - if (m) - m_freem(m); - return error; - } - if (mp) - *mp = NULL; - if ((so->so_state & SS_ISCONFIRMING) && uio->uio_resid) - (*pr->pr_userreq)(so, PRU_RCVD, NULL, NULL, NULL); - -restart: - if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags)))) - return error; - m = so->so_rcv.sb_mb; - /* - * If we have less data than requested, block awaiting more - * (subject to any timeout) if: - * 1. the current count is less than the low water mark, - * 2. MSG_WAITALL is set, and it is possible to do the entire - * receive operation at once if we block (resid <= hiwat), or - * 3. MSG_DONTWAIT is not set. - * If MSG_WAITALL is set but resid is larger than the receive buffer, - * we have to do the receive in sections, and thus risk returning - * a short count if a timeout or signal occurs after we start. - */ - if (m == NULL || (((flags & MSG_DONTWAIT) == 0 && - (uint) so->so_rcv.sb_cc < uio->uio_resid) && - (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || - ((flags & MSG_WAITALL) && uio->uio_resid <= (uint) so->so_rcv.sb_hiwat)) && - m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { - - if (so->so_error) { - if (m) - goto dontblock; - error = so->so_error; - if ((flags & MSG_PEEK) == 0) - so->so_error = 0; - goto release; - } - if ((so->so_state & SS_CANTRCVMORE)) { - if (m) - goto dontblock; - else - goto release; - } - for (;m; m = m->m_next) - if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { - m = so->so_rcv.sb_mb; - goto dontblock; - } - if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING)) == 0 && - (so->so_proto->pr_flags & PR_CONNREQUIRED)) { - error = ENOTCONN; - goto release; - } - if (uio->uio_resid == 0) - goto release; - if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { - error = EWOULDBLOCK; - goto release; - } - sbunlock(&so->so_rcv); - error = sockbuf_wait(&so->so_rcv); - if (error) - return error; - goto restart; - } - -dontblock: - nextrecord = m->m_nextpkt; - if (pr->pr_flags & PR_ADDR) { - orig_resid = 0; - if (flags & MSG_PEEK) { - if (!paddr) - *paddr = m_copym(m, 0, m->m_len); - m = m->m_next; - } else { - sbfree(&so->so_rcv, m); - if (paddr) { - *paddr = m; - so->so_rcv.sb_mb = m->m_next; - m->m_next = NULL; - m = so->so_rcv.sb_mb; - } else { - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; - } - } - } - while (m && m->m_type == MT_CONTROL && error == 0) { - if ((flags & MSG_PEEK)) { - if (controlp) - *controlp = m_copym(m, 0, m->m_len); - m = m->m_next; - } else { - sbfree(&so->so_rcv, m); - if (controlp) { - /* XXX technically we should look at control rights here, - * but so far we have no notion of them... - */ - *controlp = m; - so->so_rcv.sb_mb = m->m_next; - m->m_next = NULL; - m = so->so_rcv.sb_mb; - } else { - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; - } - } - if (controlp) { - orig_resid = 0; - controlp = &(*controlp)->m_next; - } - } - if (m) { - if ((flags & MSG_PEEK) == 0) - m->m_nextpkt = nextrecord; - type = m->m_type; - if (type == MT_OOBDATA) - flags |= MSG_OOB; - } - moff = 0; - offset = 0; - while (m && uio->uio_resid > 0 && error == 0) { - if (m->m_type == MT_OOBDATA) { - if (type != MT_OOBDATA) - break; - } else if (type == MT_OOBDATA) { - break; - } - so->so_state &= ~SS_RCVATMARK; - len = uio->uio_resid; - if (so->so_oobmark && (uint) len > so->so_oobmark - offset) - len = so->so_oobmark - offset; - if (len > (int) m->m_len - moff) - len = m->m_len - moff; - if (!mp) - error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); - else - uio->uio_resid -= len; - if (len == (int) m->m_len - moff) { - if (m->m_flags & M_EOR) - flags |= MSG_EOR; - if (flags & MSG_PEEK) { - m = m->m_next; - moff = 0; - } else { - nextrecord = m->m_nextpkt; - sbfree(&so->so_rcv, m); - if (mp) { - *mp = m; - mp = &m->m_next; - so->so_rcv.sb_mb = m = m->m_next; - *mp = NULL; - } else { - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; - } - if (m) - m->m_nextpkt = nextrecord; - } - } else { - if ((flags & MSG_PEEK)) - moff += len; - else { - if (mp) - *mp = m_copym(m, 0, len); - m->m_data += len; - m->m_len -= len; - so->so_rcv.sb_cc -= len; - } - } - if (so->so_oobmark) { - if ((flags & MSG_PEEK) == 0) { - so->so_oobmark -= len; - if (so->so_oobmark == 0) { - so->so_state |= SS_RCVATMARK; - break; - } - } else { - offset += len; - if ((uint) offset == so->so_oobmark) - break; - } - } - if (flags & MSG_EOR) - break; - while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 && - !sosendallatonce(so) && !nextrecord) { - if (so->so_error || so->so_state & SS_CANTRCVMORE) - break; - error = sockbuf_wait(&so->so_rcv); - if (error) { - sbunlock(&so->so_rcv); - return 0; - } - if ((m = so->so_rcv.sb_mb)) - nextrecord = m->m_nextpkt; - } - } - - if (m && pr->pr_flags & PR_ATOMIC) { - flags |= MSG_TRUNC; - if ((flags & MSG_PEEK) == 0) - sockbuf_droprecord(&so->so_rcv); - } - if ((flags & MSG_PEEK) == 0) { - if (!m) - so->so_rcv.sb_mb = nextrecord; - if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) - (*pr->pr_userreq)(so, PRU_RCVD, (struct mbuf*)flags, NULL, NULL); - } - if (orig_resid == uio->uio_resid && orig_resid && - (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { - sbunlock(&so->so_rcv); - goto restart; - } - if (flagsp) - *flagsp |= flags; - -release: - sbunlock(&so->so_rcv); - return error; -} - -int socket_ioctl(struct socket *so, int cmd, caddr_t data) -{ - switch (cmd) { - case FIONBIO: - if (*(int*)data) - so->so_state |= SS_NBIO; - else - so->so_state &= ~SS_NBIO; - return 0; - case FIONREAD: - /* how many bytes do we have waiting... */ - *(int*)data = so->so_rcv.sb_cc; - return 0; - case SIOCATMARK: - *(int*)data = (so->so_state & SS_RCVATMARK) != 0; - return 0; - } - - if (IOCGROUP(cmd) == 'i') { - return ifioctl(so, cmd, data); - } - if (IOCGROUP(cmd) == 'r') { - return EINVAL; /* EOPNOTSUPP */ - } - return (*so->so_proto->pr_userreq)(so, PRU_CONTROL, - (struct mbuf*)cmd, (struct mbuf*)data, NULL); -} - - -int socket_close(struct socket *so) -{ - int error = 0; - - /* we don't want any more events... */ - so->event_callback = NULL; - so->event_callback_cookie = NULL; - - if (so->so_options & SO_ACCEPTCONN) { - while (so->so_q0) - (*so->so_proto->pr_userreq)(so, PRU_ABORT, NULL, NULL, NULL); - while (so->so_q) - (*so->so_proto->pr_userreq)(so, PRU_ABORT, NULL, NULL, NULL); - } - - if (so->so_pcb == NULL) - goto discard; - - if (so->so_state & SS_ISCONNECTED) { - if ((so->so_state & SS_ISDISCONNECTING) == 0) { - error = sodisconnect(so); - if (error) - goto drop; - } - if (so->so_options & SO_LINGER) { - if ((so->so_state & SS_ISDISCONNECTING) && - (so->so_state & SS_NBIO)) - goto drop; - while (so->so_state & SS_ISCONNECTED) - if ((error = nsleep(so->so_timeo, "lingering close", so->so_linger))) - break; - } - } - -drop: - if (so->so_pcb) { - int error2 = (*so->so_proto->pr_userreq)(so, PRU_DETACH, NULL, NULL, NULL); - if (error2 == 0) - error = error2; - } - -discard: - if (so->so_state & SS_NOFDREF) - printf("PANIC: socket_close: NOFDREF"); - so->so_state |= SS_NOFDREF; - sofree(so); - return error; -} - -int sorflush(struct socket *so) -{ - struct sockbuf *sb = &so->so_rcv; - struct sockbuf asb; - - sb->sb_flags |= SB_NOINTR; - sblock(sb, M_WAITOK); - socket_set_cantrcvmore(so); - sbunlock(sb); - asb = *sb; - memset(sb, 0, sizeof(*sb)); - - sockbuf_release(&asb); - return 0; -} - -int sodisconnect(struct socket *so) -{ - int error; - - if ((so->so_state & SS_ISCONNECTED) == 0) { - error = ENOTCONN; - goto bad; - } - if (so->so_state & SS_ISDISCONNECTING) { - error = EALREADY; - goto bad; - } - error = so->so_proto->pr_userreq(so, PRU_DISCONNECT, - NULL, NULL, NULL); - -bad: - return error; -} - -static void sofree(struct socket *so) -{ - if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) - return; - - if (so->so_head) { - if (!soqremque(so, 0) && !soqremque(so, 1)) { - printf("PANIC: sofree: couldn't dq socket\n"); - return; - } - so->so_head = NULL; - } - sockbuf_release(&so->so_snd); - sorflush(so); - - delete_sem(so->so_rcv.sb_pop); - delete_sem(so->so_snd.sb_pop); - delete_sem(so->so_timeo); - delete_sem(so->so_rcv.sb_sleep); - delete_sem(so->so_snd.sb_sleep); - - pool_put(spool, so); - - return; -} - -int socket_setsockopt(struct socket *so, int level, int optnum, const void *data, size_t datalen) -{ - struct mbuf *m, *m0; - int error = 0; - - m = m_get(MT_SOOPTS); - if (!m) - return ENOMEM; - if (memcpy(mtod(m, void*), data, datalen) == NULL) - return ENOMEM; - m->m_len = datalen; - m0 = m; - - if (level != (int) SOL_SOCKET) { - if (so->so_proto && so->so_proto->pr_ctloutput) - return (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, level, optnum, &m0); - error = ENOPROTOOPT; - } else { - switch (optnum) { - case SO_LINGER: - if (datalen != sizeof(struct linger)) { - error = EINVAL; - goto bad; - } - so->so_linger = mtod(m, struct linger*)->l_linger; - /* fall thru... */ - case SO_DEBUG: - case SO_KEEPALIVE: - case SO_DONTROUTE: - case SO_USELOOPBACK: - case SO_BROADCAST: - case SO_REUSEADDR: - case SO_REUSEPORT: - case SO_OOBINLINE: - case SO_NONBLOCK: - if (datalen < sizeof(int)) { - error = EINVAL; - goto bad; - } - if (*mtod(m, int*)) - so->so_options |= optnum; - else - so->so_options &= ~optnum; - - if (optnum == SO_NONBLOCK) { - if (so->so_options & SO_NONBLOCK) - so->so_state |= SS_NBIO; - else - so->so_state &= ~SS_NBIO; - } - break; - - case SO_SNDBUF: - case SO_RCVBUF: - case SO_SNDLOWAT: - case SO_RCVLOWAT: - if (datalen < sizeof(int)) { - error = EINVAL; - goto bad; - } - switch (optnum) { - case SO_SNDBUF: - case SO_RCVBUF: - if (sockbuf_reserve(optnum == SO_SNDBUF ? &so->so_snd : &so->so_rcv, - (uint32)*mtod(m, int32*)) == 0) { - error = ENOBUFS; - goto bad; - } - break; - case SO_SNDLOWAT: - so->so_snd.sb_lowat = *mtod(m, int*); - break; - case SO_RCVLOWAT: - so->so_rcv.sb_lowat = *mtod(m, int*); - break; - } - break; - case SO_SNDTIMEO: - case SO_RCVTIMEO: - /* bsd has the timeouts as int16, we're using int32... */ - { - struct timeval *tv; - int32 val; - - if (datalen < sizeof(*tv)) { - error = EINVAL; - goto bad; - } - tv = mtod(m, struct timeval *); - val = tv->tv_sec * 1000000 + tv->tv_usec; - switch (optnum) { - case SO_SNDTIMEO: - so->so_snd.sb_timeo = val; - break; - case SO_RCVTIMEO: - so->so_rcv.sb_timeo = val; - break; - } - break; - } - default: - error = ENOPROTOOPT; - } - if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { - (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, level, optnum, &m0); - m = NULL; - } - } -bad: - if (m) - m_free(m); - - return error; -} - -int socket_getsockopt(struct socket *so, int level, int optnum, void *data, size_t *datalen) -{ - struct mbuf *m; - - m = m_get(MT_SOOPTS); - if (memcpy(mtod(m, void*), data, *datalen) == NULL) - return ENOMEM; - if (*datalen < sizeof(int)) - return EINVAL; - m->m_len = sizeof(int); - - if (level != (int) SOL_SOCKET) { - if (so->so_proto && so->so_proto->pr_ctloutput) { - return (*so->so_proto->pr_ctloutput)(PRCO_GETOPT, so, level, optnum, &m); - } else - return ENOPROTOOPT; - } else { - switch(optnum) { - case SO_LINGER: - m->m_len = sizeof(struct linger); - mtod(m, struct linger*)->l_onoff = so->so_options & SO_LINGER; - mtod(m, struct linger*)->l_linger = so->so_linger; - break; - case SO_DEBUG: - case SO_KEEPALIVE: - case SO_DONTROUTE: - case SO_USELOOPBACK: - case SO_BROADCAST: - case SO_REUSEADDR: - case SO_REUSEPORT: - case SO_OOBINLINE: - *mtod(m, int*) = so->so_options & optnum; - break; - case SO_TYPE: - *mtod(m, int*) = so->so_type; - break; - case SO_ERROR: - *mtod(m, int*) = so->so_error; - so->so_error = 0; /* cleared once read */ - break; - case SO_SNDBUF: - *mtod(m, int*) = so->so_snd.sb_hiwat; - break; - case SO_RCVBUF: - *mtod(m, int*) = so->so_rcv.sb_hiwat; - break; - case SO_SNDLOWAT: - *mtod(m, int*) = so->so_snd.sb_lowat; - break; - case SO_RCVLOWAT: - *mtod(m, int*) = so->so_rcv.sb_lowat; - break; - case SO_SNDTIMEO: - case SO_RCVTIMEO: - { - int32 val = (optnum == SO_SNDTIMEO ? so->so_snd.sb_timeo : so->so_rcv.sb_timeo); - - m->m_len = sizeof(struct timeval); - mtod(m, struct timeval*)->tv_sec = val / 1000000; - mtod(m, struct timeval*)->tv_usec = val % 1000000; - break; - } - default: - m_free(m); - return ENOPROTOOPT; - } - if (m->m_len > *datalen) - /* XXX - horrible fudge... */ - m->m_len = *datalen; - memcpy(data, mtod(m, void *), m->m_len); - *datalen = m->m_len; - return 0; - } -} - - -int socket_set_event_callback(struct socket *so, socket_event_callback cb, void * cookie, int event) -{ - so->event_callback = cb; - so->event_callback_cookie = cookie; - if (cb) { - if (event == 3) - so->sel_ev |= SEL_EX; - else - so->sel_ev |= event; - } else { - if (event == 3) - so->sel_ev &= ~SEL_EX; - else - so->sel_ev &= ~event; - } - checkevent(so); /* notify any event condition ASAP! */ - return B_OK; -} - - -static int checkevent(struct socket *so) -{ - if (!so || !so->event_callback) - return B_OK; - - /* XXX - The checks here may seem a bit excessive, but we have a race - * condition here. If we're checking for soreadable() in one - * thread while we're closing in another, things will blow up as - * so->event_callback will have been set to NULL. - * - * ??? Maybe we should lock the socket for things like this? - */ - if (so && (so->sel_ev & SEL_READ) && soreadable(so)) { - if (so->event_callback) - so->event_callback(so, 1, so->event_callback_cookie); - so->sel_ev &= ~SEL_READ; - } - if (so && (so->sel_ev & SEL_WRITE) && sowriteable(so)) { - if (so->event_callback) - so->event_callback(so, 2, so->event_callback_cookie); - so->sel_ev &= ~SEL_WRITE; - } - if (so && (so->sel_ev & SEL_EX) && - (so->so_oobmark || (so->so_state & SS_RCVATMARK))) { - if (so->event_callback) - so->event_callback(so, 3, so->event_callback_cookie); - so->sel_ev &= ~SEL_EX; - } - - return B_OK; -} - -void sowakeup(struct socket *so, struct sockbuf *sb) -{ - if (!so || !sb) - return; - - sb->sb_flags &= ~SB_SEL; - if (sb->sb_flags & SB_WAIT) { - sb->sb_flags &= ~SB_WAIT; - /* release the lock here... */ - release_sem_etc(sb->sb_pop, 1, B_CAN_INTERRUPT); - } - checkevent(so); -} - -static void soqinsque(struct socket *head, struct socket *so, int q) -{ - struct socket **prev; - so->so_head = head; - if (q == 0) { - head->so_q0len++; - so->so_q0 = 0; - for (prev = &(head->so_q0); *prev; ) - prev = &((*prev)->so_q0); - } else { - head->so_qlen++; - so->so_q = NULL; - for (prev = &(head->so_q); *prev; ) - prev = &((*prev)->so_q); - } - *prev = so; -} - -static int soqremque(struct socket *so, int q) -{ - struct socket *head, *prev, *next; - - head = so->so_head; - prev = head; - for (;;) { - next = q ? prev->so_q : prev->so_q0; - if (next == so) - break; - if (next == NULL) - return 0; - prev = next; - } - if (q == 0) { - prev->so_q0 = next->so_q0; - head->so_q0len--; - } else { - prev->so_q = next->so_q; - head->so_qlen--; - } - next->so_q0 = next->so_q = 0; - next->so_head = 0; - return 1; -} - -void socket_set_hasoutofband(struct socket *so) -{ - /* Should we signal the process with SIGURG??? */ - checkevent(so); -} - -void socket_set_cantsendmore(struct socket *so) -{ - so->so_state |= SS_CANTSENDMORE; - sowwakeup(so); -} - -void socket_set_cantrcvmore(struct socket *so) -{ - so->so_state |= SS_CANTRCVMORE; - sorwakeup(so); -} - -void socket_set_connecting(struct socket *so) -{ - so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= SS_ISCONNECTING; -} - -void socket_set_connected(struct socket *so) -{ - struct socket *head = so->so_head; - - so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); - so->so_state |= SS_ISCONNECTED; - if (head && soqremque(so, 0)) { - soqinsque(head, so, 1); - sorwakeup(head); - wakeup(head->so_timeo); - } else { - wakeup(so->so_timeo); - sorwakeup(so); - sowwakeup(so); - } -} - -void socket_set_disconnecting(struct socket *so) -{ - so->so_state &= ~SS_ISCONNECTING; - so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); - wakeup(so->so_timeo); - sowwakeup(so); - sorwakeup(so); -} - -void socket_set_disconnected(struct socket *so) -{ - so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); - wakeup(so->so_timeo); - sowwakeup(so); - sorwakeup(so); -} - -int nsleep(sem_id chan, char *msg, int timeo) -{ - status_t rv; -// printf("nsleep: %s (%ld)\n", msg, chan); - - if (timeo > 0) - rv = acquire_sem_etc(chan, 1, B_TIMEOUT|B_CAN_INTERRUPT, timeo); - else - rv = acquire_sem_etc(chan, 1, B_CAN_INTERRUPT, 0); - - if (rv == B_TIMED_OUT) { - printf ("nsleep: EWOULDBLOCK\n"); - return EWOULDBLOCK; - } - if (rv == B_INTERRUPTED) - return EINTR; - return 0; -} - -void wakeup(sem_id chan) -{ - /* we should release as many as are waiting... - * the number 100 is just something that shuld be large enough... - */ - release_sem_etc(chan, 100, B_CAN_INTERRUPT | B_DO_NOT_RESCHEDULE); -} - -/* This file is too big - split it up!! */ -int socket_getsockname(struct socket *so, struct sockaddr *sa, int *alen) -{ - struct mbuf *m = m_getclr(MT_SONAME); - int len; - int error; - - if (!m) - return ENOBUFS; - memcpy(&len, alen, sizeof(len)); - error = (*so->so_proto->pr_userreq)(so, PRU_SOCKADDR, NULL, m, NULL); - if (error == 0) { - if (len > (int) m->m_len) - len = m->m_len; - memcpy(sa, mtod(m, caddr_t), len); - memcpy(alen, &len, sizeof(len)); - } - m_freem(m); - return error; -} - -int socket_getpeername(struct socket *so, struct sockaddr *sa, int * alen) -{ - struct mbuf *m = m_getclr(MT_SONAME); - int len; - int error; - - if (!m) - return ENOBUFS; - if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) - return ENOTCONN; - memcpy(&len, alen, sizeof(len)); - error = (*so->so_proto->pr_userreq)(so, PRU_PEERADDR, NULL, m, NULL); - if (error == 0) { - if (len > (int) m->m_len) - len = m->m_len; - memcpy(sa, mtod(m, caddr_t), len); - memcpy(alen, &len, sizeof(len)); - } - m_freem(m); - return error; -} - -int socket_accept(struct socket *so, struct socket **nso, void *data, int *alen) -{ - int len; - int error; - struct mbuf *nam; - - if (data) - memcpy(&len, alen, sizeof(len)); - if ((so->so_options & SO_ACCEPTCONN) == 0) - return EINVAL; - if ((so->so_state & SS_NBIO) && so->so_qlen == 0) - return EWOULDBLOCK; - while (so->so_qlen == 0 && so->so_error == 0) { - if (so->so_state & SS_CANTRCVMORE) { - so->so_error = ECONNABORTED; - break; - } - if ((error = nsleep(so->so_timeo, "socket_accept", 0))) - return error; - } - if (so->so_error) { - error = so->so_error; - so->so_error = 0; - return error; - } - - { - struct socket *aso = so->so_q; - if (soqremque(aso, 1) == 0) { - printf("PANIC: socket_accept!\n"); - return ENOMEM; - } - so = aso; - } - nam = m_get(MT_SONAME); - so->so_state &= ~SS_NOFDREF; - error = (*so->so_proto->pr_userreq)(so, PRU_ACCEPT, NULL, nam, NULL); - if (data) { - if (len > (int) nam->m_len) - len = nam->m_len; - if (memcpy(data, mtod(nam, caddr_t), len) == NULL) - memcpy(alen, (caddr_t)&len, sizeof(len)); - } - m_freem(nam); - - /* assign the socket to the cookie passed in! */ - *nso = so; - return error; -} - - -int -socket_socketpair(struct socket *so, struct socket **nso) -{ - // TODO : implement, eventually fill nso with a new cookie - return ENOSYS; -} - diff --git a/src/add-ons/kernel/network/interfaces/Jamfile b/src/add-ons/kernel/network/interfaces/Jamfile deleted file mode 100644 index fe8d9e7841..0000000000 --- a/src/add-ons/kernel/network/interfaces/Jamfile +++ /dev/null @@ -1,5 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network interfaces ; - -SubInclude HAIKU_TOP src add-ons kernel network interfaces ethernet ; -SubInclude HAIKU_TOP src add-ons kernel network interfaces loopback ; -SubInclude HAIKU_TOP src add-ons kernel network interfaces ppp ; diff --git a/src/add-ons/kernel/network/interfaces/ethernet/Jamfile b/src/add-ons/kernel/network/interfaces/ethernet/Jamfile deleted file mode 100644 index 5bfa74aa4f..0000000000 --- a/src/add-ons/kernel/network/interfaces/ethernet/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network interfaces ethernet ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon ethernet : kernel obos_network interfaces : - ethernet.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/interfaces - : ethernet ; - -Package haiku-networkingkit-cvs : - ethernet : - boot home config add-ons kernel obos_network interfaces ; diff --git a/src/add-ons/kernel/network/interfaces/ethernet/ethernet.c b/src/add-ons/kernel/network/interfaces/ethernet/ethernet.c deleted file mode 100644 index bc9741d750..0000000000 --- a/src/add-ons/kernel/network/interfaces/ethernet/ethernet.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* ethernet.c - * ethernet encapsulation - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "protocols.h" -#include "netinet/in_var.h" -#include "sys/protosw.h" -#include "net/if.h" -#include "net/if_arp.h" -#include "net/if_dl.h" -#include "netinet/if_ether.h" -#include "sys/socket.h" -#include "sys/sockio.h" -#include "net/route.h" - -#include "core_module.h" -#include "core_funcs.h" -#include "net_timer.h" -#include "ether_driver.h" - -#include "ethernet_module.h" - -#include -#define printf dprintf - -/* forward prototypes */ -int ether_dev_start(ifnet *dev); -int ether_dev_stop (ifnet *dev); - -status_t std_ops(int32 op, ...); - -/* Local variables */ -static struct protosw *proto[IPPROTO_MAX]; -static struct core_module_info *core = NULL; -static net_timer_id arptimer_id; -static struct ether_device *ether_devices = NULL; /* list of ethernet devices */ -static struct ifq *etherq = NULL; -static thread_id ether_rxt = -1; -static int arpt_prune = (5 * 60); /* time interval we prune the arp cache? 5 minutes */ -static int arpt_keep = (20 * 60); /* length of time we keep entries... (20 mins) */ -static int arpt_down = 20; /* seconds between arp flooding */ -static int arp_maxtries = 5; /* max tries before a pause */ -static int32 arp_inuse = 0; /* how many entries do we have? */ -static int32 arp_allocated = 0; /* how many arp entries have we created? */ - -/* Prototypes */ -int32 ether_input(void *data); -int ether_output(struct ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0); -static int ether_ioctl(struct ifnet *ifp, ulong cmd, caddr_t data); -int ether_dev_attach(ifnet *dev); -int ether_dev_stop(ifnet *dev); -void arp_rtrequest(int req, struct rtentry *rt, struct sockaddr *sa); -static void arpinput(struct mbuf *m); -static void arpwhohas(struct arpcom *ac, struct in_addr *ia); - - -#define DRIVER_DIRECTORY "/dev/net" -#define SIN(s) ((struct sockaddr_in*)s) -#define SDL(s) ((struct sockaddr_dl*)s) -#define rt_expire rt_rmx.rmx_expire - -static uint8 ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -static ethernet_receiver_func pppoe_receiver = NULL; - -struct llinfo_arp llinfo_arp; -struct in_ifaddr *primary_addr; - -static char digits[] = "0123456789abcdef"; - -static char *ether_sprintf(uint8 *ap) -{ - register int i; - static char etherbuf[18]; - register char *cp = etherbuf; - - for (i = 0; i < 6; i++) { - *cp++ = digits[*ap >> 4]; - *cp++ = digits[*ap++ & 0xf]; - *cp++ = ':'; - } - *--cp = 0; - return (etherbuf); -} - -#if ARP_DEBUG -static void dump_arp(void *buffer) -{ - struct ether_arp *arp = (struct ether_arp *)buffer; - - printf("arp request :\n"); - printf(" : hardware type : %s\n", - ntohs(arp->arp_hrd) == ARPHRD_ETHER ? "ethernet" : "unknown"); - printf(" : protocol type : %s\n", - ntohs(arp->arp_pro) == ETHERTYPE_IP ? "IPv4" : "unknown"); - printf(" : hardware size : %d\n", arp->arp_hln); - printf(" : protocol size : %d\n", arp->arp_pln); - printf(" : op code : "); - switch(ntohs(arp->arp_op)) { - case ARPOP_REPLY: - printf("ARP Reply\n"); - break; - case ARPOP_REQUEST: - printf("ARP Request\n"); - break; - default: - printf("Who knows? %04x\n", ntohs(arp->arp_op)); - } - printf(" : sender : %s", ether_sprintf(&arp->arp_sha)); - printf(" [%08lx]\n", ntohl(*(uint32*)&arp->arp_spa)); - printf(" : target : %s", ether_sprintf(&arp->arp_tha)); - printf(" [%08lx]\n", ntohl(*(uint32*)&arp->arp_tpa)); -} -#endif /* ARP_DEBUG */ - - -static void set_ethernet_receiver(ethernet_receiver_func func) -{ -#if DEBUG - printf("ethernet: set_ethernet_receiver()\n"); -#endif - - pppoe_receiver = func; -} - - -static void unset_ethernet_receiver(void) -{ -#if DEBUG - printf("ethernet: unset_ethernet_receiver()\n"); -#endif - - pppoe_receiver = NULL; -} - - -/* We now actually attach the device to the system... */ -static void attach_device(int devid, char *driver, char *devno) -{ - struct ether_device *ed; - struct ifnet *ifp; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - status_t status; - int fsz = 0; - - ed = (struct ether_device*) malloc(sizeof(struct ether_device)); - if (!ed) - return; - memset(ed, 0, sizeof(*ed)); - ifp = &ed->sc_if; - - /* get the MAC address... */ - status = ioctl(devid, ETHER_GETADDR, &ed->sc_addr, 6); - if (status < B_OK) { - printf("%s/%s: ignored: Failed to get a MAC address\n", driver, devno); - close(devid); - free(ed); - return; - } - /* Try to detrmine the MTU to use */ - status = ioctl(devid, ETHER_GETFRAMESIZE, &fsz, sizeof(fsz)); - if (status < 0) { - printf("%s/%s: ETHER_GETFRAMESIZE not supported, defaulting to %d\n", - driver, devno, ETHERMTU); - ifp->if_mtu = ETHERMTU; - } else - ifp->if_mtu = fsz; - - ifp->devid = -1; - ifp->if_type = IFT_ETHER; - ifp->name = strdup(driver); - ifp->if_unit = atoi(devno); - ifp->if_hdrlen = 14; - ifp->if_addrlen = 6; - ifp->if_flags |= (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); - - ifp->rx_thread = -1; - ifp->tx_thread = -1; - ifp->devq = etherq; - - ifp->input = NULL;//ðer_input; - ifp->output = ðer_output; - ifp->stop = ðer_dev_stop; - ifp->ioctl = ðer_ioctl; - - if_attach(ifp); - - /* Add the MAC address to our list of addresses... */ - for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { - if ((sdl = (struct sockaddr_dl*)ifa->ifa_addr) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_type = IFT_ETHER; - sdl->sdl_alen = ifp->if_addrlen; - memcpy(LLADDR(sdl), &ed->sc_addr, ifp->if_addrlen); - break; - } - } - - ed->next = NULL; /* we get added at the end of the list */ - /* we maintain our own list of devices as well as the global list */ - if (!ether_devices) { - ether_devices = ed; - } else { - struct ether_device *dptr = ether_devices; - while (dptr->next) - dptr = dptr->next; - - dptr->next = ed; - } -} - - -static void -open_device(char *driver, char *devno) -{ - status_t status; - int dev; - - char *path = malloc(B_PATH_NAME_LENGTH); - if (path == NULL) - return; - - sprintf(path, "%s/%s/%s", DRIVER_DIRECTORY, driver, devno); - dev = open(path, O_RDWR); - if (dev < B_OK) { - printf("Unable to open %s\n", path); - free(path); - return; - } - - status = ioctl(dev, ETHER_INIT, NULL, 0); - if (status == B_OK) - attach_device(dev, driver, devno); - - close(dev); - free(path); -}; - -#if 0 -static void find_devices(char *root) -{ - DIR *dir; - struct dirent *de; - struct stat st; - char path[1024]; - - dir = opendir(root); - if (!dir) { - printf("ethernet: Couldn't open the directory %s\n", root); - return; - }; - - while ((de = readdir(dir)) != NULL) { - if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) - continue; // skip pseudo-directories - - sprintf(path, "%s/%s", root, de->d_name); - - if (stat(path, &st) < 0) { - printf("ethernet: Can't stat(%s) entry! Skipping...\n", path); - continue; - }; - - if (S_ISDIR(st.st_mode)) - find_devices(path); - else if (S_ISCHR(st.st_mode)) { // char device = driver! - if (strcmp(de->d_name, "socket") == 0 || // OBOS old socket driver - strcmp(de->d_name, "stack") == 0 || // OBOS stack driver - strcmp(de->d_name, "server") == 0 || // OBOS server driver - strcmp(de->d_name, "api") == 0) // BONE stack driver - continue; // skip pseudo-entries - - open_device(path, de->d_name); - }; - }; - - closedir(dir); -} -#else - -static void -find_devices(void) -{ - DIR *dir, *driv_dir; - struct dirent *de, *dre; - char* path = malloc(B_PATH_NAME_LENGTH); - if (path == NULL) - return; - - dir = opendir(DRIVER_DIRECTORY); - if (!dir) { - printf("Couldn't open the directory %s\n", DRIVER_DIRECTORY); - free(path); - return; - } - - while ((de = readdir(dir)) != NULL) { - /* hmm, is it a driver? */ - if (!strcmp(de->d_name, ".") - || !strcmp(de->d_name, "..") - || !strcmp(de->d_name, "server") - || !strcmp(de->d_name, "stack")) - continue; - - /* OK we assume it's a driver...but skip the ether driver - * as I don't really know what it is! - */ - if (strcmp(de->d_name, "ether") == 0) - continue; - - sprintf(path, "%s/%s", DRIVER_DIRECTORY, de->d_name); - driv_dir = opendir(path); - if (!driv_dir) { - printf("I couldn't find any drivers in the %s driver directory\n", - de->d_name); - } else { - while ((dre = readdir(driv_dir)) != NULL) { - /* skip . and .. */ - if (strcmp(dre->d_name, ".") == 0 || - strcmp(dre->d_name, "..") == 0) - continue; - - open_device(de->d_name, dre->d_name); - } - closedir(driv_dir); - } - } - closedir(dir); - free(path); -} -#endif - - -#if DEBUG -static void dump_ether_details(struct mbuf *buf) -{ - struct ether_header *eth = mtod(buf, struct ether_header *); - - printf("Ethernet packet from %s", ether_sprintf(eth->ether_shost)); - printf(" to %s", ether_sprintf(eth->ether_dhost)); - - if (buf->m_flags & M_BCAST) - printf(" BCAST"); - - printf(" proto "); - switch (eth->ether_type) { - case ETHER_ARP: - printf("ARP\n"); - break; - case ETHER_RARP: - printf("RARP\n"); - break; - case ETHER_IPV4: - printf("IPv4\n"); - break; - case ETHER_IPV6: - printf("IPv6\n"); - break; - case ETHER_PPPOE_DISC: - printf("PPPoE Discovery\n"); - break; - - case ETHER_PPPOE_SESS: - printf("PPPoE Session\n"); - break; - - default: - printf("unknown (%04x)\n", eth->ether_type); - } -} -#endif - -int32 ether_input(void *data) -{ - struct mbuf *m; - struct ether_header *eth; - int len; - status_t error = B_OK; - - while (1) { - len = sizeof(struct ether_header); - error = acquire_sem_etc(etherq->pop, 1, B_CAN_INTERRUPT, 0); - if(error != B_NO_ERROR) - return error; - IFQ_DEQUEUE(etherq, m); - if (!m) - continue; - - eth = mtod(m, struct ether_header *); - eth->ether_type = ntohs(eth->ether_type); - - if (memcmp((void*)ð->ether_dhost, (void*)ðer_bcast, 6) == 0) - m->m_flags |= M_BCAST; - if (eth->ether_dhost[0] & 1) - m->m_flags |= M_MCAST; - -#if DEBUG - dump_ether_details(m); -#endif - // as PPPoE needs the ethernet header we process it before m_adj - if(eth->ether_type == ETHERTYPE_PPPOEDISC - || eth->ether_type == ETHERTYPE_PPPOE) { - if(pppoe_receiver) - pppoe_receiver(m); - else { - printf("PPPoE packet detected, but no handler found :(\n"); - m_freem(m); - } - - continue; - } - - m_adj(m, len); - - switch(eth->ether_type) { - case ETHERTYPE_ARP: - arpinput(m); - break; - case ETHERTYPE_IP: - if (proto[IPPROTO_IP] && proto[IPPROTO_IP]->pr_input) - proto[IPPROTO_IP]->pr_input(m, 0); - else - printf("proto[%d] = %p, not called...\n", IPPROTO_IP, - proto[IPPROTO_IP]); - break; - default: - printf("Couldn't process unknown protocol %04x\n", eth->ether_type); - m_freem(m); - } - } - - return error; -} - -#define senderr(e) { error = (e); goto bad; } - -int ether_output(struct ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0) -{ - struct ether_header *eh; - struct rtentry *rt; - struct arpcom *ac = (struct arpcom*)ifp; - uint8 edst[6]; - int off; - uint16 type; - struct mbuf *mcopy = NULL; - int error = 0; - - if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) - senderr(ENETDOWN); - - if ((rt = rt0)) { - if ((rt->rt_flags & RTF_UP) == 0) { - if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) - rt->rt_refcnt--; - else - senderr(EHOSTUNREACH); - } - if (rt->rt_flags & RTF_GATEWAY) { - if (!rt->rt_gwroute) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt0); - rt = rt0; -lookup: - rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); - - if ((rt = rt->rt_gwroute) == NULL) - senderr(EHOSTUNREACH); - } - } - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_expire == 0 || - rt->rt_expire > real_time_clock()) { - /* XXX - add test for expired here... */ - printf("flags & RTF_REJECT\n"); - printf("Error: %s\n", rt == rt0 ? "EHOSTDOWN" : "EHOSTUNREACH"); - senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } - } - - switch (dst->sa_family) { - case AF_INET: - if (!arpresolve(ac, rt, buf, dst, edst)) { - return 0; - } - if ((buf->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) - mcopy = m_copym(buf, 0, (int)M_COPYALL); - off = buf->m_pkthdr.len - buf->m_len; - type = ETHERTYPE_IP; - break; - case AF_UNSPEC: - eh = (struct ether_header*)dst->sa_data; - memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof(edst)); - type = eh->ether_type; - break; - } - -/* Hmmm, can't find a good way of getting this to work without expanding the - * macro for the kernel case, so it's here expanded. I've found that using the - * directly causes segafults. Bear in mind we want ALL allocation/free actions - * to take place in the core to keep as small a memory footprint as possible. - */ -#define M_LEADINGSPACE(m) \ - ((m)->m_flags & M_EXT ? (m)->m_data - (m)->m_ext.ext_buf : \ - (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \ - (m)->m_data - (m)->m_dat) - - if (M_LEADINGSPACE(buf) >= (int32) sizeof(struct ether_header)) { - buf->m_data -= sizeof(struct ether_header); - buf->m_len += sizeof(struct ether_header); - } else - buf = m_prepend(buf, sizeof(struct ether_header)); - if (buf && buf->m_flags & M_PKTHDR) - buf->m_pkthdr.len += sizeof(struct ether_header); - - if (buf == NULL) - senderr(ENOMEM); - eh = mtod(buf, struct ether_header*); - type = htons(type); - memcpy(&eh->ether_type, &type, sizeof(eh->ether_type)); - memcpy(&eh->ether_dhost, edst, sizeof(edst)); - memcpy(&eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost)); - - IFQ_ENQUEUE(ifp->txq, buf); - - return error; -bad: - if (buf) - m_free(buf); - printf("ether_output: returning %d\n", error); - return error; -} - -static struct llinfo_arp *arplookup(uint32 addr, int create, int proxy) -{ - struct rtentry *rt; - static struct sockaddr_inarp sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(sin); - sin.sin_addr.s_addr = addr; - sin.sin_other = proxy ? SIN_PROXY : 0; - rt = rtalloc1((struct sockaddr*) &sin, create); - if (!rt) - return NULL; - rt->rt_refcnt--; - if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || - rt->rt_gateway->sa_family != AF_LINK) { - if (create) - printf("arptnew failed on %08lx\n", ntohl(addr)); - return NULL; - } - return ((struct llinfo_arp *)rt->rt_llinfo); -} - -int arpresolve(struct arpcom *ac, struct rtentry *rt, struct mbuf *m, - struct sockaddr *dst, uint8 *desten) -{ - struct llinfo_arp *la; - struct sockaddr_dl *sdl; - - if (m->m_flags & M_BCAST) { - memcpy(desten, ðer_bcast, sizeof(ether_bcast)); - return 1; - } - if (m->m_flags & M_MCAST) { - ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten); - return 1; - } - - if (rt) { - la = (struct llinfo_arp*) rt->rt_llinfo; - } else { - if ((la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0))) - rt = la->la_rt; - } - if (la == NULL || rt == NULL) { - printf("arpresolve: can't allocate llinfo!\n"); - m_freem(m); - return 0; - } - sdl = SDL(rt->rt_gateway); - - if ((rt->rt_expire == 0 || rt->rt_expire > real_time_clock()) && - sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { - memcpy(desten, LLADDR(sdl), sdl->sdl_alen); - return 1; - } - - if (la->la_hold) { - m_freem(la->la_hold); - } - - la->la_hold = m; - - if (rt->rt_expire) { - rt->rt_flags &= ~RTF_REJECT; - if (la->la_asked == 0 || rt->rt_expire != real_time_clock()) { - rt->rt_expire = real_time_clock(); - if (la->la_asked++ < arp_maxtries) { - arpwhohas(ac, &(SIN(dst)->sin_addr)); - } else { - rt->rt_flags |= RTF_REJECT; - rt->rt_expire += arpt_down; - la->la_asked = 0; - } - } - } - return 0; -} - -static void arptfree(struct llinfo_arp *la) -{ - struct rtentry *rt = la->la_rt; - struct sockaddr_dl *sdl; - - if (rt == NULL) - return; - if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && - sdl->sdl_family == AF_LINK) { - sdl->sdl_alen = 0; - la->la_asked = 0; - rt->rt_flags &= ~RTF_REJECT; - return; - } - rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL); -} - -static void arptimer(void *data) -{ - struct llinfo_arp *la = llinfo_arp.la_next; - while (la != &llinfo_arp) { - struct rtentry *rt = la->la_rt; - la = la->la_next; - if (rt->rt_expire && rt->rt_expire <= real_time_clock()) - arptfree(la->la_prev); - } - return; -} - -static void arprequest(struct arpcom *ac, uint32 *sip, uint32 *tip, uint8 *enaddr) -{ - struct mbuf *m; - struct ether_header *eh; - struct ether_arp *ea; - struct sockaddr sa; - - if ((m = m_gethdr(MT_DATA)) == NULL) - return; - m->m_len = sizeof(*ea); - m->m_pkthdr.len = sizeof(*ea); - MH_ALIGN(m, sizeof(*ea)); - - ea = mtod(m, struct ether_arp*); - eh = (struct ether_header*) sa.sa_data; - memset(ea, 0, sizeof(*ea)); - - memcpy(eh->ether_dhost, ðer_bcast, sizeof(eh->ether_dhost)); - eh->ether_type = ETHERTYPE_ARP; - - ea->arp_hrd = htons(ARPHRD_ETHER); - ea->arp_pro = htons(ETHERTYPE_IP); - ea->arp_hln = sizeof(ea->arp_sha); - ea->arp_pln = sizeof(ea->arp_spa); - ea->arp_op = htons(ARPOP_REQUEST); - - memcpy((caddr_t)ea->arp_sha, (caddr_t)enaddr, sizeof(ea->arp_sha)); - memcpy(ea->arp_spa, sip, sizeof(ea->arp_spa)); - memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa)); - - sa.sa_family = AF_UNSPEC; - sa.sa_len = sizeof(sa); - - (*ac->ac_if.output)(&ac->ac_if, m, &sa, NULL); -} - -static void arpwhohas(struct arpcom *ac, struct in_addr *ia) -{ - arprequest(ac, &ac->ac_ipaddr.s_addr, &ia->s_addr, ac->ac_enaddr); -} - - -void arp_rtrequest(int req, struct rtentry *rt, struct sockaddr *sa) -{ - struct sockaddr *gate = rt->rt_gateway; - static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; - struct llinfo_arp *la = (struct llinfo_arp*)rt->rt_llinfo; - - if (rt->rt_flags & RTF_GATEWAY) - return; - - switch (req) { - case RTM_ADD: - if ((rt->rt_flags & RTF_HOST) == 0 && - SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) - rt->rt_flags |= RTF_CLONING; - if (rt->rt_flags & RTF_CLONING) { - rt_setgate(rt, rt_key(rt), (struct sockaddr*)&null_sdl); - gate = rt->rt_gateway; - SDL(gate)->sdl_type = rt->rt_ifp->if_type; - SDL(gate)->sdl_index = rt->rt_ifp->if_index; - rt->rt_expire = real_time_clock(); - break; - } - if (rt->rt_flags & RTF_ANNOUNCE) - arprequest((struct arpcom*) rt->rt_ifp, - &SIN(rt_key(rt))->sin_addr.s_addr, - &SIN(rt_key(rt))->sin_addr.s_addr, - (uint8*)LLADDR(SDL(gate))); - case RTM_RESOLVE: - if (gate->sa_family != AF_LINK || - gate->sa_len < sizeof(null_sdl)) { - printf("arp_rtrequest: bad gateway value!\n"); - break; - } - SDL(gate)->sdl_type = rt->rt_ifp->if_type; - SDL(gate)->sdl_index = rt->rt_ifp->if_index; - if (la) - break; - - R_Malloc(la, struct llinfo_arp *, sizeof(*la)); - if (!la) { - printf("arp_rtrequest: malloc failed!\n"); - break; - } - rt->rt_llinfo = (caddr_t)la; - arp_inuse++, arp_allocated++; - Bzero(la, sizeof(*la)); - - la->la_rt = rt; - rt->rt_flags |= RTF_LLINFO; - insque(la, &llinfo_arp); - - if (SIN(rt_key(rt))->sin_addr.s_addr == - (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { - rt->rt_expire = 0; - Bcopy(((struct arpcom*)rt->rt_ifp)->ac_enaddr, - LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); -/* -XXX - add function to get the ifnet * for the loopback from the "core" - and ability to find the loopback device when added. - if (useloopback) - rt->rt_ifp = &loif; -*/ - } - break; - case RTM_DELETE: - if (!la) - break; - arp_inuse--; - remque(la); - rt->rt_llinfo = NULL; - rt->rt_flags &= ~ RTF_LLINFO; - if (la->la_hold) - m_freem(la->la_hold); - Free((caddr_t)la); - } -} - -static void arpinput(struct mbuf *m) -{ - struct ether_arp *ea; - struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif; - struct ether_header *eh; - struct llinfo_arp *la = NULL; - struct in_ifaddr *ia = NULL, *maybe_ia = NULL; - struct in_addr isaddr, itaddr, myaddr; - struct rtentry *rt; - int op; - struct sockaddr_dl *sdl; - struct sockaddr sa; - -#if ARP_DEBUG - dump_arp(mtod(m, void*)); -#endif - - if (!primary_addr) - primary_addr = get_primary_addr(); - - ea = mtod(m, struct ether_arp *); - op = ntohs(ea->arp_op); - memcpy(&isaddr, ea->arp_spa, sizeof(isaddr)); - memcpy(&itaddr, ea->arp_tpa, sizeof(isaddr)); - - /* find out if it's for us... */ - for (ia = primary_addr;ia ; ia = ia->ia_next) - if (ia->ia_ifp == &ac->ac_if) { - maybe_ia = ia; - if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || - (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) - break; - } - if (!maybe_ia) - goto out; - - myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; - - if (!memcmp(ac->ac_enaddr, ea->arp_sha, sizeof(ea->arp_sha))) - goto out; - if (!memcmp(ea->arp_sha, ðer_bcast, sizeof(ea->arp_sha))) { - printf("arp_input: ether address was broadcast for %08lx\n", - htonl(isaddr.s_addr)); - goto out; - } - if (isaddr.s_addr == myaddr.s_addr) { - printf("arp_input: duplicate IP address sent from %s\n", - ether_sprintf(ea->arp_sha)); - itaddr = myaddr; - goto reply; - } - la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0); - if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) { - if (sdl->sdl_alen && memcmp(ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) - printf("arp info overwritten for %08lx by %s\n", - isaddr.s_addr, ether_sprintf(ea->arp_sha)); - memcpy(LLADDR(sdl), ea->arp_sha, sdl->sdl_alen = sizeof(ea->arp_sha)); - if (rt->rt_expire) { - rt->rt_expire = real_time_clock() + arpt_keep; - } - rt->rt_flags &= ~RTF_REJECT; - la->la_asked = 0; - if (la->la_hold) { - (*ac->ac_if.output)(&ac->ac_if, la->la_hold, rt_key(rt), rt); - la->la_hold = NULL; - } - } - -reply: - if (op != ARPOP_REQUEST) { -out: - return; - } - - if (itaddr.s_addr == myaddr.s_addr) { - memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); - memcpy(ea->arp_sha, ac->ac_enaddr, sizeof(ea->arp_sha)); - } else { - la = arplookup(itaddr.s_addr, 0, SIN_PROXY); - if (la == NULL) - goto out; - rt = la->la_rt; - memcpy(ea->arp_tha, ea->arp_sha, sizeof(ea->arp_sha)); - sdl = SDL(rt->rt_gateway); - memcpy(ea->arp_sha, LLADDR(sdl), sizeof(ea->arp_sha)); - } - - memcpy(ea->arp_tpa, ea->arp_spa, sizeof(ea->arp_spa)); - memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa)); - ea->arp_op = htons(ARPOP_REPLY); - ea->arp_pro = htons(ETHERTYPE_IP); - eh = (struct ether_header *)sa.sa_data; - memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); - eh->ether_type = ETHERTYPE_ARP; - sa.sa_family = AF_UNSPEC; - sa.sa_len = sizeof(sa); - - (*ac->ac_if.output)(&ac->ac_if, m, &sa, NULL); - return; -} - -static void arp_init() -{ - llinfo_arp.la_next = llinfo_arp.la_prev = &llinfo_arp; - - arptimer_id = net_add_timer(&arptimer, NULL, arpt_prune * 1000000); - -} - -static int ether_ioctl(struct ifnet *ifp, ulong cmd, caddr_t data) -{ - struct arpcom *ac = (struct arpcom *)ifp; - struct ifaddr *ifa = (struct ifaddr*)data; - -#if DEBUG - printf("ether_ioctl(0x%lX)\n", cmd); -#endif - - if (ifp->devid == -1) { - char path[PATH_MAX]; - sprintf(path, "%s/%s/%d", DRIVER_DIRECTORY, ifp->name, ifp->if_unit); - ifp->devid = open(path, O_RDWR); - if (ifp->devid < 0) { - ifp->devid = -1; - return -1; - } - } - - if ((ifp->if_flags & IFF_UP) == 0 && - (ifp->rx_thread > 0 || ifp->tx_thread > 0)) { - /* shutdown our threads and remove the IFF_RUNNING flag... */ - if (ifp->rx_thread > 0) - kill_thread(ifp->rx_thread); - if (ifp->tx_thread > 0) - kill_thread(ifp->tx_thread); - ifp->rx_thread = ifp->tx_thread = -1; - ifp->if_flags &= ~IFF_RUNNING; - } - ifa->ifa_rtrequest = &arp_rtrequest; - - switch (cmd) { - case SIOCSIFADDR: -#if DEBUG - printf("ether_ioctl: SIOCSIFADDR\n"); -#endif - ifp->if_flags |= IFF_UP; - switch (ifa->ifa_addr->sa_family) { - case AF_INET: - ac->ac_ipaddr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr; -#if DEBUG - printf("setting ether_device ip address to %08lx\n", - ntohl(((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr)); -#endif - break; - default: - printf("don't know how to work with address family %d\n", - ifa->ifa_addr->sa_family); - } - break; - case SIOCSIFFLAGS: - printf("ether_ioctl: SIOCSIFFLAGS\n"); - break; - default: - printf("unhandled call to ethernet_ioctl\n"); - } - -#if DEBUG - printf("ether_ioctl: setting running flag\n"); -#endif - - if ((ifp->if_flags & IFF_UP) && - (ifp->rx_thread == -1 || ifp->tx_thread == -1)) { - /* start our threads and add the IFF_RUNNING flag... */ - if (ifp->rx_thread < 0) - start_rx_thread(ifp); - if (ifp->tx_thread < 0) - start_tx_thread(ifp); - ifp->if_flags |= IFF_RUNNING; - } - /* close and reset the devid so we don't try to use it again */ - if ((ifp->if_flags & IFF_UP) == 0) { - close(ifp->devid); - ifp->devid = -1; - } -#if DEBUG - printf("ether_ioctl: finished\n"); -#endif - return 0; -} - -int ether_dev_stop(ifnet *dev) -{ - dev->if_flags &= ~IFF_UP; - - /* should find better ways of doing this... */ - kill_thread(dev->rx_thread); - kill_thread(dev->tx_thread); - - return 0; -} - -static int ether_init(void *cpp) -{ -#if DEBUG - printf("ether_init()\n"); -#endif - - if (cpp) - core = (struct core_module_info*) cpp; - - etherq = start_ifq(); - ether_rxt = spawn_kernel_thread(ether_input, "ethernet_input", B_REAL_TIME_DISPLAY_PRIORITY, NULL); - if (ether_rxt > 0) - resume_thread(ether_rxt); - - find_devices(); // "/dev/net"); - - memset(proto, 0, sizeof(struct protosw *) * IPPROTO_MAX); - add_protosw(proto, NET_LAYER2); - arp_init(); - - return 0; -} - -static int ether_stop() -{ - struct ether_device *dptr = ether_devices, *odev; - stop_ifq(etherq); - etherq = NULL; - kill_thread(ether_rxt); - - while (dptr) { - odev = dptr; - dptr = odev->next; - free(odev); - } - - net_remove_timer(arptimer_id); - - return 0; -} - -struct ethernet_module_info device_info = { - { - { - NET_ETHERNET_MODULE_NAME, - 0, - std_ops - }, - - ether_init, - ether_stop, - NULL - }, - set_ethernet_receiver, - unset_ethernet_receiver -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info**)&core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - return B_OK; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info * modules[] = { - (module_info *) &device_info, - NULL -}; diff --git a/src/add-ons/kernel/network/interfaces/loopback/Jamfile b/src/add-ons/kernel/network/interfaces/loopback/Jamfile deleted file mode 100644 index 53dbc2a3ca..0000000000 --- a/src/add-ons/kernel/network/interfaces/loopback/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network interfaces loopback ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon loopback : kernel obos_network interfaces : - loopback.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/interfaces - : loopback ; - -Package haiku-networkingkit-cvs : - loopback : - boot home config add-ons kernel obos_network interfaces ; diff --git a/src/add-ons/kernel/network/interfaces/loopback/loopback.c b/src/add-ons/kernel/network/interfaces/loopback/loopback.c deleted file mode 100644 index d89c32c5d0..0000000000 --- a/src/add-ons/kernel/network/interfaces/loopback/loopback.c +++ /dev/null @@ -1,176 +0,0 @@ -/* loopback.c - loopback device - */ - -#include -#include -#include -#include - -#include "sys/socket.h" -#include "protocols.h" -#include "netinet/in.h" -#include "netinet/ip.h" -#include "sys/socketvar.h" -#include "sys/protosw.h" -#include "sys/domain.h" -#include "sys/sockio.h" - -#include "net_malloc.h" -#include "core_module.h" -#include "net_module.h" -#include "core_funcs.h" - -#include -#define printf dprintf - -status_t std_ops(int32 op, ...); - -static struct core_module_info *core = NULL; - -static struct protosw *proto[IPPROTO_MAX]; -static struct ifnet *me = NULL; - -static int loopback_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, - struct rtentry *rt) -{ - /* turn it straight back... */ - /* This is lame as we should be detecting the protocol, but it gets - * us working. - * XXX - fix me! - */ - struct ip *ip = mtod(m, struct ip *); - - ip->ip_dst = ip->ip_src; - ip->ip_src.s_addr = INADDR_LOOPBACK; - - IFQ_ENQUEUE(ifp->rxq, m); - return 0; -} - -static void loopback_input(struct mbuf *buf) -{ - if (!buf) - return; - - buf->m_pkthdr.rcvif = me; - - if (proto[IPPROTO_IP] && proto[IPPROTO_IP]->pr_input) { - proto[IPPROTO_IP]->pr_input(buf, 0); - return; - } else - printf("No input tourtine found for IP\n"); - - m_freem(buf); - return; -} - -static int loopback_dev_stop(struct ifnet *dev) -{ - if (!dev || dev->if_type != IFT_LOOP) - return EINVAL; - - dev->if_flags &= ~IFF_UP; - - if (dev->rx_thread > 0) - kill_thread(dev->rx_thread); - if (dev->tx_thread > 0) - kill_thread(dev->tx_thread); - - dev->if_flags &= ~IFF_RUNNING; - - return 0; -} - -static int loopback_ioctl(struct ifnet *ifp, ulong cmd, caddr_t data) -{ - int error = 0; - - switch(cmd) { - case SIOCSIFADDR: - ifp->if_flags |= (IFF_UP | IFF_RUNNING); - if (ifp->rx_thread < 0) - start_rx_thread(ifp); - if (ifp->tx_thread < 0) - start_tx_thread(ifp); - break; - default: - error = EINVAL; - } - return error; -} - -static int loopback_init(void) -{ - me = (struct ifnet*)malloc(sizeof(struct ifnet)); - if (!me) - return -1; - - memset(me, 0, sizeof(*me)); - - memset(proto, 0, sizeof(struct protosw *) * IPPROTO_MAX); - - me->devid = -1; - me->name = "loop"; - me->if_unit = 0; - me->if_type = IFT_LOOP; - me->rx_thread = -1; - me->tx_thread = -1; - me->if_addrlen = 0; - me->if_hdrlen = 0; - me->if_flags = IFF_LOOPBACK | IFF_MULTICAST; - me->if_mtu = 16384; /* can be as large as we want */ - me->input = &loopback_input; - me->output = &loopback_output; - me->stop = &loopback_dev_stop; - me->ioctl = &loopback_ioctl; - - add_protosw(proto, NET_LAYER1); - if_attach(me); - - return 0; -} - -static int loopback_module_init(void *cpp) -{ - if (cpp) - core = cpp; - - loopback_init(); - - return 0; -} - -struct kernel_net_module_info device_info = { - { - NETWORK_MODULES_ROOT "interfaces/loopback", - 0, - std_ops - }, - loopback_module_init, - NULL, - NULL -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info **)&core); - if (!core) - return B_ERROR; - return B_OK; - case B_MODULE_UNINIT: - break; - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info*) &device_info, - NULL -}; - diff --git a/src/add-ons/kernel/network/interfaces/ppp/Jamfile b/src/add-ons/kernel/network/interfaces/ppp/Jamfile deleted file mode 100644 index b613ac4cdd..0000000000 --- a/src/add-ons/kernel/network/interfaces/ppp/Jamfile +++ /dev/null @@ -1,39 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network interfaces ppp ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; -UsePrivateHeaders [ FDirName kernel ] ; -UsePrivateHeaders [ FDirName kernel util ] ; -UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared - libkernelppp ] : true ; -UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared - libkernelppp headers ] : true ; - - -{ - SubDirC++Flags -fno-rtti ; -} - - -KernelAddon ppp : kernel obos_network interfaces : - ppp.cpp - PPPManager.cpp -; - -LinkAgainst ppp : libkernelppp.a ; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/interfaces - : ppp ; - -Package haiku-networkingkit-cvs : - ppp : - boot home config add-ons kernel obos_network interfaces ; diff --git a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp deleted file mode 100644 index 75a01d4de3..0000000000 --- a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp +++ /dev/null @@ -1,862 +0,0 @@ -/* - * Copyright 2003-2006, Waldemar Kornewald - * Distributed under the terms of the MIT License. - */ - -#include - -#include "PPPManager.h" -#include -#include -#include -#include - -#include - -#include - -#include -#include - - -static const char sKPPPIfNameBase[] = "ppp"; - - -static -status_t -deleter_thread(void *data) -{ - PPPManager *manager = (PPPManager*) data; - thread_id sender; - int32 code; - - while(true) { - manager->DeleterThreadEvent(); - - // check if the manager is being destroyed - if(receive_data_with_timeout(&sender, &code, NULL, 0, 500) == B_OK) - return B_OK; - } - - return B_OK; -} - - -static -void -pulse_timer(void *data) -{ - ((PPPManager*)data)->Pulse(); -} - - -PPPManager::PPPManager() - : fLock("PPPManager"), - fReportLock("PPPManagerReportLock"), - fDefaultInterface(NULL), - fReportManager(fReportLock), - fNextID(1) -{ - TRACE("PPPManager: Constructor\n"); - - fDeleterThread = spawn_kernel_thread(deleter_thread, "PPPManager: deleter_thread", - B_NORMAL_PRIORITY, this); - resume_thread(fDeleterThread); - fPulseTimer = net_add_timer(pulse_timer, this, PPP_PULSE_RATE); -} - - -PPPManager::~PPPManager() -{ - TRACE("PPPManager: Destructor\n"); - - int32 tmp; - send_data(fDeleterThread, 0, NULL, 0); - // notify deleter_thread that we are being destroyed - wait_for_thread(fDeleterThread, &tmp); - net_remove_timer(fPulseTimer); - - // now really delete the interfaces (the deleter_thread is not running) - ppp_interface_entry *entry = NULL; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry) { - delete entry->interface; - free(entry->name); - delete entry; - } - } - - free(fDefaultInterface); -} - - -int32 -PPPManager::Stop(ifnet *ifp) -{ - TRACE("PPPManager: Stop(%s)\n", ifp ? ifp->if_name : "Unknown"); - - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(ifp); - if(!entry) { - ERROR("PPPManager: Stop(): Could not find interface!\n"); - return B_ERROR; - } - - DeleteInterface(entry->interface->ID()); - - return B_OK; -} - - -int32 -PPPManager::Output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0) -{ - TRACE("PPPManager: Output(%s)\n", ifp ? ifp->if_name : "Unknown"); - - if(dst->sa_family == AF_UNSPEC) - return B_ERROR; - - LockerHelper locker(fLock); - ppp_interface_entry *entry = EntryFor(ifp); - if(!entry) { - ERROR("PPPManager: Output(): Could not find interface!\n"); - return B_ERROR; - } - - atomic_add(&entry->accessing, 1); - locker.UnlockNow(); - - if(!entry->interface->DoesConnectOnDemand() - && ifp->if_flags & (IFF_UP | IFF_RUNNING) != (IFF_UP | IFF_RUNNING)) { - m_freem(buf); - atomic_add(&entry->accessing, -1); - return ENETDOWN; - } - - int32 result = B_ERROR; - KPPPProtocol *protocol = entry->interface->FirstProtocol(); - for(; protocol; protocol = protocol->NextProtocol()) { - if(!protocol->IsEnabled() || protocol->AddressFamily() != dst->sa_family) - continue; - - if(protocol->Flags() & PPP_INCLUDES_NCP) - result = protocol->Send(buf, protocol->ProtocolNumber() & 0x7FFF); - else - result = protocol->Send(buf, protocol->ProtocolNumber()); - if(result == PPP_UNHANDLED) - continue; - - atomic_add(&entry->accessing, -1); - return result; - } - - m_freem(buf); - atomic_add(&entry->accessing, -1); - return B_ERROR; -} - - -int32 -PPPManager::Control(ifnet *ifp, ulong cmd, caddr_t data) -{ - TRACE("PPPManager: Control(%s)\n", ifp ? ifp->if_name : "Unknown"); - - LockerHelper locker(fLock); - ppp_interface_entry *entry = EntryFor(ifp); - if(!entry || entry->deleting) { - ERROR("PPPManager: Control(): Could not find interface!\n"); - return B_ERROR; - } - - int32 status = B_OK; - atomic_add(&entry->accessing, 1); - locker.UnlockNow(); - - switch(cmd) { - case SIOCSIFFLAGS: - if(((ifreq*)data)->ifr_flags & IFF_DOWN) { - if(entry->interface->DoesConnectOnDemand() - && entry->interface->Phase() == PPP_DOWN_PHASE) - DeleteInterface(entry->interface->ID()); - else - entry->interface->Down(); - } else if(((ifreq*)data)->ifr_flags & IFF_UP) - entry->interface->Up(); - break; - - default: - status = entry->interface->StackControl(cmd, data); - } - - atomic_add(&entry->accessing, -1); - return status; -} - - -ppp_interface_id -PPPManager::CreateInterface(const driver_settings *settings, - ppp_interface_id parentID) -{ - return _CreateInterface(NULL, settings, parentID); -} - - -ppp_interface_id -PPPManager::CreateInterfaceWithName(const char *name, - ppp_interface_id parentID) -{ - if(!name) - return PPP_UNDEFINED_INTERFACE_ID; - - ppp_interface_id result = _CreateInterface(name, NULL, parentID); - - return result; -} - - -bool -PPPManager::DeleteInterface(ppp_interface_id ID) -{ - TRACE("PPPManager: DeleteInterface(%ld)\n", ID); - - // This only marks the interface for deletion. - // Our deleter_thread does the real work. - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(ID); - if(!entry) - return false; - - if(entry->deleting) - return true; - // this prevents an endless loop between Delete() and interface->Down() - - entry->deleting = true; - atomic_add(&entry->accessing, 1); - locker.UnlockNow(); - - // bring interface down if needed - if(entry->interface->State() != PPP_INITIAL_STATE - || entry->interface->Phase() != PPP_DOWN_PHASE) - entry->interface->Down(); - - atomic_add(&entry->accessing, -1); - - return true; -} - - -bool -PPPManager::RemoveInterface(ppp_interface_id ID) -{ - TRACE("PPPManager: RemoveInterface(%ld)\n", ID); - - LockerHelper locker(fLock); - - int32 index; - ppp_interface_entry *entry = EntryFor(ID, &index); - if(!entry || entry->deleting) - return false; - - UnregisterInterface(ID); - - delete entry; - fEntries.RemoveItem(index); - - return true; -} - - -ifnet* -PPPManager::RegisterInterface(ppp_interface_id ID) -{ - TRACE("PPPManager: RegisterInterface(%ld)\n", ID); - - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(ID); - if(!entry || entry->deleting) - return NULL; - - // maybe the interface is already registered - if(entry->interface->Ifnet()) - return entry->interface->Ifnet(); - - // TODO: allocate struct around ifnet with pointer to entry so we can optimize - // ifnet->ppp_interface_entry translation (speeds-up Output()/Input()) - ifnet *ifp = (ifnet*) malloc(sizeof(ifnet)); - memset(ifp, 0, sizeof(ifnet)); - ifp->devid = -1; - ifp->if_type = IFT_PPP; - ifp->name = (char*)sKPPPIfNameBase; - ifp->if_unit = FindUnit(); - ifp->if_flags = IFF_POINTOPOINT; - ifp->rx_thread = ifp->tx_thread = -1; - ifp->start = NULL; - ifp->stop = ppp_ifnet_stop; - ifp->output = ppp_ifnet_output; - ifp->ioctl = ppp_ifnet_ioctl; - - TRACE("PPPManager::RegisterInterface(): Created new ifnet: %s%d\n", - ifp->name, ifp->if_unit); - - if_attach(ifp); - return ifp; -} - - -bool -PPPManager::UnregisterInterface(ppp_interface_id ID) -{ - TRACE("PPPManager: UnregisterInterface(%ld)\n", ID); - - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(ID); - if(!entry) - return false; - - if(entry->interface->Ifnet()) { - if_detach(entry->interface->Ifnet()); - free(entry->interface->Ifnet()); - } - - return true; -} - - -status_t -PPPManager::Control(uint32 op, void *data, size_t length) -{ - TRACE("PPPManager: Control(%ld)\n", op); - - // this method is intended for use by userland applications - - switch(op) { - case PPPC_CONTROL_MODULE: { - if(length < sizeof(control_net_module_args) || !data) - return B_ERROR; - - control_net_module_args *args = (control_net_module_args*) data; - if(!args->name) - return B_ERROR; - - char name[B_PATH_NAME_LENGTH]; - sprintf(name, "%s/%s", PPP_MODULES_PATH, args->name); - ppp_module_info *module; - if(get_module(name, (module_info**) &module) != B_OK - || !module->control) - return B_NAME_NOT_FOUND; - - return module->control(args->op, args->data, args->length); - } break; - - case PPPC_CREATE_INTERFACE: { - if(length < sizeof(ppp_interface_description_info) || !data) - return B_ERROR; - - ppp_interface_description_info *info - = (ppp_interface_description_info*) data; - if(!info->u.settings) - return B_ERROR; - - info->interface = CreateInterface(info->u.settings); - // parents cannot be set from userland - return info->interface != PPP_UNDEFINED_INTERFACE_ID ? B_OK : B_ERROR; - } break; - - case PPPC_CREATE_INTERFACE_WITH_NAME: { - if(length < sizeof(ppp_interface_description_info) || !data) - return B_ERROR; - - ppp_interface_description_info *info - = (ppp_interface_description_info*) data; - if(!info->u.name) - return B_ERROR; - - info->interface = CreateInterfaceWithName(info->u.name); - // parents cannot be set from userland - return info->interface != PPP_UNDEFINED_INTERFACE_ID ? B_OK : B_ERROR; - } break; - - case PPPC_DELETE_INTERFACE: - if(length != sizeof(ppp_interface_id) || !data) - return B_ERROR; - - if(!DeleteInterface(*(ppp_interface_id*)data)) - return B_ERROR; - break; - - case PPPC_BRING_INTERFACE_UP: { - if(length != sizeof(ppp_interface_id) || !data) - return B_ERROR; - - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(*(ppp_interface_id*)data); - if(!entry || entry->deleting) - return B_BAD_INDEX; - - atomic_add(&entry->accessing, 1); - locker.UnlockNow(); - - entry->interface->Up(); - atomic_add(&entry->accessing, -1); - } break; - - case PPPC_BRING_INTERFACE_DOWN: { - if(length != sizeof(ppp_interface_id) || !data) - return B_ERROR; - - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(*(ppp_interface_id*)data); - if(!entry || entry->deleting) - return B_BAD_INDEX; - - atomic_add(&entry->accessing, 1); - locker.UnlockNow(); - - entry->interface->Down(); - atomic_add(&entry->accessing, -1); - } break; - - case PPPC_CONTROL_INTERFACE: { - if(length < sizeof(ppp_control_info) || !data) - return B_ERROR; - - ppp_control_info *control = (ppp_control_info*) data; - - return ControlInterface(control->index, control->op, control->data, - control->length); - } break; - - case PPPC_GET_INTERFACES: { - if(length < sizeof(ppp_get_interfaces_info) || !data) - return B_ERROR; - - ppp_get_interfaces_info *info = (ppp_get_interfaces_info*) data; - if(!info->interfaces) - return B_ERROR; - - info->resultCount = GetInterfaces(info->interfaces, info->count, - info->filter); - return info->resultCount >= 0 ? B_OK : B_ERROR; - } break; - - case PPPC_COUNT_INTERFACES: - if(length != sizeof(ppp_interface_filter) || !data) - return B_ERROR; - - return CountInterfaces(*(ppp_interface_filter*)data); - break; - - case PPPC_FIND_INTERFACE_WITH_SETTINGS: { - if(length < sizeof(ppp_interface_description_info) || !data) - return B_ERROR; - - ppp_interface_description_info *info - = (ppp_interface_description_info*) data; - if(!info->u.settings) - return B_ERROR; - - LockerHelper locker(fLock); - - ppp_interface_entry *entry = EntryFor(info->u.settings); - if(entry) - info->interface = entry->interface->ID(); - else { - info->interface = PPP_UNDEFINED_INTERFACE_ID; - return B_ERROR; - } - } break; - - case PPPC_ENABLE_REPORTS: { - if(length < sizeof(ppp_report_request) || !data) - return B_ERROR; - - ppp_report_request *request = (ppp_report_request*) data; - ReportManager().EnableReports(request->type, request->thread, - request->flags); - } break; - - case PPPC_DISABLE_REPORTS: { - if(length < sizeof(ppp_report_request) || !data) - return B_ERROR; - - ppp_report_request *request = (ppp_report_request*) data; - ReportManager().DisableReports(request->type, request->thread); - } break; - - default: - return B_BAD_VALUE; - } - - return B_OK; -} - - -status_t -PPPManager::ControlInterface(ppp_interface_id ID, uint32 op, void *data, size_t length) -{ - TRACE("PPPManager: ControlInterface(%ld)\n", ID); - - LockerHelper locker(fLock); - - status_t result = B_BAD_INDEX; - ppp_interface_entry *entry = EntryFor(ID); - if(entry && !entry->deleting) { - atomic_add(&entry->accessing, 1); - locker.UnlockNow(); - result = entry->interface->Control(op, data, length); - atomic_add(&entry->accessing, -1); - } - - return result; -} - - -int32 -PPPManager::GetInterfaces(ppp_interface_id *interfaces, int32 count, - ppp_interface_filter filter) -{ - TRACE("PPPManager: GetInterfaces()\n"); - - LockerHelper locker(fLock); - - int32 item = 0; - // the current item in 'interfaces' (also the number of ids copied) - ppp_interface_entry *entry; - - for(int32 index = 0; item < count && index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(!entry || entry->deleting) - continue; - - switch(filter) { - case PPP_ALL_INTERFACES: - interfaces[item++] = entry->interface->ID(); - break; - - case PPP_REGISTERED_INTERFACES: - if(entry->interface->Ifnet()) - interfaces[item++] = entry->interface->ID(); - break; - - case PPP_UNREGISTERED_INTERFACES: - if(!entry->interface->Ifnet()) - interfaces[item++] = entry->interface->ID(); - break; - - default: - return B_ERROR; - // the filter is unknown - } - } - - return item; -} - - -int32 -PPPManager::CountInterfaces(ppp_interface_filter filter) -{ - TRACE("PPPManager: CountInterfaces()\n"); - - LockerHelper locker(fLock); - - if(filter == PPP_ALL_INTERFACES) - return fEntries.CountItems(); - - int32 count = 0; - ppp_interface_entry *entry; - - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(!entry || entry->deleting) - continue; - - switch(filter) { - case PPP_REGISTERED_INTERFACES: - if(entry->interface->Ifnet()) - ++count; - break; - - case PPP_UNREGISTERED_INTERFACES: - if(!entry->interface->Ifnet()) - ++count; - break; - - default: - return B_ERROR; - // the filter is unknown - } - } - - return count; -} - - -ppp_interface_entry* -PPPManager::EntryFor(ppp_interface_id ID, int32 *saveIndex) const -{ - TRACE("PPPManager: EntryFor(%ld)\n", ID); - - if(ID == PPP_UNDEFINED_INTERFACE_ID) - return NULL; - - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry && entry->interface->ID() == ID) { - if(saveIndex) - *saveIndex = index; - return entry; - } - } - - return NULL; -} - - -ppp_interface_entry* -PPPManager::EntryFor(ifnet *ifp, int32 *saveIndex) const -{ - if(!ifp) - return NULL; - - TRACE("PPPManager: EntryFor(%s%d)\n", ifp->name, ifp->if_unit); - - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry && entry->interface->Ifnet() == ifp) { - if(saveIndex) - *saveIndex = index; - return entry; - } - } - - return NULL; -} - - -ppp_interface_entry* -PPPManager::EntryFor(const char *name, int32 *saveIndex) const -{ - if(!name) - return NULL; - - TRACE("PPPManager: EntryFor(%s)\n", name); - - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry && entry->name && !strcmp(entry->name, name)) { - if(saveIndex) - *saveIndex = index; - return entry; - } - } - - return NULL; -} - - -ppp_interface_entry* -PPPManager::EntryFor(const driver_settings *settings) const -{ - if(!settings) - return NULL; - - TRACE("PPPManager: EntryFor(settings)\n"); - - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry && equal_interface_settings(entry->interface->Settings(), settings)) - return entry; - } - - return NULL; -} - - -void -PPPManager::SettingsChanged() -{ - // get default interface name and update interfaces if it changed - void *handle = load_driver_settings("ptpnet.settings"); - const char *name = get_driver_parameter(handle, "default", NULL, NULL); - - if((!fDefaultInterface && !name) || (fDefaultInterface && name - && !strcmp(name, fDefaultInterface))) { - unload_driver_settings(handle); - return; - } - - ppp_interface_entry *entry = EntryFor(fDefaultInterface); - if(entry && entry->interface->StateMachine().Phase() == PPP_DOWN_PHASE) - DeleteInterface(entry->interface->ID()); - - free(fDefaultInterface); - if(!name) { - fDefaultInterface = NULL; - unload_driver_settings(handle); - return; - } - - fDefaultInterface = strdup(name); - unload_driver_settings(handle); - ppp_interface_id id = CreateInterfaceWithName(fDefaultInterface); - entry = EntryFor(id); - if(entry) - entry->interface->SetConnectOnDemand(true); -} - - -static -int -greater(const void *a, const void *b) -{ - return (*(const int*)a - *(const int*)b); -} - - -// used by the public CreateInterface() methods -ppp_interface_id -PPPManager::_CreateInterface(const char *name, - const driver_settings *settings, ppp_interface_id parentID) -{ - TRACE("PPPManager: CreateInterface(%s)\n", name ? name : "Unnamed"); - - LockerHelper locker(fLock); - - ppp_interface_entry *parentEntry = EntryFor(parentID); - if(parentID != PPP_UNDEFINED_INTERFACE_ID && !parentEntry) - return PPP_UNDEFINED_INTERFACE_ID; - - // the day when NextID() returns 0 will come, be prepared! ;) - ppp_interface_id id = NextID(); - if(id == PPP_UNDEFINED_INTERFACE_ID) - id = NextID(); - - // check if we already have an entry for the named interface - ppp_interface_entry *entry = EntryFor(name); - if(entry) - return entry->interface->ID(); - - entry = new ppp_interface_entry; - entry->name = name ? strdup(name) : NULL; - entry->accessing = 1; - entry->deleting = false; - fEntries.AddItem(entry); - // nothing bad can happen because we are in a locked section - - new KPPPInterface(name, entry, id, settings, - parentEntry ? parentEntry->interface : NULL); - // KPPPInterface will add itself to the entry (no need to do it here) - if(entry->interface->InitCheck() != B_OK) { - delete entry->interface; - free(entry->name); - fEntries.RemoveItem(entry); - delete entry; - return PPP_UNDEFINED_INTERFACE_ID; - } - - // hidden/child interfaces should never bother the user - if(!entry->name) - entry->interface->SetAskBeforeConnecting(false); - - locker.UnlockNow(); - // it is safe to access the manager from userland now - - Report(PPP_MANAGER_REPORT, PPP_REPORT_INTERFACE_CREATED, &id, - sizeof(ppp_interface_id)); - - // notify handlers that interface has been created and they can initialize it now - entry->interface->StateMachine().DownProtocols(); - entry->interface->StateMachine().ResetLCPHandlers(); - - atomic_add(&entry->accessing, -1); - - return id; -} - - -int32 -PPPManager::FindUnit() const -{ - // Find the smallest unused unit. - int32 *units = new int32[fEntries.CountItems()]; - - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry && entry->interface->Ifnet()) - units[index] = entry->interface->Ifnet()->if_unit; - else - units[index] = -1; - } - - qsort(units, fEntries.CountItems(), sizeof(int32), greater); - - int32 unit = 0; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - if(units[index] > unit) - return unit; - else if(units[index] == unit) - ++unit; - } - - return unit; -} - - -void -PPPManager::DeleterThreadEvent() -{ - LockerHelper locker(fLock); - - SettingsChanged(); - // TODO: Use Haiku's kernel node monitoring capabilities - - // delete and remove marked interfaces - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry && entry->deleting && entry->accessing <= 0) { - delete entry->interface; - fEntries.RemoveItem(index); - --index; - - // recreate default interface - if(entry->name && fDefaultInterface && - !strcmp(entry->name, fDefaultInterface)) { - free(fDefaultInterface); - fDefaultInterface = NULL; - SettingsChanged(); - } - - free(entry->name); - delete entry; - } - } -} - - -void -PPPManager::Pulse() -{ - LockerHelper locker(fLock); - - ppp_interface_entry *entry; - for(int32 index = 0; index < fEntries.CountItems(); index++) { - entry = fEntries.ItemAt(index); - if(entry) - entry->interface->Pulse(); - } -} diff --git a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h deleted file mode 100644 index 84c578e611..0000000000 --- a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2003-2006, Waldemar Kornewald - * Distributed under the terms of the MIT License. - */ - -#ifndef _PPP_MANAGER__H -#define _PPP_MANAGER__H - -#include -#include -#include - - -// these functions are defined in ppp.cpp -extern int ppp_ifnet_stop(ifnet *ifp); -extern int ppp_ifnet_output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0); -extern int ppp_ifnet_ioctl(ifnet *ifp, ulong cmd, caddr_t data); - - -class PPPManager { - public: - PPPManager(); - ~PPPManager(); - - int32 Stop(ifnet *ifp); - int32 Output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0); - int32 Control(ifnet *ifp, ulong cmd, caddr_t data); - - ppp_interface_id CreateInterface(const driver_settings *settings, - ppp_interface_id parentID = PPP_UNDEFINED_INTERFACE_ID); - ppp_interface_id CreateInterfaceWithName(const char *name, - ppp_interface_id parentID = PPP_UNDEFINED_INTERFACE_ID); - bool DeleteInterface(ppp_interface_id ID); - bool RemoveInterface(ppp_interface_id ID); - - ifnet *RegisterInterface(ppp_interface_id ID); - bool UnregisterInterface(ppp_interface_id ID); - - status_t Control(uint32 op, void *data, size_t length); - status_t ControlInterface(ppp_interface_id ID, uint32 op, void *data, - size_t length); - - int32 GetInterfaces(ppp_interface_id *interfaces, int32 count, - ppp_interface_filter filter = PPP_REGISTERED_INTERFACES); - int32 CountInterfaces(ppp_interface_filter filter = PPP_REGISTERED_INTERFACES); - - KPPPReportManager& ReportManager() - { return fReportManager; } - bool Report(ppp_report_type type, int32 code, void *data, int32 length) - { return ReportManager().Report(type, code, data, length); } - // returns false if reply was bad (or an error occured) - - // these methods must be called from a locked section - ppp_interface_entry *EntryFor(ppp_interface_id ID, - int32 *saveIndex = NULL) const; - ppp_interface_entry *EntryFor(ifnet *ifp, int32 *saveIndex = NULL) const; - ppp_interface_entry *EntryFor(const char *name, int32 *saveIndex = NULL) const; - ppp_interface_entry *EntryFor(const driver_settings *settings) const; - - void SettingsChanged(); - - ppp_interface_id NextID() - { return (ppp_interface_id) atomic_add((int32*) &fNextID, 1); } - - void DeleterThreadEvent(); - void Pulse(); - - private: - ppp_interface_id _CreateInterface(const char *name, - const driver_settings *settings, ppp_interface_id parentID); - int32 FindUnit() const; - - private: - BLocker fLock, fReportLock; - char *fDefaultInterface; - KPPPReportManager fReportManager; - TemplateList fEntries; - ppp_interface_id fNextID; - thread_id fDeleterThread, fPulseTimer; -}; - - -#endif diff --git a/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp b/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp deleted file mode 100644 index 6a1548d7c4..0000000000 --- a/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2003-2006, Waldemar Kornewald - * Distributed under the terms of the MIT License. - */ - -#include -#include -#include - -#include -#include "PPPManager.h" - - -status_t std_ops(int32 op, ...); - -struct core_module_info *core = NULL; -static PPPManager *sManager = NULL; - - -int -ppp_ifnet_stop(ifnet *ifp) -{ - if(sManager) - return sManager->Stop(ifp); - else - return B_ERROR; -} - - -int -ppp_ifnet_output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0) -{ - if(sManager) - return sManager->Output(ifp, buf, dst, rt0); - else - return B_ERROR; -} - - -int -ppp_ifnet_ioctl(ifnet *ifp, ulong cmd, caddr_t data) -{ - if(sManager) - return sManager->Control(ifp, cmd, data); - else - return B_ERROR; -} - - -static -int -ppp_start(void *cpp) -{ - if(cpp) - core = (core_module_info*) cpp; - - sManager = new PPPManager; - - return B_OK; -} - - -static -int -ppp_stop() -{ - delete sManager; - sManager = NULL; - - return B_OK; -} - - -// PPPManager wrappers -static -status_t -ppp_control(uint32 op, void *data, size_t length) -{ - if(sManager) - return sManager->Control(op, data, length); - else - return B_ERROR; -} - - -static -ppp_interface_id -CreateInterface(const driver_settings *settings, ppp_interface_id parent) -{ - if(sManager) - return sManager->CreateInterface(settings, parent); - else - return PPP_UNDEFINED_INTERFACE_ID; -} - - -static -ppp_interface_id -CreateInterfaceWithName(const char *name, ppp_interface_id parent) -{ - if(sManager) - return sManager->CreateInterfaceWithName(name, parent); - else - return PPP_UNDEFINED_INTERFACE_ID; -} - - -static -bool -DeleteInterface(ppp_interface_id ID) -{ - if(sManager) - return sManager->DeleteInterface(ID); - else - return false; -} - - -static -bool -RemoveInterface(ppp_interface_id ID) -{ - if(sManager) - return sManager->RemoveInterface(ID); - else - return false; -} - - -static -ifnet* -RegisterInterface(ppp_interface_id ID) -{ - if(sManager) - return sManager->RegisterInterface(ID); - else - return NULL; -} - - -static -bool -UnregisterInterface(ppp_interface_id ID) -{ - if(sManager) - return sManager->UnregisterInterface(ID); - else - return false; -} - - -static -status_t -ControlInterface(ppp_interface_id ID, uint32 op, void *data, size_t length) -{ - if(sManager) - return sManager->ControlInterface(ID, op, data, length); - else - return B_ERROR; -} - - -static -int32 -GetInterfaces(ppp_interface_id *interfaces, int32 count, - ppp_interface_filter filter = PPP_REGISTERED_INTERFACES) -{ - if(sManager) - return sManager->GetInterfaces(interfaces, count, filter); - else - return 0; -} - - -static -int32 -CountInterfaces(ppp_interface_filter filter = PPP_REGISTERED_INTERFACES) -{ - if(sManager) - return sManager->CountInterfaces(filter); - else - return 0; -} - - -static -void -EnableReports(ppp_report_type type, thread_id thread, int32 flags = PPP_NO_FLAGS) -{ - if(sManager) - sManager->ReportManager().EnableReports(type, thread, flags); -} - - -static -void -DisableReports(ppp_report_type type, thread_id thread) -{ - if(sManager) - sManager->ReportManager().DisableReports(type, thread); -} - - -static -bool -DoesReport(ppp_report_type type, thread_id thread) -{ - if(sManager) - return sManager->ReportManager().DoesReport(type, thread); - else - return false; -} - - -ppp_interface_module_info ppp_interface_module = { - { - { - PPP_INTERFACE_MODULE_NAME, - 0, - std_ops - }, - ppp_start, - ppp_stop, - ppp_control - }, - CreateInterface, - CreateInterfaceWithName, - DeleteInterface, - RemoveInterface, - RegisterInterface, - UnregisterInterface, - ControlInterface, - GetInterfaces, - CountInterfaces, - EnableReports, - DisableReports, - DoesReport -}; - - -_EXPORT -status_t -std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - put_module(NET_CORE_MODULE_NAME); - break; - - default: - return B_ERROR; - } - - return B_OK; -} - - -_EXPORT -module_info *modules[] = { - (module_info*) &ppp_interface_module, - NULL -}; diff --git a/src/add-ons/kernel/network/protocols/Jamfile b/src/add-ons/kernel/network/protocols/Jamfile deleted file mode 100644 index eccb6c9b7e..0000000000 --- a/src/add-ons/kernel/network/protocols/Jamfile +++ /dev/null @@ -1,9 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols ; - -SubInclude HAIKU_TOP src add-ons kernel network protocols icmp ; -SubInclude HAIKU_TOP src add-ons kernel network protocols ipv4 ; -SubInclude HAIKU_TOP src add-ons kernel network protocols tcp ; -SubInclude HAIKU_TOP src add-ons kernel network protocols udp ; -SubInclude HAIKU_TOP src add-ons kernel network protocols raw ; -SubInclude HAIKU_TOP src add-ons kernel network protocols route ; - diff --git a/src/add-ons/kernel/network/protocols/icmp/Jamfile b/src/add-ons/kernel/network/protocols/icmp/Jamfile deleted file mode 100644 index a719dc0060..0000000000 --- a/src/add-ons/kernel/network/protocols/icmp/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols icmp ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon icmp : kernel obos_network protocols : - icmp.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/protocols - : icmp ; - -Package haiku-networkingkit-cvs : - icmp : - boot home config add-ons kernel obos_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/icmp/icmp.c b/src/add-ons/kernel/network/protocols/icmp/icmp.c deleted file mode 100644 index 5578bf3e79..0000000000 --- a/src/add-ons/kernel/network/protocols/icmp/icmp.c +++ /dev/null @@ -1,466 +0,0 @@ -/* icmp.c - */ -#ifndef _KERNEL_MODE - #include - #include -#endif - -#include -#include "net_misc.h" -#include -#include -#include -#include -#include "protocols.h" -#include "sys/protosw.h" -#include "sys/domain.h" -#include -#include -#include - -#include "core_module.h" -#include "net_module.h" -#include "core_funcs.h" -#include "raw_module.h" -#include "icmp_module.h" -#include "ipv4_module.h" - -#include -status_t std_ops(int32 op, ...); - -/* private variables */ -static struct core_module_info *core = NULL; -static struct raw_module_info *raw = NULL; -static struct protosw* proto[IPPROTO_MAX]; -static struct in_ifaddr *ic_ifaddr = NULL; -static struct ipv4_module_info *ipm = NULL; - -struct icmpstat icmpstat; - -static struct route icmprt; - -#if SHOW_DEBUG -static void dump_icmp(struct mbuf *buf) -{ - struct ip *ip = mtod(buf, struct ip *); - struct icmp *ic = (struct icmp*)((caddr_t)ip + (ip->ip_hl * 4)); - - printf("ICMP: "); - switch (ic->icmp_type) { - case ICMP_ECHO: - printf ("Echo request\n"); - break; - case ICMP_ECHOREPLY: - printf("echo reply\n"); - break; - default: - printf("?? type = %d\n", ic->icmp_type); - } -} -#endif - -static void icmp_send(struct mbuf *m, struct mbuf *opts) -{ - struct ip *ip = mtod(m, struct ip*); - int hlen; - struct icmp *icp; - - hlen = ip->ip_hl << 2; - m->m_data += hlen; - m->m_len -= hlen; - icp = mtod(m, struct icmp *); - icp->icmp_cksum = 0; - icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen, 0); - m->m_data -= hlen; - m->m_len += hlen; - proto[IPPROTO_IP]->pr_output(m, opts, NULL, 0, NULL); -} - -static void icmp_reflect(struct mbuf *m) -{ - struct ip *ip = mtod(m, struct ip*); - struct in_ifaddr *ia; - struct in_addr t; - struct mbuf *opts = NULL; - int optlen = (ip->ip_hl << 2) - sizeof(struct ip); - struct sockaddr_in icmpdst; - - if (!ic_ifaddr) { - ic_ifaddr = get_primary_addr(); - if (!ic_ifaddr) { - printf("icmp_reflect: no interfaces available (ic_ifaddr == NULL)\n"); - m_freem(m); - return; - } - } - - if (!in_canforward(ip->ip_src) && - ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) != - (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) { - printf("icmp_reflect: can't forward packet!\n"); - m_freem(m); - goto done; - } - t = ip->ip_dst; - ip->ip_dst = ip->ip_src; - for (ia = ic_ifaddr; ia; ia = ia->ia_next) { - if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) - break; - if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && - t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) - break; - } - icmpdst.sin_addr = t; - if (ia == NULL) - ia = (struct in_ifaddr*)ifaof_ifpforaddr((struct sockaddr*)&icmpdst, - m->m_pkthdr.rcvif); - if (ia == NULL) - ia = get_primary_addr(); //XXX is this right? - t = IA_SIN(ia)->sin_addr; - ip->ip_src = t; - ip->ip_ttl = MAXTTL; - if (optlen > 0) { - uint8 *cp; - int opt, cnt, len; - - cp = (uint8*)(ip + 1); - if ((opts = ipm->srcroute()) == 0 && - (opts = m_gethdr(MT_HEADER))) { - opts->m_len = sizeof(struct in_addr); - mtod(opts, struct in_addr*)->s_addr = 0; - } - if (opts) { - for (cnt = optlen; cnt > 0; cnt -= len, cp+= len) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) - len = 1; - else { - len = cp[IPOPT_OLEN]; - if (len <= 0 || len > cnt) - break; - } - if (opt == IPOPT_RR || opt == IPOPT_TS || - opt == IPOPT_SECURITY) { - memcpy((void*)(mtod(opts, char*) + opts->m_len), - (void*)cp, len); - opts->m_len += len; - } - } - if ((cnt = opts->m_len % 4)) { - for (; cnt < 4; cnt++) { - *(mtod(opts, char*) + opts->m_len) = IPOPT_EOL; - opts->m_len++; - } - } - } - ip->ip_len -= optlen; - ip->ip_hl = sizeof(struct ip) >> 2; - m->m_len -= optlen; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len -= optlen; - optlen += sizeof(struct ip); - memcpy((void*)(ip + 1), (void*)(ip + optlen), - (uint)(m->m_len - sizeof(struct ip))); - } - m->m_flags &= ~(M_BCAST | M_MCAST); - icmp_send(m, opts); -done: - if (opts) - m_free(opts); -} - -static void icmp_input(struct mbuf *buf, int hdrlen) -{ - struct ip *ip = mtod(buf, struct ip *); - struct icmp *ic; - int icl = ip->ip_len; - int i; - uint16 rv; - int code; - struct sockaddr_in icmpsrc = {sizeof(struct sockaddr_in), AF_INET}; - - if (icl < ICMP_MINLEN) { - icmpstat.icps_tooshort++; - goto freeit; - } -#if SHOW_DEBUG - dump_icmp(buf); -#endif - i = hdrlen + min(icl, (int) ICMP_ADVLENMIN); - if ((int) buf->m_len < i && (buf = m_pullup(buf, i)) == NULL) { - icmpstat.icps_tooshort++; - return; - } - ip = mtod(buf, struct ip*); - buf->m_len -= hdrlen; - buf->m_data += hdrlen; - ic = mtod(buf, struct icmp*); - - if ((rv = in_cksum(buf, icl, 0)) != 0) { - printf("icmp_input: checksum failed over %d bytes (%d)!\n", icl, rv); - icmpstat.icps_checksum++; - goto freeit; - } - buf->m_len += hdrlen; - buf->m_data -= hdrlen; - if (ic->icmp_type > ICMP_MAXTYPE) - goto raw; - - icmpstat.icps_inhist[ic->icmp_type]++; - code = ic->icmp_code; - switch (ic->icmp_type) { - case ICMP_UNREACH: - switch (code) { - case ICMP_UNREACH_NET: - case ICMP_UNREACH_HOST: - case ICMP_UNREACH_PROTOCOL: - case ICMP_UNREACH_PORT: - case ICMP_UNREACH_SRCFAIL: - code += PRC_UNREACH_NET; - break; - case ICMP_UNREACH_NEEDFRAG: - code = PRC_MSGSIZE; - break; - case ICMP_UNREACH_NET_UNKNOWN: - case ICMP_UNREACH_NET_PROHIB: - case ICMP_UNREACH_TOSNET: - code = PRC_UNREACH_NET; - break; - case ICMP_UNREACH_HOST_UNKNOWN: - case ICMP_UNREACH_ISOLATED: - case ICMP_UNREACH_HOST_PROHIB: - case ICMP_UNREACH_TOSHOST: - code = PRC_UNREACH_HOST; - break; - default: - goto badcode; - } - goto deliver; - case ICMP_TIMXCEED: - if (code > 1) - goto badcode; - code += PRC_TIMXCEED_INTRANS; - goto deliver; - case ICMP_PARAMPROB: - if (code > 1) - goto badcode; - code = PRC_PARAMPROB; - goto deliver; - case ICMP_SOURCEQUENCH: - if (code) - goto badcode; - code = PRC_QUENCH; -deliver: - if (icl < (int) ICMP_ADVLENMIN || icl < ICMP_ADVLEN(ic) || - (ic->icmp_ip.ip_hl < sizeof(struct ip) >> 2)) { - icmpstat.icps_badlen++; - goto freeit; - } - ic->icmp_ip.ip_len = htons(ic->icmp_ip.ip_len); - icmpsrc.sin_addr = ic->icmp_ip.ip_dst; - if (proto[ic->icmp_ip.ip_p]->pr_ctlinput) - proto[ic->icmp_ip.ip_p]->pr_ctlinput(code, - (struct sockaddr*)&icmpsrc, (void*)&ic->icmp_ip); - break; -badcode: - icmpstat.icps_badcode++; - break; - case ICMP_ECHO: { - ic->icmp_type = ICMP_ECHOREPLY; - ip->ip_len += hdrlen; - icmpstat.icps_reflect++; - icmpstat.icps_outhist[ic->icmp_type]++; - icmp_reflect(buf); - return; - break; - } - case ICMP_ECHOREPLY: - break; - default: - break; - } - -raw: - if (raw) - raw->input(buf, 0); - - return; - -freeit: - m_freem(buf); - return; -} - - -static void icmp_error(struct mbuf *n, int type, int code, n_long dest, - struct ifnet *destifp) -{ - struct ip *oip = mtod(n, struct ip*), *nip; - uint oiplen = oip->ip_hl << 2; - struct icmp *icp; - struct mbuf *m; - uint icmplen; - - if (type != ICMP_REDIRECT) - icmpstat.icps_error++; - if (oip->ip_off & ~(IP_MF | IP_DF)) - goto freeit; - if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && - n->m_len >= oiplen + ICMP_MINLEN && - ICMP_INFOTYPE(((struct icmp*)((void*)(oip + oiplen)))->icmp_type)) { - icmpstat.icps_oldicmp++; - goto freeit; - } - /* don't send icmp errors in response to multi or broad cast */ - if (n->m_flags & (M_BCAST | M_MCAST)) - goto freeit; - - m = m_gethdr(MT_HEADER); - if (!m) - goto freeit; - icmplen = oiplen + min(8, oip->ip_len); - m->m_len = icmplen + ICMP_MINLEN; - MH_ALIGN(m, m->m_len); - icp = mtod(m, struct icmp*); - if ((uint)type > ICMP_MAXTYPE) { - /* PANIC */ - printf("PANIC: icmp_error! type outside of range\n"); - return; - } - icmpstat.icps_outhist[type]++; - icp->icmp_type = type; - if (type == ICMP_REDIRECT) - icp->icmp_gwaddr.s_addr = dest; - else { - icp->icmp_void = 0; - if (type == ICMP_PARAMPROB) { - icp->icmp_pptr = code; - } else if (type == ICMP_UNREACH && - code == ICMP_UNREACH_NEEDFRAG && - destifp) { - icp->icmp_nextmtu = htons(destifp->if_mtu); - } - } - icp->icmp_code = code; - memcpy((void*)&icp->icmp_ip, (void*)oip, icmplen); - nip = &icp->icmp_ip; - nip->ip_len = htons((nip->ip_len + oiplen)); - if (m->m_data - sizeof(struct ip) < m->m_pktdat) { - /* PANIC */ - printf("PANIC: icmp_error: icmp len\n"); - return; - } - m->m_data -= sizeof(struct ip); - m->m_len += sizeof(struct ip); - m->m_pkthdr.len = m->m_len; - m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; - nip = mtod(m, struct ip*); - memcpy((void*)nip, (void*)oip, sizeof(struct ip)); - nip->ip_len = m->m_len; - nip->ip_hl = sizeof(struct ip) >> 2; - nip->ip_p = IPPROTO_ICMP; - nip->ip_tos = 0; - icmp_reflect(m); - -freeit: - m_freem(n); -} - -static void icmp_init(void) -{ - memset(&icmprt, 0, sizeof(icmprt)); - - memset(proto, 0, sizeof(struct protosw *) * IPPROTO_MAX); - add_protosw(proto, NET_LAYER2); - if (!raw) - get_module(NET_RAW_MODULE_NAME, (module_info**)&raw); - ic_ifaddr = get_primary_addr(); -} - -struct protosw my_proto = { - "ICMP (v4)", - NET_ICMP_MODULE_NAME, - 0, - NULL, - IPPROTO_ICMP, - PR_ATOMIC | PR_ADDR, - NET_LAYER2, - - &icmp_init, - &icmp_input, - NULL, /* pr_output, */ - NULL, - NULL, /* pr_sysctl */ - NULL, - NULL, /* pr_ctloutput */ - - NULL, - NULL -}; - -static int icmp_protocol_init(void *cpp) -{ - /* we will never call this with anything but NULL when in kernel, - * so this should be safe. - */ - if (cpp) - core = (struct core_module_info *)cpp; - add_domain(NULL, AF_INET); - add_protocol(&my_proto, AF_INET); - - if (!ipm) - get_module(NET_IPV4_MODULE_NAME, (module_info**)&ipm); - - return 0; -} - -static int icmp_protocol_stop(void) -{ - remove_protocol(&my_proto); - remove_domain(AF_INET); - return 0; -} - -struct icmp_module_info protocol_info = { - { - { - NET_ICMP_MODULE_NAME, - 0, - std_ops - }, - icmp_protocol_init, - icmp_protocol_stop, - NULL - }, - - icmp_error -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - if (!core) - get_module(NET_CORE_MODULE_NAME, (module_info **) &core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - break; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info *) &protocol_info, - NULL -}; - diff --git a/src/add-ons/kernel/network/protocols/ipv4/Jamfile b/src/add-ons/kernel/network/protocols/ipv4/Jamfile deleted file mode 100644 index efbd269704..0000000000 --- a/src/add-ons/kernel/network/protocols/ipv4/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols ipv4 ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon ipv4 : kernel obos_network protocols : - ipv4.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/protocols - : ipv4 ; - -Package haiku-networkingkit-cvs : - ipv4 : - boot home config add-ons kernel obos_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.c b/src/add-ons/kernel/network/protocols/ipv4/ipv4.c deleted file mode 100644 index 753087742f..0000000000 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* ipv4.c - * simple ipv4 implementation - */ - -#ifndef _KERNEL_MODE - #include -#endif -#include -#include -#include -#include - -#include "netinet/in.h" -#include "netinet/in_var.h" -#include "netinet/in_systm.h" -#include "netinet/ip.h" -#include "netinet/ip_var.h" -#include "netinet/in_pcb.h" -#include "netinet/ip_icmp.h" -#include "protocols.h" -#include "sys/protosw.h" -#include "sys/domain.h" - -#include "core_module.h" -#include "core_funcs.h" -#include "net_module.h" -#include "ipv4_module.h" -#include "icmp_module.h" - -#include -static status_t std_ops(int32 op, ...); - -#define INA struct in_ifaddr * -#define SA struct sockaddr * - -/* private variables */ -static struct core_module_info *core = NULL; -static struct protosw *proto[IPPROTO_MAX]; -static int ipforwarding = 0; -static int ipsendredirects = 1; -static uint32 ip_id = 0; -static struct in_ifaddr *ip_ifaddr = NULL; -static struct icmp_module_info *icmp = NULL; -static struct ipq ipq; -static net_timer_id timerid; - -struct ipstat ipstat; //XXX might need to be shared - -static uint16 get_ip_id(void); - -static void ipv4_input(struct mbuf *, int); -static int ipv4_output(struct mbuf *, struct mbuf *, struct route *, int, void *); -static int ipv4_ctloutput(int, struct socket *, int, int, struct mbuf **); - -static int ip_dooptions(struct mbuf *); -static void ip_stripoptions(struct mbuf *, struct mbuf *); -static struct mbuf *ip_srcroute(void); - - - -/* ??? - Globals we need to remove... TLS storage? */ -struct route ipforward_rt; - -/* Forward prototypes */ -//int ipv4_output(struct mbuf *, struct mbuf *, struct route *, int, void *); - -#if SHOW_DEBUG - -void -dump_ipv4_addr(char *msg, void *ad) -{ - uint8 *b = (uint8*)ad; - printf("%s %d.%d.%d.%d\n", msg, b[0], b[1], b[2], b[3]); -} - - -static void -dump_ipv4_header(struct mbuf *buf) -{ - struct ip *ip = mtod(buf, struct ip *); - - printf("IPv4 Header :\n"); - printf(" : version : %d\n", ip->ip_v); - printf(" : header length : %d\n", ip->ip_hl * 4); - printf(" : tos : %d\n", ip->ip_tos); - printf(" : total length : %d\n", ntohs(ip->ip_len)); - printf(" : id : %d\n", ntohs(ip->ip_id)); - printf(" : ttl : %d\n", ip->ip_ttl); - dump_ipv4_addr(" : src address :", &ip->ip_src); - dump_ipv4_addr(" : dst address :", &ip->ip_dst); - - printf(" : protocol : "); - - switch(ip->ip_p) { - case IPPROTO_ICMP: - printf("ICMP\n"); - break; - case IPPROTO_UDP: - printf("UDP\n"); - break; - case IPPROTO_TCP: - printf("TCP\n"); - break; - default: - printf("unknown (0x%02x)\n", ip->ip_p); - } -} -#endif - - -/* IP Options variables and structures... */ -int ip_nhops = 0; -static struct ip_srcrt { - struct in_addr dst; - char nop; - char srcopt[IPOPT_OFFSET + 1]; - struct in_addr route[MAX_IPOPTLEN / sizeof(struct in_addr)]; -} ip_srcrt; - -/* - * Strip out IP options, at higher - * level protocol in the kernel. - * Second argument is buffer to which options - * will be moved, and return value is their length. - * XXX should be deleted; last arg currently ignored. - */ -static void ip_stripoptions(struct mbuf *m, struct mbuf *mopt) -{ - int i; - struct ip *ip = mtod(m, struct ip *); - caddr_t opts; - int olen; - - olen = (ip->ip_hl<<2) - sizeof (struct ip); - opts = (caddr_t)(ip + 1); - i = m->m_len - (sizeof (struct ip) + olen); - memcpy(opts, opts + olen, (unsigned)i); - m->m_len -= olen; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len -= olen; - ip->ip_hl = sizeof(struct ip) >> 2; -} - -static struct mbuf *ip_insertoptions(struct mbuf *m, struct mbuf *opt, int *phlen) -{ - struct ipoption * p = mtod(opt, struct ipoption*); - struct mbuf *n; - struct ip *ip = mtod(m, struct ip*); - uint optlen; - - optlen = opt->m_len - sizeof(p->ipopt_dst); - if (optlen + ip->ip_len > IP_MAXPACKET) - return (m); - if (p->ipopt_dst.s_addr) - ip->ip_dst = p->ipopt_dst; - if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { - n = m_get(MT_HEADER); - if (!n) - return (m); - n->m_pkthdr.len = m->m_pkthdr.len + optlen; - m->m_len -= sizeof(struct ip); - m->m_data += sizeof(struct ip); - n->m_next = m; - m = n; - m->m_len = optlen + sizeof(struct ip); - m->m_data += get_max_linkhdr(); - memcpy(mtod(m, void *), ip, sizeof(struct ip)); - } else { - m->m_data -= optlen; - m->m_len += optlen; - m->m_pkthdr.len += optlen; - memmove(mtod(m, void *), ip, sizeof(struct ip)); - } - ip = mtod(m, struct ip*); - memcpy((void*)(ip + 1), p->ipopt_list, optlen); - *phlen = sizeof(struct ip) + optlen; - ip->ip_len += optlen; - return (m); -} - -static struct in_ifaddr * ip_rtaddr(struct in_addr dst) -{ - struct sockaddr_in *sin; - - sin = (struct sockaddr_in*)&ipforward_rt.ro_dst; - - if (ipforward_rt.ro_rt == NULL || dst.s_addr != sin->sin_addr.s_addr) { - if (ipforward_rt.ro_rt) { - RTFREE(ipforward_rt.ro_rt); - ipforward_rt.ro_rt = NULL; - } - memset(&sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = dst; - - rtalloc(&ipforward_rt); - } - if (ipforward_rt.ro_rt == NULL) - return NULL; - return ((struct in_ifaddr*) ipforward_rt.ro_rt->rt_ifa); -} - -static void save_rte(uchar *option, struct in_addr dst) -{ - uint olen; - - olen = option[IPOPT_OLEN]; - if (olen > sizeof(struct ip_srcrt) - (1 + sizeof(dst))) - return; - memcpy((caddr_t) ip_srcrt.srcopt, (caddr_t)option, olen); - ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); - - ip_srcrt.dst = dst; -} - -static void ip_forward(struct mbuf *m, int srcrt) -{ - struct ip *ip = mtod(m, struct ip*); - struct sockaddr_in *sin; - struct rtentry *rt; - struct mbuf *mcopy; - n_long dest; - int code, type, error; - struct ifnet *destifp; - - dest = 0; - code = type = error = 0; - sin = NULL; - destifp = NULL; - if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { - ipstat.ips_cantforward++; - m_freem(m); - return; - } - ip->ip_id = htons(ip->ip_id); - if (ip->ip_ttl <= IPTTLDEC) { - icmp->error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); - return; - } - ip->ip_ttl -= IPTTLDEC; - - sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; - if ((rt = ipforward_rt.ro_rt) == NULL || - ip->ip_dst.s_addr != sin->sin_addr.s_addr) { - if (ipforward_rt.ro_rt) { - RTFREE(ipforward_rt.ro_rt); - ipforward_rt.ro_rt = NULL; - } - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ip->ip_dst; - - rtalloc(&ipforward_rt); - if (ipforward_rt.ro_rt == NULL) { - icmp->error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); - return; - } - rt = ipforward_rt.ro_rt; - } - mcopy = m_copym(m, 0, (int)min(ip->ip_len, 64)); - - if (rt->rt_ifp == m->m_pkthdr.rcvif && - (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED)) == 0 && - satosin(rt_key(rt))->sin_addr.s_addr != 0 && - ipsendredirects && !srcrt) { -#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) - uint32 src = ntohl(ip->ip_src.s_addr); - if (RTA(rt) && - (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { - if (rt->rt_flags & RTF_GATEWAY) - dest = satosin(rt->rt_gateway)->sin_addr.s_addr; - else - dest = ip->ip_dst.s_addr; - type = ICMP_REDIRECT; - code = ICMP_REDIRECT_HOST; - } - } - error = ipv4_output(m, NULL, &ipforward_rt, IP_FORWARDING | IP_ALLOWBROADCAST, 0); - if (error) - ipstat.ips_cantforward++; - else { - ipstat.ips_forward++; - if (type) - ipstat.ips_redirectsent++; - else { - if (mcopy) - m_freem(mcopy); - return; - } - } - if (!mcopy) - return; - destifp = NULL; - - switch(error) { - case 0: - break; - case ENETUNREACH: - case EHOSTUNREACH: - case ENETDOWN: - case EHOSTDOWN: - default: - type = ICMP_UNREACH; - code = ICMP_UNREACH_HOST; - break; - case EMSGSIZE: - type = ICMP_UNREACH; - code = ICMP_UNREACH_NEEDFRAG; - if (ipforward_rt.ro_rt) - destifp = ipforward_rt.ro_rt->rt_ifp; - ipstat.ips_cantfrag++; - break; - case ENOBUFS: - type = ICMP_SOURCEQUENCH; - code = 0; - break; - } - icmp->error(mcopy, type, code, dest, destifp); -} - -static int ip_dooptions(struct mbuf *m) -{ - struct ip *ip = mtod(m, struct ip*); - uint8 *cp; - struct in_addr dst, *sin; - struct sockaddr_in ipaddr; - int cnt, optlen, opt, code, off; - int type = ICMP_PARAMPROB; - int forward = 0; - struct in_ifaddr *ia; - struct ip_timestamp*ipt; - n_time ntime; - -printf("ip_dooptions\n"); - - dst = ip->ip_dst; - cp = (uint8*)(ip + 1); - cnt = (ip->ip_hl << 2) - sizeof(struct ip); - for (; cnt > 0; cnt -= optlen, cp+= optlen) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) - optlen = 1; - else { - optlen = cp[IPOPT_OLEN]; - if (optlen <= 0 || optlen > cnt) { - code = &cp[IPOPT_OLEN] - (uint8 *)ip; - goto bad; - } - } - switch (opt) { - case IPOPT_LSRR: - case IPOPT_SSRR: - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (uint8 *)ip; - goto bad; - } - ipaddr.sin_addr = ip->ip_dst; - ia = (struct in_ifaddr*)ifa_ifwithaddr((struct sockaddr*)&ipaddr); - if (ia == NULL) { - if (opt == IPOPT_SSRR) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - break; - } - off--; - if (off > (int) (optlen - sizeof(struct in_addr))) { - save_rte(cp, ip->ip_src); - break; - } - memcpy(&ipaddr.sin_addr, cp+off, sizeof(ipaddr.sin_addr)); - if (opt == IPOPT_SSRR) { - if ((ia = (INA) ifa_ifwithdstaddr((SA)&ipaddr)) == NULL) - ia = (INA) ifa_ifwithnet((SA)&ipaddr); - } else - ia = ip_rtaddr(ipaddr.sin_addr); - if (ia == NULL) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; - goto bad; - } - ip->ip_dst = ipaddr.sin_addr; - memcpy(cp+off, &(IA_SIN(ia)->sin_addr), sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); - break; - case IPOPT_RR: - if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { - code = &cp[IPOPT_OFFSET] - (uint8*)ip; - goto bad; - } - off--; - if (off > (int) (optlen - sizeof(struct in_addr))) - break; - memcpy(&ipaddr.sin_addr, &ip->ip_dst, sizeof(ipaddr.sin_addr)); - if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL && - (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) { - type = ICMP_UNREACH; - code = ICMP_UNREACH_HOST; - goto bad; - } - memcpy(cp+off, &(IA_SIN(ia)->sin_addr), sizeof(struct in_addr)); - cp[IPOPT_OFFSET] += sizeof(struct in_addr); - break; - case IPOPT_TS: - code = cp - (uint8*)ip; - ipt = (struct ip_timestamp *)cp; - if (ipt->ipt_len < 5) - goto bad; - if (ipt->ipt_ptr > ipt->ipt_len - sizeof(uint32)) { - if (++ipt->ipt_oflw == 0) - goto bad; - break; - } - sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); - switch (ipt->ipt_flg) { - case IPOPT_TS_TSONLY: - break; - case IPOPT_TS_TSANDADDR: - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; - ipaddr.sin_addr = dst; - ia = (INA)ifaof_ifpforaddr((SA) &ipaddr, m->m_pkthdr.rcvif); - if (!ia) - continue; - memcpy(sin, &IA_SIN(ia)->sin_addr, sizeof(struct in_addr)); - ipt->ipt_ptr += sizeof(struct in_addr); - break; - case IPOPT_TS_PRESPEC: - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; - memcpy(&ipaddr.sin_addr, sin, sizeof(struct in_addr)); - if (ifa_ifwithaddr((SA)&ipaddr) == 0) - continue; - ipt->ipt_ptr += sizeof(struct in_addr); - break; - default: - goto bad; - } - ntime = iptime(); - memcpy(cp+ipt->ipt_ptr - 1, &ntime, sizeof(n_time)); - ipt->ipt_ptr += sizeof(n_time); - default: - break; - } - } - if (forward) { - ip_forward(m, 1); - return 1; - } - return 0; -bad: - ip->ip_len -= ip->ip_hl << 2; - icmp->error(m, type, code, 0, 0); - ipstat.ips_badoptions++; - return 1; -} - - -static struct mbuf * ip_srcroute(void) -{ - struct in_addr *p, *q; - struct mbuf *m; - - if (ip_nhops == 0) - return NULL; - - m = m_get(MT_SOOPTS); - if (!m) - return NULL; - -#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) - - m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + OPTSIZ; - - p = &ip_srcrt.route[ip_nhops-1]; - *(mtod(m, struct in_addr*)) = *p--; - ip_srcrt.nop = IPOPT_NOP; - ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; - memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), &ip_srcrt.nop, OPTSIZ); - q = (struct in_addr*)(mtod(m, caddr_t) + sizeof(struct in_addr) + OPTSIZ); - -#undef OPTSIZ - - while (p >= ip_srcrt.route) { - *q++ = *p--; - } - - *q = ip_srcrt.dst; - return m; -} - -/* XXX - don't think these are thread safe somehow! - * look at adding locking or making them thread safe - */ -static void ip_enq(struct ipasfrag *p, struct ipasfrag *prev) -{ - p->ipf_prev = prev; - p->ipf_next = prev->ipf_next; - prev->ipf_next->ipf_prev = p; - prev->ipf_next = p; -} - -static void ip_deq(struct ipasfrag *p) -{ - p->ipf_prev->ipf_next = p->ipf_next; - p->ipf_next->ipf_prev = p->ipf_prev; -} - -static void ip_freef(struct ipq *fp) -{ - struct ipasfrag *q, *p; - - for (q = fp->ipq_next; q!= (struct ipasfrag*)fp; q = p) { - p = q->ipf_next; - ip_deq(q); - m_freem(dtom(q)); - } - remque(fp); - m_free(dtom(fp)); -} - -static struct ip *ip_reass(struct ipasfrag *ip, struct ipq *fp) -{ - struct mbuf *m = dtom(ip); - struct ipasfrag *q; - struct mbuf *t; - int hlen = ip->ip_hl << 2; - int i, next; - - m->m_data += hlen; - m->m_len -= hlen; - - if (!fp) { - if ((t = m_get(MT_FTABLE)) == NULL) - goto dropfrag; - fp = mtod(t, struct ipq*); - insque(fp, &ipq); - fp->ipq_ttl = IPFRAGTTL; - fp->ipq_p = ip->ip_p; - fp->ipq_id = ip->ip_id; - fp->ipq_next = fp->ipq_prev = (struct ipasfrag*)fp; - fp->ipq_src = ((struct ip*)ip)->ip_src; - fp->ipq_dst = ((struct ip*)ip)->ip_dst; - q = (struct ipasfrag*)fp; - goto insert; - } - /* Find a fragment that begins after the one we're trying to insert */ - for (q = fp->ipq_next; q != (struct ipasfrag*)fp; q = q->ipf_next) - if (q->ip_off > ip->ip_off) - break; - /* If we have a preceeding fragment, check for overlaps and discard - * the overlapped data from the new fragment - */ - if (q->ipf_prev != (struct ipasfrag*)fp) { - i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; - if (i > 0) { - /* overlapped! */ - if (i >= ip->ip_len) - goto dropfrag; - m_adj(dtom(ip), i); - ip->ip_off += i; - ip->ip_len -= i; - } - } - /* Trim overlapping fragments or if they overlap totally simply drop - * them - */ - while (q != (struct ipasfrag*)fp && ip->ip_off + ip->ip_len > q->ip_off) { - i = (ip->ip_off + ip->ip_len) - q->ip_off; - if (i < q->ip_len) { - q ->ip_len -= i; - q->ip_off += i; - m_adj(dtom(q), i); - break; - } - q = q->ipf_next; - m_freem(dtom(q->ipf_prev)); - ip_deq(q->ipf_prev); - } -insert: - ip_enq(ip, q->ipf_prev); - next = 0; - for (q = fp->ipq_next; q != (struct ipasfrag*)fp; q = q->ipf_next) { - if (q->ip_off != next) - return NULL; - next += q->ip_len; - } - if (q->ipf_prev->ipf_mff & 1) - return NULL; - /* we're the last fragment */ - q = fp->ipq_next; - m = dtom(q); - t = m->m_next; - m->m_next = NULL; - m_cat(m, t); - q = q->ipf_next; - while (q != (struct ipasfrag*)fp) { - t = dtom(q); - q = q->ipf_next; - m_cat(m, t); - } - /* create new header */ - ip = fp->ipq_next; - ip->ip_len = next; - ip->ipf_mff &= ~1; - ((struct ip*)ip)->ip_src = fp->ipq_src; - ((struct ip*)ip)->ip_dst = fp->ipq_dst; - remque(fp); - m_free(dtom(fp)); - m = dtom(ip); - m->m_len += (ip->ip_hl << 2); - m->m_data -= (ip->ip_hl << 2); - if (m->m_flags & M_PKTHDR) { - int plen = 0; - for (t=m;m;m = m->m_next) - plen += m->m_len; - t->m_pkthdr.len = plen; - } - return ((struct ip*)ip); - -dropfrag: - ipstat.ips_fragdropped++; - m_freem(m); - return NULL; -} - -void ipv4_input(struct mbuf *m, int hdrlen) -{ - struct ip *ip; - struct in_ifaddr *ia = NULL; - int hlen; - struct ipq *fp; - -#if SHOW_DEBUG - dump_ipv4_header(m); -#endif - if (!m) - return; - /* If we don't have a pointer to our IP addresses we can't go on */ - if (!ip_ifaddr) { - ip_ifaddr = get_primary_addr(); - if (!ip_ifaddr) { - printf("ipv4_input: no interfaces available! (ip_ifaddr == NULL)\n"); - goto bad; - } - } - - ipstat.ips_total++; - /* Get the whole header in the first mbuf */ - if (m->m_len < sizeof(struct ip) && - (m = m_pullup(m, sizeof(struct ip))) == NULL) { - ipstat.ips_toosmall++; - return; - } - ip = mtod(m, struct ip *); - - /* Check IP version... */ - if (ip->ip_v != IPVERSION) { - printf("Wrong IP version! %d\n", ip->ip_v); - ipstat.ips_badvers++; - goto bad; - } - /* Figure out of header length */ - hlen = ip->ip_hl << 2; - /* Check we're at least the minimum possible length */ - if (hlen < (int) sizeof(struct ip)) { - ipstat.ips_badhlen++; - goto bad; - } - /* Check again we have the entire header in the first mbuf */ - if (hlen > (int) m->m_len) { - if ((m = m_pullup(m, hlen)) == NULL) { - ipstat.ips_badhlen++; - goto bad; - } - ip = mtod(m, struct ip *); - } - - /* Checksum (should be 0) */ - if ((ip->ip_sum = in_cksum(m, hlen, 0)) != 0) { - printf("ipv4_input: checksum failed\n"); - ipstat.ips_badsum++; - goto bad; - } - - /* we put the length into host order here... */ - ip->ip_len = ntohs(ip->ip_len); - /* sanity check. Datagram MUST be longer than the header! */ - if (ip->ip_len < hlen) { - ipstat.ips_badhlen++; - goto bad; - } - ip->ip_id = ntohs(ip->ip_id); - ip->ip_off = ntohs(ip->ip_off); - - /* the first mbuf should be the packet hdr, so check it's length */ - if (m->m_pkthdr.len < ip->ip_len) { - ipstat.ips_tooshort++; - goto bad; - } - - /* Strip excess data from mbuf */ - if (m->m_pkthdr.len > ip->ip_len) { - if (m->m_pkthdr.len == (int) m->m_len) { - m->m_len = ip->ip_len; - m->m_pkthdr.len = ip->ip_len; - } else - m_adj(m, ip->ip_len - m->m_pkthdr.len); - } - - /* options processing */ - ip_nhops = 0; - if (hlen > (int) (sizeof(struct ip)) && ip_dooptions(m)) - return; - - for (ia = ip_ifaddr;ia; ia = ia->ia_next) { - if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) - goto ours; - - if (ia->ia_ifp == m->m_pkthdr.rcvif && - (ia->ia_ifp->if_flags & IFF_BROADCAST)) { - uint32 t; - - if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr) - goto ours; - if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) - goto ours; - t = ntohl(ip->ip_dst.s_addr); - if (t == ia->ia_subnet) - goto ours; - if (t == ia->ia_net) - goto ours; - } - } - - if (ip->ip_dst.s_addr == (uint32)INADDR_BROADCAST) - goto ours; - if (ip->ip_dst.s_addr == INADDR_ANY) - goto ours; - - if (ipforwarding == 0) { - ipstat.ips_cantforward++; - m_freem(m); - } else - ip_forward(m, 0); - return; -ours: - if (ip->ip_off & ~IP_DF) { - if (m->m_flags & M_EXT) { - if ((m = m_pullup(m, sizeof(struct ip))) == NULL) { - ipstat.ips_toosmall++; - return; - } - ip = mtod(m, struct ip*); - } - for (fp = ipq.next; fp != &ipq; fp = fp->next) { - if (ip->ip_id == fp->ipq_id && - ip->ip_src.s_addr == fp->ipq_src.s_addr && - ip->ip_dst.s_addr == fp->ipq_dst.s_addr && - ip->ip_p == fp->ipq_p) - goto found; - } - fp = NULL; -found: - ip->ip_len -= hlen; - ((struct ipasfrag*)ip)->ipf_mff &= ~1; - if (ip->ip_off & IP_MF) - ((struct ipasfrag*)ip)->ipf_mff |= 1; - ip->ip_off <<= 3; - if (((struct ipasfrag*)ip)->ipf_mff & 1 || ip->ip_off) { - ipstat.ips_fragments++; - ip = ip_reass((struct ipasfrag*)ip, fp); - if (ip == NULL) - return; - ipstat.ips_reassembled++; - m = dtom(ip); - } else if (fp) - ip_freef(fp); - } else - ip->ip_len -= hlen; - -#if SHOW_ROUTE - /* This just shows which interface we're planning on using */ - printf("Accepting packet [%d] to address %08lx via device %s from src addr %08lx\n", - ip->ip_p, ntohl(ip->ip_dst.s_addr), m->m_pkthdr.rcvif->if_name, - ntohl(ip->ip_src.s_addr)); -#endif - - ipstat.ips_delivered++; - if (proto[ip->ip_p] && proto[ip->ip_p]->pr_input) { - proto[ip->ip_p]->pr_input(m, hlen); - return; - } else { - printf("proto[%d] = %p\n", ip->ip_p, proto[ip->ip_p]); - goto bad; - } - - return; -bad: - m_freem(m); - return; -} - -static int ip_optcopy(struct ip *ip, struct ip *jp) -{ - uint8 *cp, *dp; - int opt, optlen, cnt; - - cp =(uint8*)(ip + 1); - dp = (uint8*)(jp + 1); - cnt = (ip->ip_hl << 2) - sizeof(struct ip); - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[0]; - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) { - *dp++ = IPOPT_NOP; - optlen = 1; - continue; - } else - optlen = cp[IPOPT_OLEN]; - if (optlen > cnt) - optlen = cnt; - if (IPOPT_COPIED(opt)) { - memcpy(dp, cp, optlen); - dp += optlen; - } - } - for (optlen = dp - (uint8*)(jp + 1); optlen & 0x3; optlen ++) - *dp++ = IPOPT_EOL; - return (optlen); -} - -static int ipv4_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, - int flags, void *optp) -{ - struct mbuf *m = m0; - struct ip *ip = mtod(m, struct ip*), *mhip; - struct route iproute; /* temporary route we may need */ - struct sockaddr_in *dst; /* destination address */ - struct in_ifaddr *ia; - int error = 0, hlen = sizeof(struct ip); - struct ifnet *ifp = NULL; - int len, off; - - /* handle options... */ - if (opt) { - m = ip_insertoptions(m, opt, &len); - hlen = len; - } - - ip = mtod(m, struct ip*); - - if ((flags & (IP_FORWARDING | IP_RAWOUTPUT)) == 0) { - ip->ip_v = IPVERSION; - ip->ip_off &= IP_DF; - ip->ip_id = htons(ip_id++); - ip->ip_hl = hlen >> 2; - ipstat.ips_localout++; - } else - hlen = ip->ip_hl << 2; - - /* route the packet! */ - if (!ro) { - ro = &iproute; - memset(ro, 0, sizeof(iproute)); - } - dst = (struct sockaddr_in *)&ro->ro_dst; - - if (ro && ro->ro_rt && - ((ro->ro_rt->rt_flags & RTF_UP) == 0 || /* route isn't available */ - dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { /* not same ip address */ - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } - if (ro->ro_rt == NULL) { - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); - dst->sin_family = AF_INET; - dst->sin_len = sizeof(*dst); - dst->sin_addr = ip->ip_dst; - } - if (flags & IP_ROUTETOIF) { - /* we're routing to an interface... */ - if (!(ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) && - !(ia = ifatoia(ifa_ifwithnet(sintosa(dst))))) { - ipstat.ips_noroute++; - error = ENETUNREACH; - goto bad; - } - ifp = ia->ia_ifp; - ip->ip_ttl = 1; - } else { - /* normal routing */ - if (ro->ro_rt == NULL) - rtalloc(ro); - if (ro->ro_rt == NULL) { - ipstat.ips_noroute++; - printf("EHOSTUNREACH\n"); - error = EHOSTUNREACH; - goto bad; - } - - ia = ifatoia(ro->ro_rt->rt_ifa); - ifp = ro->ro_rt->rt_ifp; - atomic_add((volatile long *)&ro->ro_rt->rt_use, 1); - if (ro->ro_rt->rt_flags & RTF_GATEWAY) - dst = (struct sockaddr_in *) ro->ro_rt->rt_gateway; - } - /* make sure we have an outgoing address. if not yet specified, use the - * address of the outgoing interface - */ - if (ip->ip_src.s_addr == INADDR_ANY) - ip->ip_src = IA_SIN(ia)->sin_addr; - - if ((in_broadcast(dst->sin_addr, ifp))) { - if ((ifp->if_flags & IFF_BROADCAST) == 0) { - error = EADDRNOTAVAIL; - goto bad; - } - if ((flags & IP_ALLOWBROADCAST) == 0) { - error = EACCES; - goto bad; - } - if (ip->ip_len > ifp->if_mtu) { - error = EMSGSIZE; - goto bad; - } - m->m_flags |= M_BCAST; - } else - m->m_flags &= ~M_BCAST; - -#if SHOW_ROUTE - /* This just shows which interface we're planning on using */ - printf("Sending to address %08lx via device %s using src addr %08lx\n", - ntohl(ip->ip_dst.s_addr), ifp->if_name, ntohl(ip->ip_src.s_addr)); -#endif - - /* if we're small enough, just send the thing! */ - if (ip->ip_len <= ifp->if_mtu) { - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m, hlen, 0); - /* now send the packet! */ - error = (*ifp->output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); - goto done; - } - - /* datagram is too big for interface! */ - /* IP_DF = do not fragment, so if we're too big we have a problem */ - if ((ip->ip_off & IP_DF)) { - error = EMSGSIZE; - ipstat.ips_cantfrag++; - goto bad; - } - len = (ifp->if_mtu - hlen) & ~7; - /* we need at least 8 bytes per fragment... */ - if (len < 8) { - error = EMSGSIZE; - goto bad; - } - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_nextpkt; - - m0 = m; - mhlen = sizeof(struct ip); - for (off = hlen + len; off < (uint16)ip->ip_len; off += len) { - m = m_gethdr(MT_HEADER); - if (!m) { - error = ENOBUFS; - ipstat.ips_odropped++; - goto sendorfree; - } - m->m_data += get_max_linkhdr(); - mhip = mtod(m, struct ip*); - *mhip = *ip; - if (hlen > (int) sizeof(struct ip)) { - mhlen = ip_optcopy(ip, mhip) + sizeof(struct ip); - mhip->ip_hl = mhlen >> 2; - } - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); - if (ip->ip_off & IP_MF) - mhip->ip_off |= IP_MF; - if (off + len >= (uint16)ip->ip_len) - len = (uint16) ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons(len + mhlen); - m->m_next = m_copym(m0, off, len); - if (!m->m_next) { - m_freem(m); - error = ENOBUFS; - ipstat.ips_odropped++; - goto sendorfree; - } - m->m_pkthdr.len = mhlen + len; - m->m_pkthdr.rcvif = NULL; - mhip->ip_off = htons(mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = in_cksum(m, mhlen, 0); - *mnext = m; - mnext = &m->m_nextpkt; - ipstat.ips_ofragments++; - } - m = m0; - m_adj(m, hlen + firstlen - ip->ip_len); - m->m_pkthdr.len = hlen + firstlen; - ip->ip_len = htons(m->m_pkthdr.len); - ip->ip_off = htons((ip->ip_off | IP_MF)); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m, hlen, 0); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_nextpkt; - m->m_nextpkt = NULL; - if (error == 0) - error = (*ifp->output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); - else - m_freem(m); - } - if (error == 0) - ipstat.ips_fragmented++; - } - -done: - if (ro == &iproute && /* we used our own variable */ - (flags & IP_ROUTETOIF) == 0 && /* we didn't route to an iterface */ - ro->ro_rt) { /* we have an allocated route */ - RTFREE(ro->ro_rt); /* free the route */ - } - - return error; -bad: - m_free(m0); - goto done; -} - -static uint16 get_ip_id(void) -{ - return (uint16) atomic_add(&ip_id, 1); -} - -static int ipv4_ctloutput(int op, struct socket *so, int level, - int optnum, struct mbuf **mp) -{ - struct inpcb *inp = sotoinpcb(so); - struct mbuf *m = *mp; - int optval; - int error = 0; - - if (level != IPPROTO_IP) { - error = EINVAL; - if (op == PRCO_SETOPT && *mp) - m_free(*mp); - } else { - switch(op) { - case PRCO_SETOPT: - switch(optnum) { - case IP_OPTIONS: - /* process options... */ - break; - case IP_TOS: - case IP_TTL: - case IP_RECVOPTS: - case IP_RECVRETOPTS: - case IP_RECVDSTADDR: - if (m->m_len != sizeof(int)) - error = EINVAL; - else { - optval = *mtod(m, int*); - switch (optnum) { - case IP_TOS: - inp->inp_ip.ip_tos = optval; - break; - case IP_TTL: - inp->inp_ip.ip_ttl = optval; - break; -#define OPTSET(bit) \ - if (optval) \ - inp->inp_flags |= bit; \ - else \ - inp->inp_flags &= ~bit; - - case IP_RECVOPTS: - OPTSET(INP_RECVOPTS); - break; - case IP_RECVRETOPTS: - OPTSET(INP_RECVRETOPTS); - break; - case IP_RECVDSTADDR: - OPTSET(INP_RECVDSTADDR); - break; - } - } - break; -//freeit: - default: - error = EINVAL; - break; - } - if (m) - m_free(m); - break; - case PRCO_GETOPT: - switch(optnum) { - /* XXX - add the code here */ - default: - error = ENOPROTOOPT; - break; - } - break; - } - } - return error; -} - -static void ip_slowtimer(void *data) -{ - struct ipq *fp; - - fp = ipq.next; - if (!fp) - return; - while (fp != &ipq) { - --fp->ipq_ttl; - fp = fp->next; - if (fp->prev->ipq_ttl == 0) { - /* timed out! remove it */ - ipstat.ips_fragtimeout++; - ip_freef(fp->prev); - } - } -} - -static void ipv4_init(void) -{ - if (ip_id == 0) - ip_id = real_time_clock() & 0xffff; - - ip_ifaddr = get_primary_addr(); - - memset(proto, 0, sizeof(struct protosw *) * IPPROTO_MAX); - add_protosw(proto, NET_LAYER2); - - ipq.next = ipq.prev = &ipq; - - timerid = net_add_timer(&ip_slowtimer, NULL, 1000000 / PR_SLOWHZ); -} - -struct protosw my_proto = { - "IPv4", - NET_IPV4_MODULE_NAME, - 0, - NULL, - IPPROTO_IP, - 0, - NET_LAYER2, - - &ipv4_init, - &ipv4_input, - &ipv4_output, - NULL, /* pr_userreq */ - NULL, /* pr_sysctl */ - NULL, - &ipv4_ctloutput, - - NULL, - NULL -}; - - -static int ipv4_module_init(void *cpp) -{ - if (cpp) - core = cpp; - - add_domain(NULL, AF_INET); - add_protocol(&my_proto, AF_INET); - - if (!icmp) - get_module(NET_ICMP_MODULE_NAME, (module_info **) &icmp); - - return 0; -} - -static int ipv4_module_stop(void) -{ - remove_protocol(&my_proto); - remove_domain(AF_INET); - - net_remove_timer(timerid); - return 0; -} - -struct ipv4_module_info protocol_info = { - { - { - NET_IPV4_MODULE_NAME, - 0, - std_ops - }, - ipv4_module_init, - ipv4_module_stop, - NULL - }, - - ipv4_output, - get_ip_id, - ipv4_ctloutput, - ip_srcroute, - ip_stripoptions, - ip_srcroute -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info **) &core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - return B_OK; - - default: - return B_ERROR; - } - return B_OK; -} - - -_EXPORT module_info *modules[] = { - (module_info *) &protocol_info, - NULL -}; - diff --git a/src/add-ons/kernel/network/protocols/raw/Jamfile b/src/add-ons/kernel/network/protocols/raw/Jamfile deleted file mode 100644 index d4bc31522c..0000000000 --- a/src/add-ons/kernel/network/protocols/raw/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols raw ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon raw : kernel obos_network protocols : - raw.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/protocols - : raw ; - -Package haiku-networkingkit-cvs : - raw : - boot home config add-ons kernel obos_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/raw/raw.c b/src/add-ons/kernel/network/protocols/raw/raw.c deleted file mode 100644 index f289f85634..0000000000 --- a/src/add-ons/kernel/network/protocols/raw/raw.c +++ /dev/null @@ -1,346 +0,0 @@ -/* raw.c */ - -#ifndef _KERNEL_MODE -#include -#include -#endif - -#include "sys/protosw.h" -#include "sys/domain.h" -#include "sys/socket.h" -#include "netinet/in_pcb.h" -#include "netinet/in.h" -#include "netinet/in_var.h" -#include "netinet/ip_var.h" - -#include "core_module.h" -#include "net_module.h" -#include "core_funcs.h" -#include "raw_module.h" -#include "ipv4_module.h" - -#include -status_t std_ops(int32 op, ...); - -static struct core_module_info *core = NULL; -static struct ipv4_module_info *ipm = NULL; - -static struct inpcb rawinpcb; -static struct sockaddr_in ripsrc; -static int rip_sendspace = 8192; -static int rip_recvspace = 8192; - -struct ipstat ipstat; //XXX might need to be shared - -static void rip_init(void) -{ - rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; - memset(&ripsrc, 0, sizeof(ripsrc)); - ripsrc.sin_family = AF_INET; - ripsrc.sin_len = sizeof(ripsrc); -} - -static void rip_input(struct mbuf *m, int hdrlen) -{ - struct ip *ip = mtod(m, struct ip*); - struct inpcb *inp; - struct socket *last = NULL; - - ripsrc.sin_addr = ip->ip_src; - for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp=inp->inp_next) { - if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) - continue; - if (inp->laddr.s_addr && inp->laddr.s_addr == ip->ip_dst.s_addr) - continue; - if (inp->faddr.s_addr && inp->faddr.s_addr == ip->ip_src.s_addr) - continue; - if (last) { - struct mbuf *n; - if ((n = m_copym(m, 0, (int)M_COPYALL))) { - if (sockbuf_appendaddr(&last->so_rcv, (struct sockaddr*)&ripsrc, - n, NULL) == 0) - m_freem(n); - else - sorwakeup(last); - } - } - last = inp->inp_socket; - } - if (last) { - if (sockbuf_appendaddr(&last->so_rcv, (struct sockaddr*)&ripsrc, - m, NULL) == 0) - m_freem(m); - else - sorwakeup(last); - } else { - m_freem(m); - ipstat.ips_noproto++; - ipstat.ips_delivered--; - } - return; -} - -static int rip_output(struct mbuf *m, struct socket *so, uint32 dst) -{ - struct ip *ip; - struct inpcb *inp = sotoinpcb(so); - struct mbuf *opts; - int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; - - if ((inp->inp_flags & INP_HDRINCL) == 0) { - M_PREPEND(m, (int) sizeof(struct ip)); - ip = mtod(m, struct ip *); - ip->ip_p = inp->inp_ip.ip_p; - ip->ip_len = m->m_pkthdr.len; - ip->ip_src = inp->laddr; - ip->ip_dst.s_addr = dst; - ip->ip_ttl = MAXTTL; - opts = inp->inp_options; - ip->ip_off = 0; - ip->ip_tos = 0; - } else { - ip = mtod(m, struct ip *); - /* ip_output relies on having the ip->ip_len in host - * order...this is lame... */ - ip->ip_len = ntohs(ip->ip_len); - if (ip->ip_id == 0) - if (ipm) - ip->ip_id = htons(ipm->ip_id()); - - opts = NULL; - flags |= IP_RAWOUTPUT; - ipstat.ips_rawout++; - } - - if (ipm) { - return ipm->output(m, opts, &inp->inp_route, flags, NULL); - } - /* XXX - last arg should be inp->inp_moptions when we have multicast */ - - return 0; -} - -static int rip_userreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, - struct mbuf *control) -{ - int error = 0; - struct inpcb *inp = sotoinpcb(so); - struct ifnet *interfaces = get_interfaces(); - - switch(req) { - case PRU_ATTACH: - if (inp) { - printf("Trying to attach to a socket already attached!\n"); - return EINVAL; - } - if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || - (error = in_pcballoc(so, &rawinpcb))) - break; - inp = (struct inpcb*)so->so_pcb; - inp->inp_ip.ip_p = (int)nam; - break; - case PRU_DISCONNECT: - if ((so->so_state & SS_ISCONNECTED) == 0) { - error = ENOTCONN; - break; - } - case PRU_ABORT: - socket_set_disconnected(so); - case PRU_DETACH: - if (inp == NULL) { - printf("Can't detach from NULL protocol block!\n"); - error = EINVAL; - break; - } - in_pcbdetach(inp); - break; - case PRU_SEND: { - uint32 dst; - if ((so->so_state & SS_ISCONNECTED)) { - if (nam) { - error = EISCONN; - break; - } - dst = inp->faddr.s_addr; - } else { - if (!nam) { - error = ENOTCONN; - break; - } - dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; - } - error = rip_output(m, so, dst); - m = NULL; - break; - } - case PRU_BIND: { - struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); - if (nam->m_len != sizeof(*addr)) { - error = EINVAL; - break; - } - if ((interfaces) || - ((addr->sin_family != AF_INET) && - (addr->sin_family != AF_IMPLINK)) || - (addr->sin_addr.s_addr && - ifa_ifwithaddr((struct sockaddr*)addr) == 0)) { - error = EADDRNOTAVAIL; - break; - } - inp->laddr = addr->sin_addr; - break; - } - case PRU_CONNECT: { - struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); - - if (nam->m_len != sizeof(*addr)) { - error = EINVAL; - break; - } - if ((interfaces == NULL)) { - error = EADDRNOTAVAIL; - break; - } - if ((addr->sin_family != AF_INET) && - (addr->sin_family != AF_IMPLINK)) { - error = EAFNOSUPPORT; - break; - } - inp->faddr = addr->sin_addr; - socket_set_connected(so); - break; - } - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - case PRU_SHUTDOWN: - socket_set_cantsendmore(so); - break; - case PRU_RCVOOB: - case PRU_RCVD: - case PRU_LISTEN: - case PRU_ACCEPT: - case PRU_SENDOOB: - error = EINVAL;//EOPNOTSUPP; - break; - /* add remaining cases */ - } - - return error; -} - -static int rip_ctloutput(int op, struct socket *so, int level, - int optnum, struct mbuf **m) -{ - struct inpcb *inp = sotoinpcb(so); - - if (level != IPPROTO_IP) - return EINVAL; - - switch (optnum) { - case IP_HDRINCL: - if (op == PRCO_SETOPT || op == PRCO_GETOPT) { - if (m == NULL || *m == NULL || (*m)->m_len < sizeof(int)) - return EINVAL; - if (op == PRCO_SETOPT) { - if (*mtod(*m, int*)) - inp->inp_flags |= INP_HDRINCL; - else - inp->inp_flags &= ~INP_HDRINCL; - m_free(*m); - } else { - (*m)->m_len = sizeof(int); - *mtod(*m, int*) = inp->inp_flags & INP_HDRINCL; - } - return 0; - } - break; - /* XXX - Add other options here */ - } - - return ipm->ctloutput(op, so, level, optnum, m); -} - -static struct protosw my_protocol = { - "Raw IP module", - NET_RAW_MODULE_NAME, - SOCK_RAW, - NULL, - 0, - PR_ATOMIC | PR_ADDR, - NET_LAYER4, - - &rip_init, - &rip_input, - NULL, - &rip_userreq, - NULL, /* pr_sysctl */ - NULL, - &rip_ctloutput, - - NULL, - NULL -}; - -static int raw_module_init(void *cpp) -{ - if (cpp) - core = cpp; - - add_domain(NULL, AF_INET); - add_protocol(&my_protocol, AF_INET); - - if (!ipm) - get_module(NET_IPV4_MODULE_NAME, (module_info**) &ipm); - - return 0; -} - -static int raw_module_stop(void) -{ - put_module(NET_IPV4_MODULE_NAME); - - remove_protocol(&my_protocol); - remove_domain(AF_INET); - - return 0; -} - -struct raw_module_info protocol_info = { - { - { - NET_RAW_MODULE_NAME, - 0, - std_ops - }, - raw_module_init, - raw_module_stop, - NULL - }, - &rip_input -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info **) &core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - break; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info *) &protocol_info, - NULL -}; diff --git a/src/add-ons/kernel/network/protocols/route/Jamfile b/src/add-ons/kernel/network/protocols/route/Jamfile deleted file mode 100644 index 007d5ffdf2..0000000000 --- a/src/add-ons/kernel/network/protocols/route/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols route ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon route : kernel obos_network protocols : - route.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/protocols - : route ; - -Package haiku-networkingkit-cvs : - route : - boot home config add-ons kernel obos_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/route/route.c b/src/add-ons/kernel/network/protocols/route/route.c deleted file mode 100644 index b383e8254b..0000000000 --- a/src/add-ons/kernel/network/protocols/route/route.c +++ /dev/null @@ -1,786 +0,0 @@ -/* route.c */ - -#ifndef _KERNEL_MODE -#include -#include -#endif - -#include "net_malloc.h" - -#include "net/route.h" /* includes net/radix.h */ -#include "protocols.h" -#include "net/if.h" -#include "sys/protosw.h" -#include "sys/domain.h" -#include "net/raw_cb.h" -#include "sys/socketvar.h" - -#include "core_module.h" -#include "net_module.h" -#include "core_funcs.h" - -#include -status_t std_ops(int32 op, ...); -#define NET_ROUTE_MODULE_NAME NETWORK_MODULES_ROOT "protocols/route" - -static struct core_module_info *core = NULL; -static struct rawcb rawcb; -static struct route_cb route_cb; -static struct pool_ctl *rawcbpool = NULL; - -static int32 raw_sendspace = 8192; -static int32 raw_recvspace = 8192; - -static struct sockaddr route_src = { 2, PF_ROUTE, }; -static struct sockaddr route_dst = { 2, PF_ROUTE, }; -static struct sockproto route_proto = { PF_ROUTE, }; - -#define ROUNDUP(a) (a >0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) - -/* BSD used these, we don't, we expand them fully! */ -//#define dst info.rti_info[RTAX_DST] -//#define gate info.rti_info[RTAX_GATEWAY] -//#define netmask info.rti_info[RTAX_NETMASK] -//#define genmask info.rti_info[RTAX_GENMASK] -//#define ifpaddr info.rti_info[RTAX_IFP] -//#define ifaaddr info.rti_info[RTAX_IFA] -//#define brdaddr info.rti_info[RTAX_BRD] - -/* Routing socket support */ - -static void rt_setmetrics(uint32 which, struct rt_metrics *in, - struct rt_metrics *out) -{ -#define metric(f, e) if (which & f) out->e = in->e; - metric(RTV_RPIPE, rmx_recvpipe); -#undef metric -} - -static void rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) -{ - struct sockaddr *sa; - int i; - - memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); - for (i = 0;(i < RTAX_MAX) && (cp < cplim);i++) { - if ((rtinfo->rti_addrs & (1 << i)) == 0) - continue; - rtinfo->rti_info[i] = sa = (struct sockaddr*)cp; - ADVANCE(cp, sa); - } -} - -static int rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, - struct walkarg *w) -{ - int i; - int len, dlen, second_time = 0; - caddr_t cp0; - - rtinfo->rti_addrs = 0; -again: - switch(type) { - case RTM_DELADDR: - case RTM_NEWADDR: - len = sizeof(struct ifa_msghdr); - break; - case RTM_IFINFO: - len = sizeof(struct if_msghdr); - break; - default: - len = sizeof(struct rt_msghdr); - } - - if ((cp0 = cp)) - cp += len; - for (i=0; i < RTAX_MAX; i++) { - struct sockaddr *sa; - - if ((sa = rtinfo->rti_info[i]) == NULL) - continue; - rtinfo->rti_addrs |= (1 << i); - dlen = ROUNDUP(sa->sa_len); - if (cp) { - memcpy(cp, (caddr_t)sa, dlen); - cp += dlen; - } - len += dlen; - } - - if (cp == NULL && w!= NULL && !second_time) { - struct walkarg *rw = w; - - rw->w_needed += len; - if (rw->w_needed <= 0 && rw->w_where) { - if (rw->w_tmemsize < len) { - if (rw->w_tmem) - free(rw->w_tmem); - if ((rw->w_tmem = (caddr_t)malloc(len))) { - memset(rw->w_tmem, 0, len); - rw->w_tmemsize = len; - } - } - if (rw->w_tmem) { - cp = rw->w_tmem; - second_time = 1; - goto again; - } else - rw->w_where = NULL; - } - } - if (cp) { - struct rt_msghdr *rtm = (struct rt_msghdr*)cp0; - rtm->rtm_version = RTM_VERSION; - rtm->rtm_type = type; - rtm->rtm_msglen = len; - } - return len; -} - -static void raw_init(void) -{ - rawcb.rcb_next = rawcb.rcb_prev = &rawcb; - memset(&route_cb, 0, sizeof(struct route_cb)); - if (!rawcbpool) - pool_init(&rawcbpool, sizeof(struct rawcb)); -} - -static int raw_attach(struct socket *so, int proto) -{ - struct rawcb *rp = sotorawcb(so); - int error; - - if (rp == NULL) - return ENOBUFS; - if ((error = soreserve(so, raw_sendspace, raw_recvspace))) - return error; - rp->rcb_socket = so; - rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family; - rp->rcb_proto.sp_protocol = proto; - - rp->rcb_prev = rawcb.rcb_next->rcb_prev; - rp->rcb_next = rawcb.rcb_next; - rawcb.rcb_next->rcb_prev = rp; - rawcb.rcb_next = rp; - - return 0; -} - -static int raw_detach(struct rawcb *rp) -{ - struct socket *so = rp->rcb_socket; - - so->so_pcb = NULL; - rp->rcb_prev->rcb_next = rp->rcb_next; - rp->rcb_next->rcb_prev = rp->rcb_prev; - - pool_put(rawcbpool, rp); - return 0; -} - -static int raw_input(struct mbuf *m0, struct sockproto *proto, struct sockaddr *src, - struct sockaddr *dst) -{ - struct rawcb *rp; - struct mbuf *m = m0; - int sockets = 0; - struct socket *last; - - last = NULL; - for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { - if (rp->rcb_proto.sp_family != proto->sp_family) - continue; - if (rp->rcb_proto.sp_protocol && - rp->rcb_proto.sp_protocol != proto->sp_protocol) - continue; -#define equal(a1, a2) (memcmp((caddr_t)a1, (caddr_t)a2, a1->sa_len) == 0) - if (rp->rcb_laddr && !equal(rp->rcb_laddr, dst)) - continue; - if (rp->rcb_faddr && !equal(rp->rcb_faddr, src)) - continue; - if (last) { - struct mbuf *n; - if ((n = m_copym(m, 0, M_COPYALL))) { - if (sockbuf_appendaddr(&last->so_rcv, src, n, NULL) == 0) - m_freem(n); - else { - sorwakeup(last); - sockets++; - } - } - } - last = rp->rcb_socket; - } - if (last) { - if (sockbuf_appendaddr(&last->so_rcv, src, m, NULL) == 0) - m_freem(m); - else { - sorwakeup(last); - sockets++; - } - } else - m_freem(m); - return 0; -} - -static int route_output(struct mbuf *m, struct socket *so) -{ - struct rt_msghdr *rtm = NULL; - struct rtentry *rt = NULL; - struct rtentry *saved_nrt = NULL; - struct rt_addrinfo info; - int len; - int error = 0; - struct ifnet *ifp = NULL; - struct ifaddr *ifa = NULL; - -#define snderr(e) { error = e; goto flush; } - - if (m == NULL || ((m->m_len < sizeof(int32)) && - ((m = m_pullup(m, sizeof(int32))) == NULL))) { - printf("route_output: ENOBUFS (m_pullup)\n"); - if (m) - printf("m = %p, m_len = %ld\n", m, m->m_len); - return ENOBUFS; - } - if ((m->m_flags & M_PKTHDR) == 0) { - printf("route_output: Not packet header\n"); - return -1; - } - len = m->m_pkthdr.len; - if (len < (int) sizeof(*rtm) || len != (mtod(m, struct rt_msghdr*))->rtm_msglen) { - info.rti_info[RTAX_DST] = NULL; - printf("route_output: EINVAL\n"); - snderr(EINVAL); - } - R_Malloc(rtm, struct rt_msghdr *, len); - if (rtm == NULL) { - info.rti_info[RTAX_DST] = NULL; - printf("route_output: ENOBUFS (rtm == NULL)\n"); - snderr(ENOBUFS); - } - m_copydata(m, 0, len, (caddr_t)rtm); - if (rtm->rtm_version != RTM_VERSION) { - info.rti_info[RTAX_DST] = NULL; - printf("route_output: EPROTONOSUPPORT\n"); - snderr(EPROTONOSUPPORT); - } - - info.rti_addrs = rtm->rtm_addrs; - rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info); - - if (info.rti_info[RTAX_DST] == NULL) - snderr(EINVAL); - - if (info.rti_info[RTAX_GENMASK]) { - struct radix_node *t; - t = rn_addmask((caddr_t)info.rti_info[RTAX_GENMASK], 1, 2); - if (t && Bcmp(info.rti_info[RTAX_GENMASK], t->rn_key, *(uint8*)info.rti_info[RTAX_GENMASK]) == 0) - info.rti_info[RTAX_GENMASK] = (struct sockaddr *)t->rn_key; - else - snderr(ENOBUFS); - } - - switch (rtm->rtm_type) { - case RTM_ADD: - if (info.rti_info[RTAX_GATEWAY] == NULL) { - printf("route_output: EINVAL\n"); - snderr(EINVAL); - } - error = rtrequest(RTM_ADD, info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY], - info.rti_info[RTAX_NETMASK], rtm->rtm_flags, &saved_nrt); - if (error == 0 && saved_nrt) { - rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &saved_nrt->rt_rmx); - saved_nrt->rt_refcnt--; - saved_nrt->rt_genmask = info.rti_info[RTAX_GENMASK]; - } - break; - case RTM_DELETE: - error = rtrequest(RTM_DELETE, info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY], - info.rti_info[RTAX_NETMASK], rtm->rtm_flags, NULL); - break; - case RTM_GET: - case RTM_CHANGE: - case RTM_LOCK: - rt = rtalloc1(info.rti_info[RTAX_DST], 0); - if (rt == NULL) { - printf("route_output: ESRCH\n"); - snderr(ESRCH); - } - if (rtm->rtm_type != RTM_GET) { - struct radix_node *rn; - if (Bcmp(info.rti_info[RTAX_DST], rt_key(rt), - info.rti_info[RTAX_DST]->sa_len) != 0) - snderr(ESRCH); - if (info.rti_info[RTAX_NETMASK] && - (rn = rn_head_search(info.rti_info[RTAX_NETMASK]))) - info.rti_info[RTAX_NETMASK] = (struct sockaddr*)rn->rn_key; - for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) - if (info.rti_info[RTAX_NETMASK] == (struct sockaddr*)rn->rn_mask) - break; - if (rn == NULL) { - printf("route_output: ETOOMANYREFS\n"); - snderr(EINVAL);//ETOOMANYREFS; - } - rt = (struct rtentry *)rn; - } - switch (rtm->rtm_type) { - case RTM_GET: - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GENMASK] = rt->rt_genmask; - if (rtm->rtm_addrs && (RTA_IFP | RTA_IFA)) { - if ((ifp = rt->rt_ifp)) { - info.rti_info[RTAX_IFA] = ifp->if_addrlist->ifa_addr; - info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; - rtm->rtm_index = ifp->if_index; - } else { - info.rti_info[RTAX_IFA] = NULL; - info.rti_info[RTAX_IFA] = NULL; - } - } - len = rt_msg2(RTM_GET, &info, NULL, NULL); - if (len > rtm->rtm_msglen) { - struct rt_msghdr *new_rtm ; - R_Malloc(new_rtm, struct rt_msghdr *, len); - if (new_rtm == NULL) - snderr(ENOBUFS); - Bcopy(rtm, new_rtm, rtm->rtm_msglen); - Free(rtm); - rtm = new_rtm; - } - (void)rt_msg2(RTM_GET, &info, (caddr_t)rtm, NULL); - rtm->rtm_flags = rt->rt_flags; - rtm->rtm_rmx = rt->rt_rmx; - rtm->rtm_addrs = info.rti_addrs; - break; - case RTM_CHANGE: - if (info.rti_info[RTAX_GATEWAY] && rt_setgate(rt, rt_key(rt), info.rti_info[RTAX_GATEWAY])) { - printf("route_output: EDQUOT\n"); - snderr(EINVAL); //EDQUOT ??? - } - /* new gateway could require a new ifaddr and ifp, flags might also - * be different. ifp may be specified by link level sockaddr when - * protocol address is ambiguous... - */ - if (info.rti_info[RTAX_IFA] && - (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFA])) && - (ifp = ifa->ifa_ifp)) - ifa = ifaof_ifpforaddr(info.rti_info[RTAX_IFA] ? - info.rti_info[RTAX_IFA] : - info.rti_info[RTAX_GATEWAY], - ifp); - else if ((info.rti_info[RTAX_IFA] && (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || - (ifa = ifa_ifwithroute(rt->rt_flags, rt_key(rt), info.rti_info[RTAX_GATEWAY]))) - ifp = ifa->ifa_ifp; - if (ifa) { - struct ifaddr *oifa = rt->rt_ifa; - if (oifa != ifa) { - if (oifa && oifa->ifa_rtrequest) - oifa->ifa_rtrequest(RTM_DELETE, rt, info.rti_info[RTAX_GATEWAY]); - IFAFREE(rt->rt_ifa); - rt->rt_ifa = ifa; - ifa->ifa_refcnt++; - rt->rt_ifp = ifp; - } - } - rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx); - if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) - rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info.rti_info[RTAX_GATEWAY]); - if (info.rti_info[RTAX_GENMASK]) - rt->rt_genmask = info.rti_info[RTAX_GENMASK]; - /* fall through... */ - case RTM_LOCK: - rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); - rt->rt_rmx.rmx_locks |= (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); - break; - } - break; - default: - printf("route_output: EOPNOTSUPP\n"); - snderr(EINVAL); //EOPNOTSUPP; - } - -flush: - if (rtm) { - if (error) - rtm->rtm_errno = error; - else - rtm->rtm_flags |= RTF_DONE; - } - if (rt) - rtfree(rt); - { - struct rawcb *rp = NULL; - /* check if it's our own message! */ - if ((so->so_options & SO_USELOOPBACK) == 0) { - if (route_cb.any_count <= 1) { - if (rtm) - Free(rtm); - m_freem(m); - return error; - } - rp = sotorawcb(so); - } - if (rtm) { - m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); - Free(rtm); - } - if (rp) - rp->rcb_proto.sp_family = 0; - if (info.rti_info[RTAX_DST]) - route_proto.sp_protocol = info.rti_info[RTAX_DST]->sa_family; - raw_input(m, &route_proto, &route_src, &route_dst); - if (rp) - rp->rcb_proto.sp_family = PF_ROUTE; - } - return error; -} - -static int sysctl_dumpentry(struct radix_node *rn, void *data) -{ - struct rtentry *rt = (struct rtentry *)rn; - int error = 0, size; - struct rt_addrinfo info; - struct walkarg *w = (struct walkarg *)data; - - if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) - return 0; - memset((caddr_t)&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GENMASK] = rt->rt_genmask; - size = rt_msg2(RTM_GET, &info, 0, w); - if (w->w_where && w->w_tmem) { - struct rt_msghdr *rtm = (struct rt_msghdr*)w->w_tmem; - - rtm->rtm_flags = rt->rt_flags; - rtm->rtm_use = rt->rt_use; - rtm->rtm_rmx = rt->rt_rmx; - rtm->rtm_index = rt->rt_ifp->if_index; - rtm->rtm_errno = rtm->rtm_seq = 0; - rtm->rtm_addrs = info.rti_addrs; - if (memcpy(w->w_where, (caddr_t)rtm, size) == NULL) { - error = ENOMEM; - w->w_where = NULL; - } else - w->w_where += size; - } - return error; -} - -static int sysctl_iflist(int af, struct walkarg *w) -{ - struct ifnet *ifp; - struct ifaddr *ifa; - struct rt_addrinfo info; - int len; - struct ifnet *interfaces = get_interfaces(); - - memset(&info, 0, sizeof(info)); - for (ifp = interfaces; ifp; ifp = ifp->if_next) { - if (w->w_arg && w->w_arg != ifp->if_index) - continue; - ifa = ifp->if_addrlist; - info.rti_info[RTAX_IFA] = ifa->ifa_addr; - len = rt_msg2(RTM_IFINFO, &info, NULL, w); - info.rti_info[RTAX_IFA] = NULL; - if (w->w_where && w->w_tmem) { - struct if_msghdr *ifm; - - ifm = (struct if_msghdr*)w->w_tmem; - ifm->ifm_index = ifp->if_index; - ifm->ifm_flags = ifp->if_flags; - ifm->ifm_data = ifp->ifd; - ifm->ifm_addrs = info.rti_addrs; - if (memcpy(w->w_where, (caddr_t)ifm, len) == NULL) - return ENOMEM; - w->w_where += len; - } - while ((ifa = ifa->ifa_next) != NULL) { - if (af && af != ifa->ifa_addr->sa_family) - continue; - info.rti_info[RTAX_IFA] = ifa->ifa_addr; - info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; - info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; - len = rt_msg2(RTM_NEWADDR, &info, NULL, w); - if (w->w_where && w->w_tmem) { - struct ifa_msghdr *ifam; - - ifam = (struct ifa_msghdr *)w->w_tmem; - ifam->ifam_index = ifa->ifa_ifp->if_index; - ifam->ifam_flags = ifa->ifa_flags; - ifam->ifam_metric = ifa->ifa_metric; - ifam->ifam_addrs = info.rti_addrs; - if (memcpy(w->w_where, w->w_tmem, len) == NULL) - return ENOMEM; - w->w_where += len; - } - } - info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = info.rti_info[RTAX_BRD] = NULL; - } - return 0; -} - -static int sysctl_rtable(int *name, uint namelen, void *where, size_t *given, void *newp, - size_t newlen) -{ - int i, error = EINVAL; - uchar af; - struct walkarg w; - struct radix_node_head *rnh; - struct radix_node_head **rt_tables; - - if (newp) - return EPERM; - - if (namelen != 3) { - printf("sysctl_rtable: EINVAL (namelen != 3)\n"); - return EINVAL; - } - - rt_tables = get_rt_tables(); - - af = name[0]; - memset(&w, 0, sizeof(w)); - w.w_where = where; - w.w_given = *given; - w.w_needed = 0 - w.w_given; - w.w_op = name[1]; - w.w_arg = name[2]; - - switch(w.w_op) { - case NET_RT_DUMP: - case NET_RT_FLAGS: - for(i=1 ; i <= AF_MAX; i++) { - rnh = rt_tables[i]; - if (rnh && (af == 0 || af == i) && - (error = rnh->rnh_walktree(rnh, sysctl_dumpentry, &w))) - break; - } - break; - case NET_RT_IFLIST: - error = sysctl_iflist(af, &w); - } - - if (w.w_tmem) - free(w.w_tmem); - w.w_needed += w.w_given; - if (where) { - *given = (caddr_t)w.w_where - (caddr_t)where; - if (*given < (size_t) w.w_needed) { - printf("sysctl_rtable: ENOMEM\n"); - return ENOMEM; - } - } else { - *given = (11 * w.w_needed) / 10; - } - return error; -} - -static int raw_userreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, - struct mbuf *control) -{ - struct rawcb *rp = sotorawcb(so); - int error = 0; - - if (req == PRU_CONTROL) { - return EINVAL;//EOPNOTSUPP; - } - if (control && control->m_len) { - error = EINVAL;//EOPNOTSUPP; - goto release; - } - if (rp == NULL) { - error = EINVAL; - goto release; - } - - switch(req) { - case PRU_ATTACH: - error = raw_attach(so, (int) nam); - break; - case PRU_DETACH: - if (rp == NULL) { - error = ENOTCONN; - break; - } - raw_detach(rp); - break; - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - case PRU_DISCONNECT: - if (rp->rcb_faddr == NULL) { - error = ENOTCONN; - break; - } - raw_detach(rp); - socket_set_disconnected(so); - break; - case PRU_SHUTDOWN: - socket_set_cantsendmore(so); - break; - case PRU_LISTEN: - case PRU_ACCEPT: - case PRU_SENDOOB: - error = EOPNOTSUPP; - break; - case PRU_ABORT: - raw_detach(rp); - socket_set_disconnected(so); - break; - case PRU_SEND: - if (nam) { - if (rp->rcb_faddr) { - error = EISCONN; - break; - } - rp->rcb_faddr = mtod(nam, struct sockaddr *); - } else if (rp->rcb_faddr == NULL) { - error = ENOTCONN; - break; - } - /* XXX - Hmm, should we be hardcoding this??? */ - error = route_output(m, so); - m = NULL; - if (nam) - rp->rcb_faddr = NULL; - break; - default: - printf("raw_userreq: unsupported request.\n"); - } - -release: - if (m != NULL) - m_freem(m); - return error; -} - -static int route_userreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, - struct mbuf *control) -{ - int error = 0; - struct rawcb *rp = sotorawcb(so); - - if (req == PRU_ATTACH) { - rp = (struct rawcb*)pool_get(rawcbpool); - if ((so->so_pcb = (caddr_t)rp)) - memset(so->so_pcb, 0, sizeof(*rp)); - } - if (req == PRU_DETACH && rp) { - int af = rp->rcb_proto.sp_protocol; - if (af == AF_INET) - route_cb.ip_count--; - route_cb.any_count--; - } - - error = raw_userreq(so, req, m, nam, control); - rp = sotorawcb(so); - if (req == PRU_ATTACH && rp) { - int af = rp->rcb_proto.sp_protocol; - if (error) { - pool_put(rawcbpool, rp); - return error; - } - if (af == AF_INET) - route_cb.ip_count++; - route_cb.any_count++; - - rp->rcb_faddr = &route_src; - socket_set_connected(so); - so->so_options |= SO_USELOOPBACK; - } - return error; -} - - - -static struct protosw my_protocol = { - "Routing Sockets", - NET_ROUTE_MODULE_NAME, - SOCK_RAW, - NULL, - 0, - PR_ATOMIC | PR_ADDR, - NET_LAYER4, - - &raw_init, - NULL, - NULL, - &route_userreq, - &sysctl_rtable, /* pr_sysctl */ - NULL, - NULL, /* pr_ctloutput */ - - NULL, - NULL -}; - -static struct domain pf_route_domain = { - PF_ROUTE, - "route", - NULL, - NULL, - NULL, - NULL, - 0, - 0 -}; - -static int route_module_init(void *cpp) -{ - if (cpp) - core = cpp; - - add_domain(&pf_route_domain, PF_ROUTE); - add_protocol(&my_protocol, PF_ROUTE); - - return 0; -} - -static int route_module_stop(void) -{ - remove_protocol(&my_protocol); - remove_domain(PF_ROUTE); - return 0; -} - -struct kernel_net_module_info protocol_info = { - { - NET_ROUTE_MODULE_NAME, - 0, - std_ops - }, - route_module_init, - route_module_stop, - NULL -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info**) &core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - break; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info *)&protocol_info, - NULL -}; diff --git a/src/add-ons/kernel/network/protocols/tcp/Jamfile b/src/add-ons/kernel/network/protocols/tcp/Jamfile deleted file mode 100644 index 27c30f78c6..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/Jamfile +++ /dev/null @@ -1,29 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols tcp ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon tcp : kernel obos_network protocols : - arc4random.c - tcp.c - tcp_debug.c - tcp_input.c - tcp_output.c - tcp_timer.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/protocols - : tcp ; - -Package haiku-networkingkit-cvs : - tcp : - boot home config add-ons kernel obos_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/tcp/arc4random.c b/src/add-ons/kernel/network/protocols/tcp/arc4random.c deleted file mode 100644 index 368d70dd91..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/arc4random.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Arc4 random number generator for OpenBSD. - * Copyright 1996 David Mazieres . - * - * Modification and redistribution in source and binary forms is - * permitted provided that due credit is given to the author and the - * OpenBSD project by leaving this copyright notice intact. - */ - -/* - * This code is derived from section 17.1 of Applied Cryptography, - * second edition, which describes a stream cipher allegedly - * compatible with RSA Labs "RC4" cipher (the actual description of - * which is a trade secret). The same algorithm is used as a stream - * cipher called "arcfour" in Tatu Ylonen's ssh package. - * - * Here the stream cipher has been modified always to include the time - * when initializing the state. That makes it impossible to - * regenerate the same random sequence twice, so this can't be used - * for encryption, but will generate good random numbers. - * - * RC4 is a registered trademark of RSA Laboratories. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ - -struct arc4_stream { - uint8 i; - uint8 j; - uint8 s[256]; -}; - -int rs_initialized; -static struct arc4_stream rs; - -void arc4random_stir(void); -void arc4random_addrandom(u_char *dat, int datlen); -uint32 arc4random(void); - - - -static inline void arc4_init(struct arc4_stream *as) -{ - int n; - - for (n = 0; n < 256; n++) - as->s[n] = n; - as->i = 0; - as->j = 0; -} - - -static inline void arc4_addrandom(struct arc4_stream *as, - u_char *dat, int datlen) -{ - int n; - uint8 si; - - as->i--; - for (n = 0; n < 256; n++) { - as->i = (as->i + 1); - si = as->s[as->i]; - as->j = (as->j + si + dat[n % datlen]); - as->s[as->i] = as->s[as->j]; - as->s[as->j] = si; - } - as->j = as->i; -} - - -static void arc4_stir(struct arc4_stream *as) -{ - int fd; - struct { - struct timeval tv; - u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)]; - } rdat; - - gettimeofday(&rdat.tv, NULL); - fd = open("/dev/arandom", O_RDONLY); - if (fd != -1) { - read(fd, rdat.rnd, sizeof(rdat.rnd)); - close(fd); - } - /* fd < 0 or failed sysctl ? Ah, what the heck. We'll just take - * whatever was on the stack... */ - - arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); -} - - -static inline uint8 arc4_getbyte(struct arc4_stream *as) -{ - uint8 si, sj; - - as->i = (as->i + 1); - si = as->s[as->i]; - as->j = (as->j + si); - sj = as->s[as->j]; - as->s[as->i] = sj; - as->s[as->j] = si; - return (as->s[(si + sj) & 0xff]); -} - - -static inline uint32 arc4_getword(struct arc4_stream *as) -{ - uint32 val; - val = arc4_getbyte(as) << 24; - val |= arc4_getbyte(as) << 16; - val |= arc4_getbyte(as) << 8; - val |= arc4_getbyte(as); - return val; -} - - -void arc4random_stir(void) -{ - if (!rs_initialized) { - arc4_init(&rs); - rs_initialized = 1; - } - arc4_stir(&rs); -} - -void arc4random_addrandom(u_char *dat, int datlen) -{ - if (!rs_initialized) - arc4random_stir(); - arc4_addrandom(&rs, dat, datlen); -} - - -uint32 arc4random(void) -{ - if (!rs_initialized) - arc4random_stir(); - return arc4_getword(&rs); -} diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.c b/src/add-ons/kernel/network/protocols/tcp/tcp.c deleted file mode 100644 index 73f2b229dd..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.c +++ /dev/null @@ -1,585 +0,0 @@ -/* udp.c - */ - -#ifndef _KERNEL_MODE -#include -#include -#endif - -#include "pools.h" -#include "net_misc.h" -#include "protocols.h" -#include "netinet/in_systm.h" -#include "netinet/in_var.h" -#include "netinet/in_pcb.h" -#include "netinet/ip.h" -#include "sys/domain.h" -#include "sys/protosw.h" -#include "netinet/ip_var.h" -#include "netinet/tcp.h" -#include "netinet/tcp_timer.h" -#include "netinet/tcp_fsm.h" -#include "netinet/tcp_seq.h" -#include "netinet/tcp_var.h" -#include "netinet/tcpip.h" - -#include "core_module.h" -#include "net_module.h" -#include "core_funcs.h" -#include "ipv4_module.h" -#include "net_timer.h" - -#include -#define NET_TCP_MODULE_NAME NETWORK_MODULES_ROOT "protocols/tcp" -status_t std_ops(int32 op, ...); - -struct core_module_info *core = NULL; -struct ipv4_module_info *ipm = NULL; - -/* Declaration as we don't have it natively... */ -uint32 arc4random(); - -struct protosw *proto[IPPROTO_MAX]; -struct pool_ctl *tcppool = NULL; - -/* patchable/settable parameters for tcp */ -int tcp_mssdflt = TCP_MSS; -int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; -static net_timer_id slowtim; -static net_timer_id fasttim; - -struct inpcb *tcp_last_inpcb = NULL; - -static uint32 tcp_sendspace = 8192; /* size of send buffer */ -static uint32 tcp_recvspace = 8192; /* size of recieve buffer */ - -/* was in tcp_var.h */ -struct inpcb tcb; -struct tcpstat tcpstat; -int tcp_mssdflt; -int tcp_do_rfc1323; -unsigned long tcp_now; - -/* was in tcp_seq.h */ -tcp_seq tcp_iss; /* tcp initial send seq # */ - - -// XXX shared? look into sockbuf.c -uint32 sb_max = SB_MAX; - -static void tcp_init(void) -{ - tcp_now = arc4random() / 2; - tcp_iss = 1; - - tcb.inp_next = tcb.inp_prev = &tcb; - if (get_max_protohdr() < (int) sizeof(struct tcpiphdr)) - set_max_protohdr(sizeof(struct tcpiphdr)); - memset(&tcpstat, 0, sizeof(struct tcpstat)); - - memset(proto, 0, sizeof(struct protosw *) * IPPROTO_MAX); - add_protosw(proto, NET_LAYER4); - - if (!tcppool) - pool_init(&tcppool, sizeof(struct tcpcb)); - - /* Add timers... */ - /* Assuming we're using usecs, then we call PR_SLOWHZ per sec - * which is 1,000,000 / PR_SLOWHZ - */ - slowtim = net_add_timer(&tcp_slowtimer, NULL, 1000000 / PR_SLOWHZ); - fasttim = net_add_timer(&tcp_fasttimer, NULL, 1000000 / PR_FASTHZ); -} - -struct tcpiphdr *tcp_template(struct tcpcb *tp) -{ - struct inpcb *inp = tp->t_inpcb; - struct mbuf *m; - struct tcpiphdr *n = NULL; - - if ((n = tp->t_template) == NULL) { - m = m_get(MT_HEADER); - if (m == NULL) - return NULL; - m->m_len = sizeof(struct tcpiphdr); - n = mtod(m, struct tcpiphdr*); - } - /* ??? maybe we should just memset 0 and then fill in what we need? */ - n->ti_next = n->ti_prev = NULL; - n->ti_x1 = 0; - n->ti_pr = IPPROTO_TCP; - n->ti_len = htons(sizeof(struct tcpiphdr) - sizeof(struct ip)); - n->ti_src = inp->laddr; - n->ti_dst = inp->faddr; - n->ti_sport = inp->lport; - n->ti_dport = inp->fport; - n->ti_seq = 0; - n->ti_ack = 0; - n->ti_x2 = 0; - n->ti_off = 5; - n->ti_flags = 0; - n->ti_win = 0; - n->ti_sum = 0; - n->ti_urp = 0; - return n; -} - -struct tcpcb *tcp_close(struct tcpcb *tp) -{ - struct tcpiphdr *t; - struct inpcb *inp = tp->t_inpcb; - struct socket *so = inp->inp_socket; - struct mbuf *m; - struct rtentry *rt; - - /* did we send enough data to get some meaningful iformation? - * If we did save it in the routing entry. - * We define enough as being the sendpipesize (default 8k) x 16 - * which should give us 16 rtt samples, assuming of course we only - * have one sample per frame. - * 16 samples is enough for the srtt filter to converge to within 5% - * of the correct value. - * - * We don't however update the default route or anything else that the - * user has locked. - */ - if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) && - (rt = inp->inp_route.ro_rt) && - ((struct sockaddr_in*)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { - uint32 i; - - if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { - i = tp->t_srtt * (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); - if (rt->rt_rmx.rmx_rtt && i) - /* - * update this value with half the old and new values, - * converting scale. - */ - rt->rt_rmx.rmx_rtt = (rt->rt_rmx.rmx_rtt + i) / 2; - else - rt->rt_rmx.rmx_rtt = i; - } - if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { - i = tp->t_rttvar * (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); - if (rt->rt_rmx.rmx_rttvar && i) - rt->rt_rmx.rmx_rttvar = (rt->rt_rmx.rmx_rttvar + i) / 2; - else - rt->rt_rmx.rmx_rttvar = i; - } - /* update the pipelimit (ssthresh) */ - if ((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && - ((i = tp->snd_ssthresh) && (rt->rt_rmx.rmx_ssthresh || - i < (rt->rt_rmx.rmx_sendpipe / 2)))) { - /* convert the limit from user data bytes to - * packets and then to packet data bytes - */ - i = (i + tp->t_maxseg / 2) / tp->t_maxseg; - if (i < 2) - i = 2; - i *= (u_long)(tp->t_maxseg + sizeof(struct tcpiphdr)); - if (rt->rt_rmx.rmx_ssthresh) - rt->rt_rmx.rmx_ssthresh = (rt->rt_rmx.rmx_ssthresh + i) / 2; - else - rt->rt_rmx.rmx_ssthresh = i; - } - } - /* free our reassembly queue */ - t = tp->seg_next; - while (t != (struct tcpiphdr*)tp) { - t = (struct tcpiphdr*)t->ti_next; - m = REASS_MBUF((struct tcpiphdr*)t->ti_prev); - remque(t->ti_prev); - m_freem(m); - } - if (tp->t_template) - (void)m_free(dtom(tp->t_template)); - - pool_put(tcppool, tp); - inp->inp_ppcb = NULL; - socket_set_disconnected(so); - if (inp == tcp_last_inpcb) - tcp_last_inpcb = &tcb; - in_pcbdetach(inp); - tcpstat.tcps_closed++; - - return NULL; -} - -struct tcpcb *tcp_drop(struct tcpcb *tp, int error) -{ - struct socket *so = tp->t_inpcb->inp_socket; - - if (TCPS_HAVERCVDSYN(tp->t_state)) { - tp->t_state = TCPS_CLOSED; - (void) tcp_output(tp); - tcpstat.tcps_drops++; - } else - tcpstat.tcps_conndrops++; - - if (error == ETIMEDOUT && tp->t_softerror) - error = tp->t_softerror; - so->so_error = error; - return tcp_close(tp); -} - -void tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, - tcp_seq ack, tcp_seq seq, int flags) -{ - int tlen; - int win = 0; - struct route *ro = NULL; - - if (tp) { - win = sbspace(&tp->t_inpcb->inp_socket->so_rcv); - ro = &tp->t_inpcb->inp_route; - } - if (m == NULL) { - m = m_gethdr(MT_HEADER); - if (!m) - return; - tlen = 0; - m->m_data += get_max_linkhdr(); - *mtod(m, struct tcpiphdr*) = *ti; - ti = mtod(m, struct tcpiphdr*); - flags = TH_ACK; - } else { - m_freem(m->m_next); - m->m_next = NULL; - m->m_data = (caddr_t) ti; - m->m_len = sizeof(struct tcpiphdr); - tlen = 0; -#define xchng(a,b,type) { type t; t=a; a=b; b= t; } - xchng(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32); - xchng(ti->ti_dport, ti->ti_sport, uint16); -#undef xchng - } - ti->ti_len = htons((uint16)(sizeof(struct tcphdr) + tlen)); - tlen += sizeof(struct tcpiphdr); - m->m_len = tlen; - m->m_pkthdr.len = tlen; - m->m_pkthdr.rcvif = NULL; - ti->ti_next = ti->ti_prev = NULL; - ti->ti_x1 = 0; - ti->ti_seq = htonl(seq); - ti->ti_ack = htonl(ack); - ti->ti_x2 = 0; - ti->ti_off = sizeof(struct tcphdr) >> 2; - ti->ti_flags = flags; - if (tp) - ti->ti_win = htons((uint16)(win >> tp->rcv_scale)); - else - ti->ti_win = htons((uint16)win); - ti->ti_urp = 0; - ti->ti_sum = 0; - ti->ti_sum = in_cksum(m, tlen, 0); - ((struct ip*)ti)->ip_len = tlen; - ((struct ip*)ti)->ip_ttl = 64;/* XXX - ip_defttl; */ - ipm->output(m, NULL, ro, 0, NULL); -} - -static struct tcpcb *tcp_usrclosed(struct tcpcb *tp) -{ - switch(tp->t_state) { - case TCPS_CLOSED: - case TCPS_LISTEN: - case TCPS_SYN_SENT: - tp->t_state = TCPS_CLOSED; - tp = tcp_close(tp); - break; - case TCPS_SYN_RECEIVED: - case TCPS_ESTABLISHED: - tp->t_state = TCPS_FIN_WAIT_1; - break; - case TCPS_CLOSE_WAIT: - tp->t_state = TCPS_LAST_ACK; - break; - } - if (tp && tp->t_state >= TCPS_FIN_WAIT_2) - socket_set_disconnected(tp->t_inpcb->inp_socket); - return tp; -} - -static struct tcpcb *tcp_disconnect(struct tcpcb *tp) -{ - struct socket *so = tp->t_inpcb->inp_socket; - - if (tp->t_state < TCPS_ESTABLISHED) - tp = tcp_close(tp); - else if ((so->so_options & SO_LINGER) && so->so_linger == 0) - tp = tcp_drop(tp, 0); - else { - socket_set_disconnecting(so); - sockbuf_flush(&so->so_rcv); - tp = tcp_usrclosed(tp); - if (tp) - tcp_output(tp); - } - return tp; -} - -static struct tcpcb * tcp_newtcpcb(struct inpcb *inp) -{ - struct tcpcb *tp; - tp = (struct tcpcb*)pool_get(tcppool); - if (!tp) - return NULL; - memset(tp, 0, sizeof(*tp)); - tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp; - tp->t_maxseg = tcp_mssdflt; - tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE | TF_REQ_TSTMP) : 0; - tp->t_inpcb = inp; - - tp->t_srtt = TCPTV_SRTTBASE; - tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; - tp->t_rttmin = TCPTV_MIN; - TCPT_RANGESET(tp->t_rxtcur, ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, - TCPTV_MIN, TCPTV_REXMTMAX); - tp->snd_cwnd = tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; - - inp->inp_ip.ip_ttl = 64;/* XXX - ip_defttl; */ - inp->inp_ppcb = (caddr_t)tp; - return tp; -} - -static int tcp_attach(struct socket *so) -{ - struct inpcb *inp; - struct tcpcb *tp; - int error = 0; - - if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { - error = soreserve(so, tcp_sendspace, tcp_recvspace); - if (error) - return error; - } - error = in_pcballoc(so, &tcb); - if (error) - return error; - inp = sotoinpcb(so); - tp = tcp_newtcpcb(inp); - if (tp == NULL) { - /* we don't want to free the socket just yet, so - * record the setting of SS_NOFDREF, then clear the bit, - * detach and then reset the bit. - */ - int nofd = so->so_state & SS_NOFDREF; - so->so_state &= ~SS_NOFDREF; - in_pcbdetach(inp); - so->so_state |= nofd; - return ENOBUFS; - } - tp->t_state = TCPS_CLOSED; - return 0; -} - -int tcp_userreq(struct socket *so, int req, struct mbuf *m, - struct mbuf *nam, struct mbuf *control) -{ - struct inpcb *inp; - struct tcpcb *tp = NULL; - int error = 0; - int ostate; - - if (req == PRU_CONTROL) - return in_control(so, (int)m, (caddr_t)nam, (struct ifnet *)control); - if (control && control->m_len) { - m_freem(control); - if (m) - m_freem(m); - return EINVAL; - } - - inp = sotoinpcb(so); - /* When we're attached, the inpcb points at the socket */ - if (inp == NULL && req != PRU_ATTACH) - return EINVAL; - - if (inp) { - tp = intotcpcb(inp); - ostate = tp->t_state; - } else - ostate = 0; - - switch(req) { - case PRU_ATTACH: - if (inp) { - error = EISCONN; - break; - } - error = tcp_attach(so); - if (error) - break; - if ((so->so_options & SO_LINGER) && so->so_linger == 0) - so->so_linger = TCP_LINGERTIME; - tp = sototcpcb(so); - break; - case PRU_DETACH: - if (tp->t_state > TCPS_LISTEN) - tp = tcp_disconnect(tp); - else - tp = tcp_close(tp); - break; - case PRU_BIND: - error = in_pcbbind(inp, nam); - break; - case PRU_LISTEN: - if (inp->lport == 0) - error = in_pcbbind(inp, NULL); - if (error == 0) - tp->t_state = TCPS_LISTEN; - break; - case PRU_CONNECT: - if (inp->lport == 0) { - error = in_pcbbind(inp, NULL); - if (error) - break; - } - - error = in_pcbconnect(inp, nam); - if (error) { - printf("in_pcbconnect gave error %d\n", error); - break; - } - tp->t_template = tcp_template(tp); - if (tp->t_template == NULL) { - in_pcbdisconnect(inp); - error = ENOBUFS; - break; - } - while (tp->request_r_scale < TCP_MAX_WINSHIFT && - (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) - tp->request_r_scale++; - socket_set_connecting(so); - tcpstat.tcps_connattempt++; - tp->t_state = TCPS_SYN_SENT; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - - tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR / 2; - tcp_sendseqinit(tp); - error = tcp_output(tp); - break; - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; - case PRU_DISCONNECT: - tp = tcp_disconnect(tp); - break; - case PRU_ACCEPT: - in_setpeeraddr(inp, nam); - break; - case PRU_SLOWTIMO: - tp = tcp_timers(tp, (int)nam); - req |= (int)nam << 8; - break; - case PRU_SEND: - sockbuf_append(&so->so_snd, m); - error = tcp_output(tp); - break; - case PRU_RCVD: - (void) tcp_output(tp); - break; - case PRU_SHUTDOWN: - socket_set_cantsendmore(so); - tp = tcp_usrclosed(tp); - if (tp) - error = tcp_output(tp); - break; - case PRU_SOCKADDR: - in_setsockaddr(inp, nam); - break; - case PRU_PEERADDR: - in_setpeeraddr(inp, nam); - break; - } -/* XXX - add tcp_trace! - if (tp && (so->so_options & SO_DEBUG)) -*/ - return error; -} - -static struct protosw my_proto = { - "TCP Module", - NET_TCP_MODULE_NAME, - SOCK_STREAM, - NULL, - IPPROTO_TCP, - PR_CONNREQUIRED | PR_WANTRCVD, - NET_LAYER3, - - &tcp_init, - &tcp_input, /* pr_input */ - NULL, /* pr_output */ - &tcp_userreq, /* pr_userreq */ - NULL, /* pr_sysctl */ - NULL, /* pr_ctlinput */ - NULL, /* pr_ctloutput */ - - NULL, - NULL -}; - - -static int tcp_module_init(void *cpp) -{ - if (cpp) - core = cpp; - - add_domain(NULL, AF_INET); - add_protocol(&my_proto, AF_INET); - - if (!ipm) - get_module(NET_IPV4_MODULE_NAME, (module_info **) &ipm); - - return 0; -} - -static int tcp_module_stop(void) -{ - net_remove_timer(slowtim); - net_remove_timer(fasttim); - - put_module(NET_IPV4_MODULE_NAME); - - remove_protocol(&my_proto); - remove_domain(AF_INET); - - return 0; -} - -struct kernel_net_module_info protocol_info = { - { - NET_TCP_MODULE_NAME, - 0, - std_ops - }, - tcp_module_init, - tcp_module_stop, - NULL -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info **) &core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - break; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info *) &protocol_info, - NULL -}; - diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp_debug.c b/src/add-ons/kernel/network/protocols/tcp/tcp_debug.c deleted file mode 100644 index 552f602526..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/tcp_debug.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 - * - * NRL grants permission for redistribution and use in source and binary - * forms, with or without modification, of the software and documentation - * created at NRL provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgements: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * This product includes software developed at the Information - * Technology Division, US Naval Research Laboratory. - * 4. Neither the name of the NRL nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS - * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the US Naval - * Research Laboratory (NRL). - */ - -#ifdef TCPDEBUG -/* load symbolic names */ -char *tanames[] = { "input", "output", "user", "respond", "drop" }; - -#define PRUREQUESTS -#define TCPSTATES -#define TCPTIMERS -#endif - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef INET6 -#ifndef INET -#include -#endif -#include -#endif /* INET6 */ - -#ifdef TCPDEBUG -int tcpconsdebug = 0; -#endif -/* - * Tcp debug routines - */ -void tcp_trace(int16 act, int16 ostate, struct tcpcb *tp, void *headers, - int req, int len) -{ -#ifdef TCPDEBUG - tcp_seq seq, ack; - int flags; -#endif - struct tcp_debug *td = &tcp_debug[tcp_debx++]; - struct tcpiphdr *ti = (struct tcpiphdr *)headers; - struct tcphdr *th; -#ifdef INET6 - struct tcpipv6hdr *ti6 = (struct tcpipv6hdr *)ti; -#endif - - if (tcp_debx == TCP_NDEBUG) - tcp_debx = 0; - td->td_time = iptime(); - td->td_act = act; - td->td_ostate = ostate; - td->td_tcb = (caddr_t)tp; - if (tp) - td->td_cb = *tp; - else - memset((caddr_t)&td->td_cb, 0, sizeof (*tp)); -#ifdef INET6 - if (tp->pf == PF_INET6) { - if (ti) { - th = &ti6->ti6_t; - td->td_ti6 = *ti6; - } else { - memset(&td->td_ti6, 0, sizeof(struct tcpipv6hdr)); - } - } else -#endif /* INET6 */ - { - if (ti) { - th = &ti->ti_t; - td->td_ti = *ti; - } else { - memset(&td->td_ti, 0, sizeof(struct tcpiphdr)); - } - } - - td->td_req = req; -#ifdef TCPDEBUG - if (tcpconsdebug == 0) - return; - if (tp) - printf("%x %s:", tp, tcpstates[ostate]); - else - printf("???????? "); - printf("%s ", tanames[act]); - switch (act) { - case TA_INPUT: - case TA_OUTPUT: - case TA_DROP: - if (ti == 0) - break; - seq = th->th_seq; - ack = th->th_ack; - if (act == TA_OUTPUT) { - seq = ntohl(seq); - ack = ntohl(ack); - } - if (len) - printf("[%x..%x)", seq, seq+len); - else - printf("%x", seq); - printf("@%x, urp=%x", ack, th->th_urp); - flags = th->th_flags; - if (flags) { -#ifndef lint - char *cp = "<"; -#define pf(f) { if (th->th_flags&TH_##f) { printf("%s%s", cp, "f"); cp = ","; } } - pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG); -#endif - printf(">"); - } - break; - - case TA_USER: - printf("%s", prurequests[req&0xff]); - if ((req & 0xff) == PRU_SLOWTIMO) - printf("<%s>", tcptimers[req>>8]); - break; - } - if (tp) - printf(" -> %s", tcpstates[tp->t_state]); - /* print out internal state of tp !?! */ - printf("\n"); - if (tp == 0) - return; - printf("\trcv_(nxt,wnd,up) (%x,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n", - tp->rcv_nxt, tp->rcv_wnd, tp->rcv_up, tp->snd_una, tp->snd_nxt, - tp->snd_max); - printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n", - tp->snd_wl1, tp->snd_wl2, tp->snd_wnd); -#endif /* TCPDEBUG */ -} diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp_input.c b/src/add-ons/kernel/network/protocols/tcp/tcp_input.c deleted file mode 100644 index 11f24b1e74..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/tcp_input.c +++ /dev/null @@ -1,1739 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 - * - * NRL grants permission for redistribution and use in source and binary - * forms, with or without modification, of the software and documentation - * created at NRL provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgements: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * This product includes software developed at the Information - * Technology Division, US Naval Research Laboratory. - * 4. Neither the name of the NRL nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS - * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the US Naval - * Research Laboratory (NRL). - */ - -#ifndef _KERNEL_MODE -#include -#endif - -#include -#include - -#include "sys/protosw.h" -#include "sys/socket.h" -#include "sys/socketvar.h" - -#include "net/if.h" -#include "net/route.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core_module.h" -#include "core_funcs.h" -#include "ipv4_module.h" - -#ifdef _KERNEL_MODE -#include -#endif - -extern struct core_module_info *core; -extern struct ipv4_module_info *ipm; - -int tcprexmtthresh = 3; -struct tcpiphdr tcp_saveti; -int tcptv_keep_init = TCPTV_KEEP_INIT; - -extern struct inpcb *tcp_last_inpcb; -extern uint32 sb_max; - -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) - -/* for modulo comparisons of timestamps */ -#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) -#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) - -#define TCP_REASS(tp, ti, m, so, flags) { \ - if ((ti)->ti_seq == (tp)->rcv_nxt && \ - (tp)->seg_next == (struct tcpiphdr*)(tp) && \ - (tp)->t_state == TCPS_ESTABLISHED) { \ - \ - (tp)->t_flags |= TF_DELACK; \ - (tp)->rcv_nxt += (ti)->ti_len; \ - (flags) = (ti)->ti_flags & TH_FIN; \ - tcpstat.tcps_rcvpack++; \ - tcpstat.tcps_rcvbyte += (ti)->ti_len; \ - sockbuf_append(&(so)->so_rcv, (m)); \ - sorwakeup(so); \ - } else { \ - (flags) = tcp_reass((tp), (ti), (m)); \ - (tp)->t_flags |= TF_ACKNOW; \ - }\ -} - -int tcp_reass(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m); - -/* The BeOS R5 kernel doesn't have abs(). */ -#ifdef COMPILE_FOR_R5 -int abs(int num) -{ - return (int)labs(num); -} -#endif - - -/* - * Insert segment ti into reassembly queue of tcp with - * control block tp. Return TH_FIN if reassembly now includes - * a segment with FIN. The macro form does the common case inline - * (segment is the next to be received on an established connection, - * and the queue is empty), avoiding linkage into and removal - * from the queue and repetition of various conversions. - * Set DELACK for segments received in order, but ack immediately - * when segments are out of order (so fast retransmit can work). - */ - -int tcp_reass(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m) -{ - struct tcpiphdr *q; - struct socket *so = tp->t_inpcb->inp_socket; - int flags; - - /* - * Call with ti==NULL after become established to - * force pre-ESTABLISHED data up to user socket. - */ - if (ti == NULL) - goto present; - - /* - * Find a segment which begins after this one does. - */ - for (q = tp->seg_next; q != (struct tcpiphdr*)tp; q = (struct tcpiphdr*)q->ti_next) - if (SEQ_GT(q->ti_seq, ti->ti_seq)) - break; - /* - * If there is a preceding segment, it may provide some of - * our data already. If so, drop the data from the incoming - * segment. If it provides all of our data, drop us. - */ - if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr*)tp) { - int i; - q = (struct tcpiphdr*)q->ti_prev; - /* conversion to int (in i) handles seq wraparound */ - i = (q->ti_seq + q->ti_len) - ti->ti_seq; - if (i > 0) { - if (i >= ti->ti_len) { - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += ti->ti_len; - //m_freem(m); - return (0); - } - m_adj(m, i); - ti->ti_len -= i; - ti->ti_seq += i; - } - q = (struct tcpiphdr*)(q->ti_next); - } - tcpstat.tcps_rcvoopack++; - tcpstat.tcps_rcvoobyte += ti->ti_len; - REASS_MBUF(ti) = m; - - /* - * While we overlap succeeding segments trim them or, - * if they are completely covered, dequeue them. - */ - while (q != (struct tcpiphdr*)tp) { - int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; - - if (i <= 0) - break; - if (i < q->ti_len) { - q->ti_seq += i; - q->ti_len -= i; - m_adj(REASS_MBUF(q), i); - break; - } - q = (struct tcpiphdr*)q->ti_next; - m = REASS_MBUF((struct tcpiphdr*)q->ti_prev); - remque(q->ti_prev); - //m_freem(m); - } - - insque(ti, q->ti_prev); - -present: - /* - * Present data to user, advancing rcv_nxt through - * completed sequence space. - */ - if (TCPS_HAVERCVDSYN(tp->t_state) == 0) { - return 0; - } - ti = tp->seg_next; - if (ti == (struct tcpiphdr*)tp || ti->ti_seq != tp->rcv_nxt) { - return 0; - } - if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) { - return 0; - } - do { - tp->rcv_nxt += ti->ti_len; - flags = ti->ti_flags & TH_FIN; - remque(ti); - - m = REASS_MBUF(ti); - ti = (struct tcpiphdr*) ti->ti_next; - /* XXX - Change - * BSD sockets would call m_freem(m) if this was true, but if we - * do that we have trouble... - * So, reverse the logic and only append data if we can. - */ - if ((so->so_state & SS_CANTRCVMORE) == 0) - sockbuf_append(&so->so_rcv, m); - } while (ti != (struct tcpiphdr*)tp && ti->ti_seq == tp->rcv_nxt); - sorwakeup(so); - return (flags); -} - -#ifdef TCP_DEBUG -static void show_ti(struct tcpiphdr *ti) -{ - printf("TCP/IP Header:\n"); - printf(" : src port : %d\n", ntohs(ti->ti_sport)); - printf(" : dst port : %d\n", ntohs(ti->ti_dport)); - printf(" : seq num : %lu\n", ti->ti_seq); - printf(" : ack num : %lu\n", ti->ti_ack); - printf(" : hdr len : %d\n", ti->ti_len); - printf(" : flags : "); - if (ti->ti_flags & TH_SYN) - printf(" SYN "); - if (ti->ti_flags & TH_ACK) - printf(" ACK "); - if (ti->ti_flags & TH_RST) - printf(" RST "); - if (ti->ti_flags & TH_PUSH) - printf(" PSH "); - if (ti->ti_flags & TH_URG) - printf(" URG "); - if (ti->ti_flags & TH_FIN) - printf(" FIN "); - printf("\n"); - printf(" : win : %d\n", ti->ti_win); - -} - -static void show_tp(struct tcpcb *tp) -{ - printf("TCP Control Block:\n"); - printf(" : snd_una : %lu\n", tp->snd_una); - printf(" : snd_nxt : %lu\n", tp->snd_nxt); - printf(" : snd_up : %lu\n", tp->snd_up); - printf(" : snd_wl1 : %lu\n", tp->snd_wl1); - printf(" : snd_wl2 : %lu\n", tp->snd_wl2); - printf(" : iss : %lu\n", tp->iss); - printf(" : rcv_wnd : %lu\n", tp->rcv_wnd); - printf(" : rcv_nxt : %lu\n", tp->rcv_nxt); - printf(" : rcv_up : %lu\n", tp->rcv_up); - printf(" : last_ack_sent : %lu\n", tp->last_ack_sent); - printf(" : flags : "); - if (tp->t_flags & TF_ACKNOW) - printf(" ACKNOW "); - if (tp->t_flags & TF_DELACK) - printf(" DELACK "); - if (tp->t_flags & TF_SENTFIN) - printf(" SENTFIN "); - if (tp->t_flags & TF_NODELAY) - printf(" NODELAY "); - if (tp->t_flags & TF_NOOPT) - printf(" NOOPT "); - printf("\n"); -} -#endif /* TCP_DEBUG */ - -/* - * TCP input routine, follows pages 65-76 of the - * protocol specification dated September, 1981 very closely. - */ -void tcp_input(struct mbuf *m, int iphlen) -{ - struct inpcb *inp; - caddr_t optp = NULL; - int optlen = 0; - int len = 0; - uint16 tlen = 0; - int off = 0; - struct tcpcb *tp = NULL; - int tiflags = 0; - struct socket *so = NULL; - int todrop, acked, ourfinisacked, needoutput = 0; - short ostate = 0; - struct in_addr laddr; - int dropsocket = 0; - int iss = 0; - u_long tiwin; - uint32 ts_val, ts_ecr; - int ts_present = 0; - struct tcpiphdr *ti; - - tcpstat.tcps_rcvtotal++; - /* Get the IP and TCP header together (the tcpiphdr struct) - * together in the first mbuf. - * NB IP layer should leave IP header in first mbuf - */ - ti = mtod(m, struct tcpiphdr*); - - if (iphlen > (int) sizeof(struct ip)) - ipm->ip_stripoptions(m, NULL); - - if (m->m_len < sizeof(struct tcpiphdr)) { - if ((m = m_pullup(m, sizeof(struct tcpiphdr))) == NULL) { - tcpstat.tcps_rcvshort++; - return; - } - ti = mtod(m, struct tcpiphdr*); - } - - /* - * Checksum extended TCP header and data. - */ - tlen = ((struct ip *) ti)->ip_len; - len = sizeof(struct ip) + tlen; - - ti->ti_next = ti->ti_prev = NULL; - ti->ti_x1 = 0; - ti->ti_len = htons(tlen); - - if ((ti->ti_sum = in_cksum(m, len, 0))) { - tcpstat.tcps_rcvbadsum++; - printf("invalid checksum %d over %d bytes!\n", ti->ti_sum, len); - goto drop; - } - - off = ti->ti_off << 2; - if (off < (int) sizeof(struct tcphdr) || off > tlen) { - tcpstat.tcps_rcvbadoff++; - printf("tcp_input: bad len\n"); - goto drop; - } - - tlen -=off; - ti->ti_len = tlen; - - if (off > (int) sizeof(struct tcphdr)) { - if (m->m_len < sizeof(struct ip) + off) { - if ((m = m_pullup(m, sizeof(struct ip) + off)) == NULL) { - tcpstat.tcps_rcvshort++; - return; - } - ti = mtod(m, struct tcpiphdr*); - } - optlen = off - sizeof(struct tcphdr); - optp = mtod(m, caddr_t) + sizeof(struct tcphdr); - - /* - * Do quick retrieval of timestamp options ("options - * prediction?"). If timestamp is the only option and it's - * formatted as recommended in RFC 1323 appendix A, we - * quickly get the values now and not bother calling - * tcp_dooptions(), etc. - */ - if ((optlen == TCPOLEN_TSTAMP_APPA || - (optlen > TCPOLEN_TSTAMP_APPA && - optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && - *(uint32 *)optp == htonl(TCPOPT_TSTAMP_HDR) && - (ti->ti_flags & TH_SYN) == 0) { - ts_present = 1; - ts_val = ntohl(*(uint32 *)(optp + 4)); - ts_ecr = ntohl(*(uint32 *)(optp + 8)); - optp = NULL; /* we've parsed the options */ - } - } - tiflags = ti->ti_flags; - - /* - * Convert TCP protocol specific fields to host format. - */ - ti->ti_seq = ntohl(ti->ti_seq); - ti->ti_ack = ntohl(ti->ti_ack); - ti->ti_win = ntohs(ti->ti_win); - ti->ti_urp = ntohs(ti->ti_urp); - - /* - * Locate pcb for segment. - */ -findpcb: - inp = tcp_last_inpcb; - if (!inp || inp->lport != ti->ti_dport || - inp->fport != ti->ti_sport || - inp->faddr.s_addr != ti->ti_src.s_addr || - inp->laddr.s_addr != ti->ti_dst.s_addr) { - inp = in_pcblookup(&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, - ti->ti_dport, INPLOOKUP_WILDCARD); - if (inp) - tcp_last_inpcb = inp; - ++tcpstat.tcps_pcbhashmiss; - } - if (inp == NULL) { -/* XXX - This is very common, but only commented out as it's useful at times - for debugging. - printf("tcp_input: dropwithreset: inp is NULL, line %d\n", __LINE__); - */ - goto dropwithreset; - } - - tp = intotcpcb(inp); - if (tp == NULL) { - printf("tcp_input: dropwithreset: tp is NULL, line %d\n", __LINE__); - goto dropwithreset; - } - - if (tp->t_state == TCPS_CLOSED) { - printf("tcp_input: state is closed\n"); - goto drop; - } - - /* Unscale the window into a 32-bit value. */ - if ((tiflags & TH_SYN) == 0) - tiwin = ti->ti_win << tp->snd_scale; - else - tiwin = ti->ti_win; - - so = inp->inp_socket; - if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { - if (so->so_options & SO_DEBUG) { - ostate = tp->t_state; - tcp_saveti = *ti; - } - if (so->so_options & SO_ACCEPTCONN) { - so = sonewconn(so, 0); - if (so == NULL) { - goto drop; - } - /* - * This is ugly, but .... - * - * Mark socket as temporary until we're - * committed to keeping it. The code at - * ``drop'' and ``dropwithreset'' check the - * flag dropsocket to see if the temporary - * socket created here should be discarded. - * We mark the socket as discardable until - * we're committed to it below in TCPS_LISTEN. - */ - dropsocket++; - inp = (struct inpcb *)so->so_pcb; - inp->laddr = ti->ti_dst; - inp->lport = ti->ti_dport; - inp->inp_options = ipm->ip_srcroute(); - tp = intotcpcb(inp); - tp->t_state = TCPS_LISTEN; - - tp->request_r_scale = 0; - /* Compute proper scaling value from buffer space */ - while (tp->request_r_scale < TCP_MAX_WINSHIFT && - TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) - tp->request_r_scale++; - } - } - - /* - * Segment received on connection. - * Reset idle time and keep-alive timer. - */ - tp->t_idle = 0; - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - - /* - * Process options if not in LISTEN state, - * else do it below (after getting remote address). - */ - if (optp && tp->t_state != TCPS_LISTEN) - tcp_dooptions(tp, (unsigned char *)optp, optlen, ti, &ts_present, &ts_val, &ts_ecr); - - /* - * Header prediction: check for the two common cases - * of a uni-directional data xfer. If the packet has - * no control flags, is in-sequence, the window didn't - * change and we're not retransmitting, it's a - * candidate. If the length is zero and the ack moved - * forward, we're the sender side of the xfer. Just - * free the data acked & wake any higher level process - * that was blocked waiting for space. If the length - * is non-zero and the ack didn't move, we're the - * receiver side. If we're getting packets in-order - * (the reassembly queue is empty), add the data to - * the socket buffer and note that we need a delayed ack. - */ - if (tp->t_state == TCPS_ESTABLISHED && - (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && - (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && - ti->ti_seq == tp->rcv_nxt && - tiwin && tiwin == tp->snd_wnd && - tp->snd_nxt == tp->snd_max) { - - /* - * If last ACK falls within this segment's sequence numbers, - * record the timestamp. - * Fix from Braden, see Stevens p. 870 - */ - if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent)) { - tp->ts_recent_age = tcp_now; - tp->ts_recent = ts_val; - } - - if (ti->ti_len == 0) { - if (SEQ_GT(ti->ti_ack, tp->snd_una) && - SEQ_LEQ(ti->ti_ack, tp->snd_max) && - tp->snd_cwnd >= tp->snd_wnd) { - /* - * this is a pure ack for outstanding data. - */ - ++tcpstat.tcps_predack; - if (ts_present) - tcp_xmit_timer(tp, tcp_now - ts_ecr + 1); - else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) - tcp_xmit_timer(tp, tp->t_rtt); - acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; - sockbuf_drop(&so->so_snd, acked); - tp->snd_una = ti->ti_ack; - m_freem(m); - - /* - * If all outstanding data are acked, stop - * retransmit timer, otherwise restart timer - * using current (possibly backed-off) value. - * If process is waiting for space, - * wakeup/selwakeup/signal. If data - * are ready to send, let tcp_output - * decide between more output or persist. - */ - if (tp->snd_una == tp->snd_max) - tp->t_timer[TCPT_REXMT] = 0; - else if (tp->t_timer[TCPT_PERSIST] == 0) - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - - if (so->so_snd.sb_flags & SB_NOTIFY) - sowwakeup(so); - if (so->so_snd.sb_cc) { - (void) tcp_output(tp); - } - return; - } - } else if (ti->ti_ack == tp->snd_una && - tp->seg_next == (struct tcpiphdr*)tp && - ti->ti_len <= sbspace(&so->so_rcv)) { - /* - * This is a pure, in-sequence data packet - * with nothing on the reassembly queue and - * we have enough buffer space to take it. - */ - ++tcpstat.tcps_preddat; - tp->rcv_nxt += ti->ti_len; - tcpstat.tcps_rcvpack++; - tcpstat.tcps_rcvbyte += ti->ti_len; - /* - * Drop TCP, IP headers and TCP options then add data - * to socket buffer. - */ - m->m_data += sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); - m->m_len -= sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); - sockbuf_append(&so->so_rcv, m); - sorwakeup(so); - tp->t_flags |= TF_DELACK; - return; - } - } - - m->m_data += sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); - m->m_len -= sizeof(struct tcpiphdr) + off - sizeof(struct tcphdr); - - /* - * Calculate amount of space in receive window, - * and then do TCP input processing. - * Receive window is amount of space in rcv queue, - * but not less than advertised window. - */ - { - int win = sbspace(&so->so_rcv); - if (win < 0) - win = 0; - tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); - } - - switch (tp->t_state) { - - /* - * If the state is LISTEN then ignore segment if it contains an RST. - * If the segment contains an ACK then it is bad and send a RST. - * If it does not contain a SYN then it is not interesting; drop it. - * If it is from this socket, drop it, it must be forged. - * Don't bother responding if the destination was a broadcast. - * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial - * tp->iss, and send a segment: - * - * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. - * Fill in remote peer address fields if not previously specified. - * Enter SYN_RECEIVED state, and process any other fields of this - * segment in this state. - */ - case TCPS_LISTEN: { - struct mbuf *am; - struct sockaddr_in *sin; - - if (tiflags & TH_RST) { - printf("tcp_input: TH_RST\n"); - goto drop; - } - if (tiflags & TH_ACK) { - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - if ((tiflags & TH_SYN) == 0) { - printf("tcp_input: TH_SYN\n"); - goto drop; - } - /* - * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN - * in_broadcast() should never return true on a received - * packet with M_BCAST not set. - */ - if (m->m_flags & (M_BCAST | M_MCAST) || - IN_MULTICAST(ti->ti_dst.s_addr)) { - printf("tcp_input: multicast! %d\n", __LINE__); - goto drop; - } - - am = m_get(MT_SONAME); - if (!am) { - printf("failed to get MT_SONAME\n"); - goto drop; - } - am->m_len = sizeof(struct sockaddr_in); - sin = mtod(am, struct sockaddr_in *); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ti->ti_src; - sin->sin_port = ti->ti_sport; - memset((caddr_t)sin->sin_zero, 0, sizeof(sin->sin_zero)); - laddr = inp->laddr; - if (inp->laddr.s_addr == INADDR_ANY) - inp->laddr = ti->ti_dst; - - if (in_pcbconnect(inp, am)) { - inp->laddr = laddr; - (void) m_free(am); - printf("tcp_input: in_pcbconnect failed\n"); - goto drop; - } - (void) m_free(am); - tp->t_template = tcp_template(tp); - if (tp->t_template == NULL) { - printf("template = NULL\n"); - tp = tcp_drop(tp, ENOBUFS); - dropsocket = 0; /* socket is already gone */ - goto drop; - } - if (optp) - tcp_dooptions(tp, (unsigned char *)optp, optlen, ti, - &ts_present, &ts_val, &ts_ecr); - - if (iss) - tp->iss = iss; - else - tp->iss = tcp_iss; - tcp_iss += TCP_ISSINCR / 2; - tp->irs = ti->ti_seq; - tcp_sendseqinit(tp); - tcp_rcvseqinit(tp); - tp->t_flags |= TF_ACKNOW; - tp->t_state = TCPS_SYN_RECEIVED; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - dropsocket = 0; /* committed to socket */ - tcpstat.tcps_accepts++; - goto trimthenstep6; - } - - /* - * If the state is SYN_RECEIVED: - * if seg contains SYN/ACK, send an RST. - * if seg contains an ACK, but not for our SYN/ACK, send an RST - */ - - case TCPS_SYN_RECEIVED: - if (tiflags & TH_ACK) { - if (tiflags & TH_SYN) { - tcpstat.tcps_badsyn++; - printf("SYN + ACK in a reply\n"); - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - if (SEQ_LEQ(ti->ti_ack, tp->snd_una) || - SEQ_GT(ti->ti_ack, tp->snd_max)) { - printf("SEQ outside of boundaries...\n"); - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - } - break; - - /* - * If the state is SYN_SENT: - * if seg contains an ACK, but not for our SYN, drop the input. - * if seg contains a RST, then drop the connection. - * if seg does not contain SYN, then drop it. - * Otherwise this is an acceptable SYN segment - * initialize tp->rcv_nxt and tp->irs - * if seg contains ack then advance tp->snd_una - * if SYN has been acked change to ESTABLISHED else SYN_RCVD state - * arrange for segment to be acked (eventually) - * continue processing rest of data/controls, beginning with URG - */ - case TCPS_SYN_SENT: - if ((tiflags & TH_ACK) && - (SEQ_LEQ(ti->ti_ack, tp->iss) || - SEQ_GT(ti->ti_ack, tp->snd_max))) { - printf("SYN_SENT but ACK was not for our request!\n"); - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - if (tiflags & TH_RST) { - if (tiflags & TH_ACK) - tp = tcp_drop(tp, ECONNREFUSED); - printf("tcp_input: %d\n", __LINE__); - goto drop; - } - if ((tiflags & TH_SYN) == 0) { - printf("tcp_input: %d\n", __LINE__); - goto drop; - } - if (tiflags & TH_ACK) { - tp->snd_una = ti->ti_ack; - if (SEQ_LT(tp->snd_nxt, tp->snd_una)) - tp->snd_nxt = tp->snd_una; - } - tp->t_timer[TCPT_REXMT] = 0; - tp->irs = ti->ti_seq; - tcp_rcvseqinit(tp); - tp->t_flags |= TF_ACKNOW; - if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { - tcpstat.tcps_connects++; - socket_set_connected(so); - tp->t_state = TCPS_ESTABLISHED; - /* Do window scaling on this connection? */ - if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - (TF_RCVD_SCALE|TF_REQ_SCALE)) { - tp->snd_scale = tp->requested_s_scale; - tp->rcv_scale = tp->request_r_scale; - } - (void) tcp_reass(tp, NULL, NULL); - /* - * if we didn't have to retransmit the SYN, - * use its rtt as our initial srtt & rtt var. - */ - if (tp->t_rtt) - tcp_xmit_timer(tp, tp->t_rtt); - } else - tp->t_state = TCPS_SYN_RECEIVED; - -trimthenstep6: - /* - * Advance ti->ti_seq to correspond to first data byte. - * If data, trim to stay within window, - * dropping FIN if necessary. - */ - ti->ti_seq++; - if (ti->ti_len > tp->rcv_wnd) { - todrop = ti->ti_len - tp->rcv_wnd; - m_adj(m, -todrop); - ti->ti_len = tp->rcv_wnd; - tiflags &= ~TH_FIN; - tcpstat.tcps_rcvpackafterwin++; - tcpstat.tcps_rcvbyteafterwin += todrop; - } - tp->snd_wl1 = ti->ti_seq - 1; - tp->rcv_up = ti->ti_seq; - goto step6; - } - - /* - * States other than LISTEN or SYN_SENT. - * First check timestamp, if present. - * Then check that at least some bytes of segment are within - * receive window. If segment begins before rcv_nxt, - * drop leading data (and SYN); if nothing left, just ack. - * - * RFC 1323 PAWS: If we have a timestamp reply on this segment - * and it's less than ts_recent, drop it. - * PAWS = Protection Against Wrapped Sequence Numbers - */ - if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && - TSTMP_LT(ts_val, tp->ts_recent)) { - - /* Check to see if ts_recent is over 24 days old. */ - if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { - /* - * Invalidate ts_recent. If this segment updates - * ts_recent, the age will be reset later and ts_recent - * will get a valid value. If it does not, setting - * ts_recent to zero will at least satisfy the - * requirement that zero be placed in the timestamp - * echo reply when ts_recent isn't valid. The - * age isn't reset until we get a valid ts_recent - * because we don't want out-of-order segments to be - * dropped when ts_recent is old. - */ - tp->ts_recent = 0; - } else { - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += ti->ti_len; - tcpstat.tcps_pawsdrop++; - goto dropafterack; - } - } - - todrop = tp->rcv_nxt - ti->ti_seq; - if (todrop > 0) { - if (tiflags & TH_SYN) { - tiflags &= ~TH_SYN; - ti->ti_seq++; - if (ti->ti_urp > 1) - ti->ti_urp--; - else - tiflags &= ~TH_URG; - todrop--; - } - if ((todrop >= ti->ti_len) || (todrop == ti->ti_len && - (tiflags & TH_FIN) == 0)) { - /* - * Any valid FIN must be to the left of the - * window. At this point, FIN must be a - * duplicate or out-of-sequence, so drop it. - */ - tiflags &= ~TH_FIN; - /* - * Send ACK to resynchronize, and drop any data, - * but keep on processing for RST or ACK. - */ - tp->t_flags |= TF_ACKNOW; - todrop = ti->ti_len; - tcpstat.tcps_rcvduppack++; - tcpstat.tcps_rcvdupbyte += todrop; - } else { - tcpstat.tcps_rcvpartduppack++; - tcpstat.tcps_rcvpartdupbyte += todrop; - } - m_adj(m, todrop); - ti->ti_seq += todrop; - ti->ti_len -= todrop; - if (ti->ti_urp > todrop) - ti->ti_urp -= todrop; - else { - tiflags &= ~TH_URG; - ti->ti_urp = 0; - } - } - - /* - * If new data are received on a connection after the - * user processes are gone, then RST the other end. - */ -/* XXX - how do we check this!!! */ - if ((so->so_state & SS_NOFDREF) && - tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { - tp = tcp_close(tp); - tcpstat.tcps_rcvafterclose++; - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - - /* - * If segment ends after window, drop trailing data - * (and PUSH and FIN); if nothing left, just ACK. - */ - todrop = (ti->ti_seq + ti->ti_len) - (tp->rcv_nxt + tp->rcv_wnd); - if (todrop > 0) { - tcpstat.tcps_rcvpackafterwin++; - if (todrop >= ti->ti_len) { - tcpstat.tcps_rcvbyteafterwin += ti->ti_len; - /* - * If a new connection request is received - * while in TIME_WAIT, drop the old connection - * and start over if the sequence numbers - * are above the previous ones. - */ - if (tiflags & TH_SYN && - tp->t_state == TCPS_TIME_WAIT && - SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { - iss = tp->rcv_nxt + TCP_ISSINCR; - tp = tcp_close(tp); - goto findpcb; - } - /* - * If window is closed can only take segments at - * window edge, and have to drop data and PUSH from - * incoming segments. Continue processing, but - * remember to ack. Otherwise, drop segment - * and ack. - */ - if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { - tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_rcvwinprobe++; - } else - goto dropafterack; - } else - tcpstat.tcps_rcvbyteafterwin += todrop; - m_adj(m, -todrop); - ti->ti_len -= todrop; - tiflags &= ~(TH_PUSH|TH_FIN); - } - - /* - * If last ACK falls within this segment's sequence numbers, - * record its timestamp. - * Fix from Braden, see Stevens p. 870 - */ - if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && - SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + ((tiflags & (TH_SYN | TH_FIN)) != 0))) { - tp->ts_recent_age = tcp_now; - tp->ts_recent = ts_val; - } - - /* - * If the RST bit is set examine the state: - * SYN_RECEIVED STATE: - * If passive open, return to LISTEN state. - * If active open, inform user that connection was refused. - * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: - * Inform user that connection was reset, and close tcb. - * CLOSING, LAST_ACK, TIME_WAIT STATES - * Close the tcb. - */ - if (tiflags & TH_RST) { - switch (tp->t_state) { - case TCPS_SYN_RECEIVED: - so->so_error = ECONNREFUSED; - goto close; - - case TCPS_ESTABLISHED: - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - case TCPS_CLOSE_WAIT: - so->so_error = ECONNRESET; -close: - tp->t_state = TCPS_CLOSED; - tcpstat.tcps_drops++; - tp = tcp_close(tp); - goto drop; - - case TCPS_CLOSING: - case TCPS_LAST_ACK: - case TCPS_TIME_WAIT: - tp = tcp_close(tp); - goto drop; - } - } - - /* - * If a SYN is in the window, then this is an - * error and we send an RST and drop the connection. - */ - if (tiflags & TH_SYN) { - tp = tcp_drop(tp, ECONNRESET); - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - - /* - * If the ACK bit is off we drop the segment and return. - */ - if ((tiflags & TH_ACK) == 0) { - printf("tcp_input: drop: no ack flag...\n"); - goto drop; - } - - /* - * Ack processing. - */ - switch (tp->t_state) { - - /* - * In SYN_RECEIVED state, the ack ACKs our SYN, so enter - * ESTABLISHED state and continue processing. - * The ACK was checked above. - */ - case TCPS_SYN_RECEIVED: - if (SEQ_GT(tp->snd_una, ti->ti_ack) || - SEQ_GT(ti->ti_ack, tp->snd_max)) { - printf("tcp_input: dropwithreset: line %d\n", __LINE__); - goto dropwithreset; - } - tcpstat.tcps_connects++; - socket_set_connected(so); - tp->t_state = TCPS_ESTABLISHED; - /* Do window scaling? */ - if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == - (TF_RCVD_SCALE|TF_REQ_SCALE)) { - tp->snd_scale = tp->requested_s_scale; - tp->rcv_scale = tp->request_r_scale; - } - (void) tcp_reass(tp, NULL, NULL); - tp->snd_wl1 = ti->ti_seq - 1; - /* fall into ... */ - - /* - * In ESTABLISHED state: drop duplicate ACKs; ACK out of range - * ACKs. If the ack is in the range - * tp->snd_una < th->th_ack <= tp->snd_max - * then advance tp->snd_una to th->th_ack and drop - * data from the retransmission queue. If this ACK reflects - * more up to date window information we update our window information. - */ - case TCPS_ESTABLISHED: - case TCPS_FIN_WAIT_1: - case TCPS_FIN_WAIT_2: - case TCPS_CLOSE_WAIT: - case TCPS_CLOSING: - case TCPS_LAST_ACK: - case TCPS_TIME_WAIT: - if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { - if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { - tcpstat.tcps_rcvdupack++; - /* - * If we have outstanding data (other than - * a window probe), this is a completely - * duplicate ack (ie, window info didn't - * change), the ack is the biggest we've - * seen and we've seen exactly our rexmt - * threshhold of them, assume a packet - * has been dropped and retransmit it. - * Kludge snd_nxt & the congestion - * window so we send only this one - * packet. - * - * We know we're losing at the current - * window size so do congestion avoidance - * (set ssthresh to half the current window - * and pull our congestion window back to - * the new ssthresh). - * - * Dup acks mean that packets have left the - * network (they're now cached at the receiver) - * so bump cwnd by the amount in the receiver - * to keep a constant cwnd packets in the - * network. - */ - if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una) - tp->t_dupacks = 0; - else if (++tp->t_dupacks == tcprexmtthresh) { - tcp_seq onxt = tp->snd_nxt; - uint32 win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; - - if (win < 2) - win = 2; - tp->snd_ssthresh = win * tp->t_maxseg; - tp->t_timer[TCPT_REXMT] = 0; - tp->t_rtt = 0; - tp->snd_nxt = ti->ti_ack; - tp->snd_cwnd = tp->t_maxseg; - (void) tcp_output(tp); - tp->snd_cwnd = tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; - if (SEQ_GT(onxt, tp->snd_nxt)) - tp->snd_nxt = onxt; - goto drop; - } else if (tp->t_dupacks > tcprexmtthresh) { - tp->snd_cwnd += tp->t_maxseg; - (void) tcp_output(tp); - goto drop; - } - } else - tp->t_dupacks = 0; - break; - } - /* - * If the congestion window was inflated to account - * for the other side's cached packets, retract it. - */ - if (tp->t_dupacks >= tcprexmtthresh && - tp->snd_cwnd > tp->snd_ssthresh) - tp->snd_cwnd = tp->snd_ssthresh; - tp->t_dupacks = 0; - - if (SEQ_GT(ti->ti_ack, tp->snd_max)) { - tcpstat.tcps_rcvacktoomuch++; - goto dropafterack; - } - acked = ti->ti_ack - tp->snd_una; - tcpstat.tcps_rcvackpack++; - tcpstat.tcps_rcvackbyte += acked; - - /* - * If we have a timestamp reply, update smoothed - * round trip time. If no timestamp is present but - * transmit timer is running and timed sequence - * number was acked, update smoothed round trip time. - * Since we now have an rtt measurement, cancel the - * timer backoff (cf., Phil Karn's retransmit alg.). - * Recompute the initial retransmit timer. - */ - if (ts_present) - tcp_xmit_timer(tp, tcp_now - ts_ecr + 1); - else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) - tcp_xmit_timer(tp,tp->t_rtt); - - /* - * If all outstanding data is acked, stop retransmit - * timer and remember to restart (more output or persist). - * If there is more data to be acked, restart retransmit - * timer, using current (possibly backed-off) value. - */ - if (ti->ti_ack == tp->snd_max) { - tp->t_timer[TCPT_REXMT] = 0; - needoutput = 1; - } else if (tp->t_timer[TCPT_PERSIST] == 0) - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - /* - * When new data is acked, open the congestion window. - * If the window gives us less than ssthresh packets - * in flight, open exponentially (maxseg per packet). - * Otherwise open linearly: maxseg per window - * (maxseg^2 / cwnd per packet). - */ - { - uint cw = tp->snd_cwnd; - uint incr = tp->t_maxseg; - - if (cw > tp->snd_ssthresh) - incr = incr * incr / cw + incr / 8; - tp->snd_cwnd = min((int) (cw + incr), TCP_MAXWIN << tp->snd_scale); - } - if (acked > so->so_snd.sb_cc) { - tp->snd_wnd -= so->so_snd.sb_cc; - sockbuf_drop(&so->so_snd, (int)so->so_snd.sb_cc); - ourfinisacked = 1; - } else { - sockbuf_drop(&so->so_snd, acked); - tp->snd_wnd -= acked; - ourfinisacked = 0; - } - if (so->so_snd.sb_flags & SB_NOTIFY) - sowwakeup(so); - tp->snd_una = ti->ti_ack; - if (SEQ_LT(tp->snd_nxt, tp->snd_una)) - tp->snd_nxt = tp->snd_una; - - switch (tp->t_state) { - - /* - * In FIN_WAIT_1 STATE in addition to the processing - * for the ESTABLISHED state if our FIN is now acknowledged - * then enter FIN_WAIT_2. - */ - case TCPS_FIN_WAIT_1: - if (ourfinisacked) { - /* - * If we can't receive any more - * data, then closing user can proceed. - * Starting the timer is contrary to the - * specification, but if we don't get a FIN - * we'll hang forever. - */ - if (so->so_state & SS_CANTRCVMORE) { - socket_set_disconnected(so); - tp->t_timer[TCPT_2MSL] = tcp_maxidle; - } - tp->t_state = TCPS_FIN_WAIT_2; - } - break; - - /* - * In CLOSING STATE in addition to the processing for - * the ESTABLISHED state if the ACK acknowledges our FIN - * then enter the TIME-WAIT state, otherwise ignore - * the segment. - */ - case TCPS_CLOSING: - if (ourfinisacked) { - tp->t_state = TCPS_TIME_WAIT; - tcp_canceltimers(tp); - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - socket_set_disconnected(so); - } - break; - - /* - * In LAST_ACK, we may still be waiting for data to drain - * and/or to be acked, as well as for the ack of our FIN. - * If our FIN is now acknowledged, delete the TCB, - * enter the closed state and return. - */ - case TCPS_LAST_ACK: - if (ourfinisacked) { - tp = tcp_close(tp); - goto drop; - } - break; - - /* - * In TIME_WAIT state the only thing that should arrive - * is a retransmission of the remote FIN. Acknowledge - * it and restart the finack timer. - */ - case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - goto dropafterack; - } - } - -step6: - /* - * Update window information. - * Don't look at window if no ACK: TAC's send garbage on first SYN. - */ - if ((tiflags & TH_ACK) && - (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq) && - (SEQ_LT(tp->snd_wl2, ti->ti_ack) || - (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))) { - /* keep track of pure window updates */ - if (ti->ti_len == 0 && - tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) - tcpstat.tcps_rcvwinupd++; - tp->snd_wnd = tiwin; - tp->snd_wl1 = ti->ti_seq; - tp->snd_wl2 = ti->ti_ack; - if (tp->snd_wnd > tp->max_sndwnd) - tp->max_sndwnd = tp->snd_wnd; - needoutput = 1; - } - /* - * Process segments with URG. - */ - if ((tiflags & TH_URG) && ti->ti_urp && - TCPS_HAVERCVDFIN(tp->t_state) == 0) { - /* - * This is a kludge, but if we receive and accept - * random urgent pointers, we'll crash in - * soreceive. It's hard to imagine someone - * actually wanting to send this much urgent data. - */ - if (ti->ti_urp + so->so_rcv.sb_cc > (int) sb_max) { - ti->ti_urp = 0; /* XXX */ - tiflags &= ~TH_URG; /* XXX */ - goto dodata; /* XXX */ - } - /* - * If this segment advances the known urgent pointer, - * then mark the data stream. This should not happen - * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since - * a FIN has been received from the remote side. - * In these states we ignore the URG. - * - * According to RFC961 (Assigned Protocols), - * the urgent pointer points to the last octet - * of urgent data. We continue, however, - * to consider it to indicate the first octet - * of data past the urgent section as the original - * spec states (in one of two places). - */ - if (SEQ_GT(ti->ti_seq + ti->ti_urp, tp->rcv_up)) { - tp->rcv_up = ti->ti_seq + ti->ti_urp; - so->so_oobmark = so->so_rcv.sb_cc + - (tp->rcv_up - tp->rcv_nxt) - 1; - if (so->so_oobmark == 0) - so->so_state |= SS_RCVATMARK; - socket_set_hasoutofband(so); - tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); - } - /* - * Remove out of band data so doesn't get presented to user. - * This can happen independent of advancing the URG pointer, - * but if two URG's are pending at once, some out-of-band - * data may creep in... ick. - */ - if (ti->ti_urp <= ti->ti_len -#ifdef SO_OOBINLINE - && (so->so_options & SO_OOBINLINE) == 0 -#endif - ) - tcp_pulloutofband(so, ti, m); - } else { - /* - * If no out of band data is expected, - * pull receive urgent pointer along - * with the receive window. - */ - if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) - tp->rcv_up = tp->rcv_nxt; - } -dodata: /* XXX */ - - /* - * Process the segment text, merging it into the TCP sequencing queue, - * and arranging for acknowledgment of receipt if necessary. - * This process logically involves adjusting tp->rcv_wnd as data - * is presented to the user (this happens in tcp_usrreq.c, - * case PRU_RCVD). If a FIN has already been received on this - * connection then we just ignore the text. - */ - - if ((ti->ti_len || (tiflags & TH_FIN)) && - TCPS_HAVERCVDFIN(tp->t_state) == 0) { - TCP_REASS(tp, ti, m, so, tiflags); - len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); - } else { - m_freem(m); - tiflags &= ~TH_FIN; - } - - /* - * If FIN is received ACK the FIN and let the user know - * that the connection is closing. Ignore a FIN received before - * the connection is fully established. - */ - if ((tiflags & TH_FIN)) { - if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { - socket_set_cantrcvmore(so); - tp->t_flags |= TF_ACKNOW; - tp->rcv_nxt++; - } - switch (tp->t_state) { - /* - * In ESTABLISHED STATE enter the CLOSE_WAIT state. - */ - case TCPS_SYN_RECEIVED: - case TCPS_ESTABLISHED: - tp->t_state = TCPS_CLOSE_WAIT; - break; - - /* - * If still in FIN_WAIT_1 STATE FIN has not been acked so - * enter the CLOSING state. - */ - case TCPS_FIN_WAIT_1: - tp->t_state = TCPS_CLOSING; - break; - - /* - * In FIN_WAIT_2 state enter the TIME_WAIT state, - * starting the time-wait timer, turning off the other - * standard timers. - */ - case TCPS_FIN_WAIT_2: - tp->t_state = TCPS_TIME_WAIT; - tcp_canceltimers(tp); - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - socket_set_disconnected(so); - break; - - /* - * In TIME_WAIT state restart the 2 MSL time_wait timer. - */ - case TCPS_TIME_WAIT: - tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; - break; - } - } - - if (so->so_options & SO_DEBUG) { - tcp_trace(TA_INPUT, ostate, tp, (caddr_t) &tcp_saveti, - 0, tlen); - } - - /* - * Return any desired output. - */ - if (needoutput || (tp->t_flags & TF_ACKNOW)) { - (void) tcp_output(tp); - } - return; - -dropafterack: - /* - * Generate an ACK dropping incoming segment if it occupies - * sequence space, where the ACK reflects our state. - */ - if (tiflags & TH_RST) - goto drop; - m_freem(m); - tp->t_flags |= TF_ACKNOW; - (void) tcp_output(tp); - return; - -dropwithreset: - /* - * Generate a RST, dropping incoming segment. - * Make ACK acceptable to originator of segment. - * Don't bother to respond if destination was broadcast/multicast. - */ - if ((tiflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST) || - IN_MULTICAST(ti->ti_dst.s_addr)) - goto drop; - if (tiflags & TH_ACK) { - tcp_respond(tp, ti, m, 0, ti->ti_ack, TH_RST); - } else { - if (tiflags & TH_SYN) - ti->ti_len++; - tcp_respond(tp, ti, m, ti->ti_seq + ti->ti_len, 0, TH_RST|TH_ACK); - } - /* destroy temporarily created socket */ - if (dropsocket) - (*so->so_proto->pr_userreq)(so, PRU_ABORT, NULL, NULL, NULL); - return; - -drop: - /* - * Drop space held by incoming segment and return. - */ - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { - tcp_trace(TA_DROP, ostate, tp, (caddr_t) &tcp_saveti, - 0, tlen); - } - - m_freem(m); - /* destroy temporarily created socket */ - - if (dropsocket) - (*so->so_proto->pr_userreq)(so, PRU_ABORT, NULL, NULL, NULL); - return; -} - -void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti, - int *ts_present, uint32 *ts_val, uint32 *ts_ecr) -{ - uint16 mss = 0; - int opt, optlen; - - for (; cnt > 0; cnt -= optlen, cp += optlen) { - opt = cp[0]; - if (opt == TCPOPT_EOL) - break; - if (opt == TCPOPT_NOP) - optlen = 1; - else { - optlen = cp[1]; - if (optlen <= 0) - break; - } - switch (opt) { - case TCPOPT_MAXSEG: - if (optlen != TCPOLEN_MAXSEG) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - memcpy((char *) &mss, (char *) cp + 2,sizeof(mss)); - ntohs(mss); - break; - case TCPOPT_WINDOW: - if (optlen != TCPOLEN_WINDOW) - continue; - if (!(ti->ti_flags & TH_SYN)) - continue; - tp->t_flags |= TF_RCVD_SCALE; - tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); - break; - case TCPOPT_TIMESTAMP: - if (optlen != TCPOLEN_TIMESTAMP) - continue; - *ts_present = 1; - memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); - ntohl(*ts_val); - memcpy((char*)ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); - ntohl(*ts_ecr); - - /* - * A timestamp received in a SYN makes - * it ok to send timestamp requests and replies. - */ - if (ti->ti_flags & TH_SYN) { - tp->t_flags |= TF_RCVD_TSTMP; - tp->ts_recent = *ts_val; - tp->ts_recent_age = tcp_now; - } - break; - default: - continue; - } - } -} - -/* - * Pull out of band byte out of a segment so - * it doesn't appear in the user's data queue. - * It is still reflected in the segment length for - * sequencing purposes. - */ -void tcp_pulloutofband(struct socket *so, struct tcpiphdr *ti, struct mbuf *m) -{ - int cnt = ti->ti_urp - 1; - - while (cnt >= 0) { - if ((int) m->m_len > cnt) { - char *cp = mtod(m, caddr_t) + cnt; - struct tcpcb *tp = sototcpcb(so); - - tp->t_iobc = *cp; - tp->t_oobflags |= TCPOOB_HAVEDATA; - memcpy(cp, cp+1, (unsigned)(m->m_len - cnt - 1)); - m->m_len--; - return; - } - cnt -= m->m_len; - m = m->m_next; - if (m == NULL) - break; - } -} - -/* - * Collect new round-trip time estimate - * and update averages and current timeout. - */ -void tcp_xmit_timer(struct tcpcb *tp, int16 rtt) -{ - int16 delta; - int16 rttmin; - - tcpstat.tcps_rttupdated++; - --rtt; - if (tp->t_srtt != 0) { - /* - * srtt is stored as fixed point with 3 bits after the - * binary point (i.e., scaled by 8). The following magic - * is equivalent to the smoothing algorithm in rfc793 with - * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed - * point). Adjust rtt to origin 0. - */ - delta = (rtt << 2) - (tp->t_srtt >> TCP_RTT_SHIFT); - if ((tp->t_srtt += delta) <= 0) - tp->t_srtt = 1; - /* - * We accumulate a smoothed rtt variance (actually, a - * smoothed mean difference), then set the retransmit - * timer to smoothed rtt + 4 times the smoothed variance. - * rttvar is stored as fixed point with 2 bits after the - * binary point (scaled by 4). The following is - * equivalent to rfc793 smoothing with an alpha of .75 - * (rttvar = rttvar*3/4 + |delta| / 4). This replaces - * rfc793's wired-in beta. - */ - if (delta < 0) - delta = -delta; - delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); - if ((tp->t_rttvar += delta) <= 0) - tp->t_rttvar = 1; - } else { - /* - * No rtt measurement yet - use the unsmoothed rtt. - * Set the variance to half the rtt (so our first - * retransmit happens at 3*rtt). - */ - tp->t_srtt = rtt << (TCP_RTT_SHIFT + 2); - tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT + 2 - 1); - } - tp->t_rtt = 0; - tp->t_rxtshift = 0; - - /* - * the retransmit should happen at rtt + 4 * rttvar. - * Because of the way we do the smoothing, srtt and rttvar - * will each average +1/2 tick of bias. When we compute - * the retransmit timer, we want 1/2 tick of rounding and - * 1 extra tick because of +-1/2 tick uncertainty in the - * firing of the timer. The bias will give us exactly the - * 1.5 tick we need. But, because the bias is - * statistical, we have to test that we don't drop below - * the minimum feasible timer (which is 2 ticks). - */ - if (tp->t_rttmin > rtt + 2) - rttmin = tp->t_rttmin; - else - rttmin = rtt + 2; - TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), rttmin, TCPTV_REXMTMAX); - - /* - * We received an ack for a packet that wasn't retransmitted; - * it is probably safe to discard any error indications we've - * received recently. This isn't quite right, but close enough - * for now (a route might have failed after we sent a segment, - * and the return path might not be symmetrical). - */ - tp->t_softerror = 0; -} - -/* - * Set connection variables based on the effective MSS. - * We are passed the TCPCB for the actual connection. If we - * are the server, we are called by the compressed state engine - * when the 3-way handshake is complete. If we are the client, - * we are called when we receive the SYN,ACK from the server. - * - * NOTE: The t_maxseg value must be initialized in the TCPCB - * before this routine is called! - */ -void tcp_mss_update(struct tcpcb *tp) -{ - int mss, rtt; - u_long bufsize; - struct rtentry *rt; - struct socket *so; - - so = tp->t_inpcb->inp_socket; - mss = tp->t_maxseg; - - rt = in_pcbrtentry(tp->t_inpcb); - - if (rt == NULL) - return; - -#ifdef RTV_MTU /* if route characteristics exist ... */ - /* - * While we're here, check if there's an initial rtt - * or rttvar. Convert from the route-table units - * to scaled multiples of the slow timeout timer. - */ - if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { - /* - * XXX the lock bit for MTU indicates that the value - * is also a minimum value; this is subject to time. - */ - if (rt->rt_rmx.rmx_locks & RTV_RTT) - TCPT_RANGESET(tp->t_rttmin, - rtt / (RTM_RTTUNIT / PR_SLOWHZ), - TCPTV_MIN, TCPTV_REXMTMAX); - tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); - if (rt->rt_rmx.rmx_rttvar) - tp->t_rttvar = rt->rt_rmx.rmx_rttvar / - (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); - else - /* default variation is +- 1 rtt */ - tp->t_rttvar = - tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE; - TCPT_RANGESET(/*(long)*/tp->t_rxtcur, - ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, - tp->t_rttmin, TCPTV_REXMTMAX); - } -#endif - - /* - * If there's a pipesize, change the socket buffer - * to that size. Make the socket buffers an integral - * number of mss units; if the mss is larger than - * the socket buffer, decrease the mss. - */ -#ifdef RTV_SPIPE - if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0) -#endif - bufsize = so->so_snd.sb_hiwat; - if ((int) bufsize < mss) { - mss = bufsize; - /* Update t_maxseg and t_maxopd */ - tcp_mss(tp, mss); - } else { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - (void)sockbuf_reserve(&so->so_snd, bufsize); - } - -#ifdef RTV_RPIPE - if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0) -#endif - bufsize = so->so_rcv.sb_hiwat; - if ((int) bufsize > mss) { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - (void)sockbuf_reserve(&so->so_rcv, bufsize); -#ifdef RTV_RPIPE - if (rt->rt_rmx.rmx_recvpipe > 0) { - tp->request_r_scale = 0; - while (tp->request_r_scale < TCP_MAX_WINSHIFT && - TCP_MAXWIN << tp->request_r_scale < - so->so_rcv.sb_hiwat) - tp->request_r_scale++; - } -#endif - } - -#ifdef RTV_SSTHRESH - if (rt->rt_rmx.rmx_ssthresh) { - /* - * There's some sort of gateway or interface - * buffer limit on the path. Use this to set - * the slow start threshhold, but set the - * threshold to no less than 2*mss. - */ - tp->snd_ssthresh = max(2 * mss, (int) rt->rt_rmx.rmx_ssthresh); - } -#endif /* RTV_MTU */ -} diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp_output.c b/src/add-ons/kernel/network/protocols/tcp/tcp_output.c deleted file mode 100644 index f80da2f430..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/tcp_output.c +++ /dev/null @@ -1,454 +0,0 @@ -/* tcp_output.c */ - -#ifndef _KERNEL_MODE -#include -#endif - -#include "sys/socketvar.h" -#include "sys/protosw.h" -#include "netinet/in.h" -#include "netinet/in_pcb.h" -#include "netinet/ip_var.h" -#include "netinet/tcp.h" -#include "netinet/tcp_timer.h" -#include "netinet/tcp_var.h" -#include "netinet/tcpip.h" -#include "netinet/tcp_seq.h" -#define TCPOUTFLAGS -#include "netinet/tcp_fsm.h" -#include "netinet/tcp_debug.h" - -#include "core_module.h" -#include "core_funcs.h" -#include "ipv4_module.h" - -#ifdef _KERNEL_MODE -#include - -#endif - -extern struct core_module_info *core; -extern struct ipv4_module_info *ipm; -extern struct pool_ctl *tcppool; - -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -extern uint32 sb_max; /* defined in socketvar.h */ - -void tcp_setpersist(struct tcpcb *tp) -{ - int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; - - if (tp->t_timer[TCPT_REXMT]) { - printf("PANIC: tcp_output REXMT\n"); - return; - } - /* Start/reset the persistance timer */ - TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], - t * tcp_backoff[tp->t_rxtshift], - TCPTV_PERSMIN, TCPTV_PERSMAX); - if (tp->t_rxtshift < TCP_MAXRXTSHIFT) - tp->t_rxtshift++; -} - -int tcp_mss(struct tcpcb *tp, uint offer) -{ - struct route *ro; - struct rtentry *rt; - struct ifnet *ifp; - int rtt, mss; - uint32 bufsize; - struct inpcb *inp; - struct socket *so; - - inp = tp->t_inpcb; - ro = &inp->inp_route; - - if ((rt = ro->ro_rt) == NULL) { - /* don't have a route, get one if we can */ - if (inp->faddr.s_addr != INADDR_ANY) { - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); - ro->ro_dst.sa_family = AF_INET; - ro->ro_dst.sa_len = sizeof(ro->ro_dst); - ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = inp->faddr; - rtalloc(ro); - } - if ((rt = ro->ro_rt) == NULL) - return tcp_mssdflt; - } - ifp=rt->rt_ifp; - so = inp->inp_socket; - - if (tp->t_srtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { - if (rt->rt_rmx.rmx_locks & RTV_RTT) - tp->t_rttmin = rtt / (RTM_RTTUNIT / PR_SLOWHZ); - tp->t_srtt = rtt / (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); - - if (rt->rt_rmx.rmx_rttvar) - tp->t_rttvar = rt->rt_rmx.rmx_rttvar / - (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); - else - tp->t_rttvar = tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE; - - TCPT_RANGESET(tp->t_rxtcur, - ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1, - tp->t_rttmin, TCPTV_REXMTMAX); - } - - if (rt->rt_rmx.rmx_mtu) - mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); - else { - mss = ifp->if_mtu - sizeof(struct tcpiphdr); -#if (MCLBYTES & (MCLBYTES - 1)) == 0 - if (mss > MCLBYTES) - mss &=~ (MCLBYTES - 1); -else - if (mss > MCLBYTES) - mss = mss / MCLBYTES * MCLBYTES; -#endif - if (!in_localaddr(inp->faddr)) - mss = min(mss, tcp_mssdflt); - } - - if (offer) - mss = min(mss, (int) offer); - - mss = max(mss, 32); - if (mss < tp->t_maxseg || offer != 0) { - if ((bufsize = rt->rt_rmx.rmx_sendpipe) == 0) - bufsize = so->so_snd.sb_hiwat; - if ((int) bufsize < mss) - mss = bufsize; - else { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - sockbuf_reserve(&so->so_snd, bufsize); - } - tp->t_maxseg = mss; - - if ((bufsize = rt->rt_rmx.rmx_recvpipe) == 0) - bufsize = so->so_rcv.sb_hiwat; - if ((int) bufsize > mss) { - bufsize = roundup(bufsize, mss); - if (bufsize > sb_max) - bufsize = sb_max; - sockbuf_reserve(&so->so_rcv, bufsize); - } - } - tp->snd_cwnd = mss; - if (rt->rt_rmx.rmx_ssthresh) { - tp->snd_ssthresh = max(2 * mss, (int) rt->rt_rmx.rmx_ssthresh); - } - return mss; -} - -void tcp_quench(struct inpcb *inp, int error) -{ - struct tcpcb *tp = intotcpcb(inp); - - if(tp) - tp->snd_cwnd = tp->t_maxseg; -} - -int tcp_output(struct tcpcb *tp) -{ - struct socket *so = tp->t_inpcb->inp_socket; - int32 len, win; - int off, flags, error = 0; - struct mbuf *m; - struct tcpiphdr *ti; - u_char opt[MAX_TCPOPTLEN]; - uint optlen, hdrlen; - int idle, sendalot; - - idle = (tp->snd_max == tp->snd_una); - - if (idle && tp->t_idle >= tp->t_rxtcur) - /* Basically have we been idle for a while? - * If so, slow start to get ack "clock" running again - */ - tp->snd_cwnd = tp->t_maxseg; - -again: - sendalot = 0; - - off = tp->snd_nxt - tp->snd_una; - win = min(tp->snd_wnd, tp->snd_cwnd); - - flags = tcp_outflags[tp->t_state]; - /* if we're in a persist window of 0, send 1 byte - * Otherwise, if we have a small but nonzero window and - * the timer has expired, send what we can and go to - * transmit state - */ - if (tp->t_force) { - if (win == 0) { - /* If we have data to send, clear the FIN bit. - */ - if (off < so->so_snd.sb_cc) - flags &= ~TH_FIN; - win = 1; - } else { - tp->t_timer[TCPT_PERSIST] = 0; - tp->t_rxtshift = 0; - } - } - len = min(so->so_snd.sb_cc, win) - off; - if (len < 0) { - /* if FIN has been sent but not ack'd, - * but we haven't been asked to retransmit, len would be -1 - * Otherwise window shrank after we sent into it. If window - * shrank to 0, cancel pending transmit and pull snd_nxt - * back to (closed) window. - */ - len = 0; - if (win == 0) { - tp->t_timer[TCPT_REXMT] = 0; - tp->snd_nxt = tp->snd_una; - } - } - if (len > tp->t_maxseg) { - len = tp->t_maxseg; - sendalot = 1; - } - if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) - flags &= ~TH_FIN; - - win = sbspace(&so->so_rcv); - - /* Do we have a reason to send anything? */ - if (len) { - if (len == tp->t_maxseg) - goto send; - if ((idle || tp->t_flags & TF_NODELAY) && - len + off >= so->so_snd.sb_cc) - goto send; - if (tp->t_force) - goto send; - if (len >= (int) tp->max_sndwnd / 2) - goto send; - if (SEQ_LT(tp->snd_nxt, tp->snd_max)) - goto send; - } - if (win > 0) { - int32 adv = min(win, (int32)TCP_MAXWIN << tp->rcv_scale) - - (tp->rcv_adv - tp->rcv_nxt); - if (adv >= (int32)(2 * tp->t_maxseg)) - goto send; - if (2 * adv >= (int32) so->so_rcv.sb_hiwat) - goto send; - } - if (tp->t_flags & TF_ACKNOW) - goto send; - if (flags & (TH_SYN | TH_RST)) - goto send; - if (SEQ_GT(tp->snd_up, tp->snd_una)) - goto send; - if ((flags & TH_FIN) && ((tp->t_flags & TF_SENTFIN) == 0 || - tp->snd_nxt == tp->snd_una)) - goto send; - if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && - (tp->t_timer[TCPT_PERSIST] == 0)) { - tp->t_rxtshift = 0; - tcp_setpersist(tp); - } - - /* We don't have a reason to send anything for this connection, - * so just return. - */ - return 0; -send: - - optlen = 0; - hdrlen = sizeof(struct tcpiphdr); - if (flags & TH_SYN) { - tp->snd_nxt = tp->iss; - if ((tp->t_flags & TF_NOOPT) == 0) { - uint16 mss; - - opt[0] = TCPOPT_MAXSEG; - opt[1] = 4; - mss = htons((uint16)tcp_mss(tp, 0)); - memcpy((caddr_t)opt + 2, &mss, sizeof(mss)); - optlen = 4; - if ((tp->t_flags & TF_REQ_SCALE) && - ((flags & TH_ACK) == 0 || - (tp->t_flags & TF_RCVD_SCALE))) { - *((uint32*)(opt + optlen)) = htonl (TCPOPT_NOP << 24 | - TCPOPT_WINDOW << 16 | - TCPOLEN_WINDOW << 8 | - tp->request_r_scale); - optlen += 4; - } - } - } - if ((tp->t_flags & (TF_REQ_TSTMP | TF_NOOPT)) == TF_REQ_TSTMP && - (flags & TH_RST) == 0 && - ((flags & (TH_SYN | TH_ACK)) == TH_SYN || - (tp->t_flags & TF_RCVD_TSTMP))) { - uint32 *lp = (uint32*)(opt + optlen); - *lp++ = htonl(TCPOPT_TSTAMP_HDR); - *lp++ = htonl(tcp_now); - *lp = htonl(tp->ts_recent); - optlen += TCPOLEN_TSTAMP_APPA; - } - hdrlen += optlen; - - if (len > (int) (tp->t_maxseg - optlen)) { - len = tp->t_maxseg - optlen; - sendalot = 1; - } - - if (len) { - if (tp->t_force && len == 1) - tcpstat.tcps_sndprobe++; - else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { - tcpstat.tcps_sndrexmitpack++; - tcpstat.tcps_sndrexmitbyte += len; - } else { - tcpstat.tcps_sndpack++; - tcpstat.tcps_sndbyte += len; - } - m = m_gethdr(MT_HEADER); - if (m == NULL) { - printf("tcp_output: ENOBUFS\n"); - error = ENOBUFS; - goto out; - } - m->m_data += get_max_linkhdr(); - m->m_len = hdrlen; - if (len <= (int) (MHLEN - hdrlen - get_max_linkhdr())) { - m_copydata(so->so_snd.sb_mb, off, (int)len, mtod(m, caddr_t) + hdrlen); - m->m_len += len; - } else { - m->m_next = m_copym(so->so_snd.sb_mb, off, (int)len); - if (m->m_next == NULL) - len = 0; - } - if (off + len == so->so_snd.sb_cc) - flags |= TH_PUSH; - } else { - if (tp->t_flags & TF_ACKNOW) - tcpstat.tcps_sndacks++; - else if (flags & (TH_SYN | TH_FIN | TH_RST)) - tcpstat.tcps_sndctrl++; - else if (SEQ_GT(tp->snd_up, tp->snd_una)) - tcpstat.tcps_sndurg++; - else - tcpstat.tcps_sndwinup++; - - m = m_gethdr(MT_HEADER); - if (m == NULL) { - printf("tcp_output: ENOBUFS\n"); - error = ENOBUFS; - goto out; - } - m->m_data += get_max_linkhdr(); - m->m_len = hdrlen; - } - m->m_pkthdr.rcvif = NULL; - ti = mtod(m, struct tcpiphdr*); - if (tp->t_template == NULL) - printf("tcp_output: PANIC t_template == NULL\n"); - memcpy((caddr_t)ti, (caddr_t)tp->t_template, sizeof(struct tcpiphdr)); - - if (flags & TH_FIN && (tp->t_flags & TF_SENTFIN) && - (tp->snd_nxt == tp->snd_max)) - tp->snd_nxt--; - - if (len || (flags & (TH_SYN | TH_FIN)) || tp->t_timer[TCPT_PERSIST]) - ti->ti_seq = htonl(tp->snd_nxt); - else - ti->ti_seq = htonl(tp->snd_max); - - ti->ti_ack = htonl(tp->rcv_nxt); - - if (optlen) { - memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen); - ti->ti_off = (sizeof(struct tcphdr) + optlen) >> 2; - } - ti->ti_flags = flags; - - if (win < (int32)(so->so_rcv.sb_hiwat / 4) && - win < (int32) tp->t_maxseg) - win = 0; - if (win > (int32) TCP_MAXWIN << tp->rcv_scale) - win = (int32) TCP_MAXWIN << tp->rcv_scale; - if (win < (int32)(tp->rcv_adv - tp->rcv_nxt)) - win = (int32)(tp->rcv_adv - tp->rcv_nxt); - ti->ti_win = htons((uint16)(win >> tp->rcv_scale)); - - if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { - ti->ti_urp = htons((uint16)(tp->snd_up - tp->snd_nxt)); - ti->ti_flags |= TH_URG; - } else - tp->snd_up = tp->snd_una; - - if (len + optlen) - ti->ti_len = htons((uint16)(sizeof(struct tcphdr) + optlen + len)); - ti->ti_sum = in_cksum(m, (int)(hdrlen+len), 0); - - if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { - tcp_seq startseq = tp->snd_nxt; - - if (flags & (TH_SYN | TH_FIN)) { - tp->snd_nxt++; - if (flags & TH_FIN) - tp->t_flags |= TF_SENTFIN; - } - tp->snd_nxt += len; - if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { - tp->snd_max = tp->snd_nxt; - if (tp->t_rtt == 0) { - tp->t_rtt = 1; - tp->t_rtseq = startseq; - tcpstat.tcps_segstimed++; - } - } - if (tp->t_timer[TCPT_REXMT] == 0 && - tp->snd_nxt != tp->snd_una) { - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - if (tp->t_timer[TCPT_PERSIST]) { - tp->t_timer[TCPT_PERSIST] = 0; - tp->t_rxtshift = 0; - } - } - } else if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) - tp->snd_max = tp->snd_nxt + len; - - if (so->so_options & SO_DEBUG) - tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0, len); - - m->m_pkthdr.len = hdrlen + len; - ((struct ip*)ti)->ip_len = m->m_pkthdr.len; - ((struct ip*)ti)->ip_ttl = tp->t_inpcb->inp_ip.ip_ttl; - ((struct ip*)ti)->ip_tos = tp->t_inpcb->inp_ip.ip_tos; - error = ipm->output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, - so->so_options & SO_DONTROUTE, NULL); - - if (error) { -out: - if (error == ENOBUFS) { - tcp_quench(tp->t_inpcb, 0); - return 0; - } - if ((error == EHOSTUNREACH || error == ENETDOWN) && - TCPS_HAVERCVDSYN(tp->t_state)) { - tp->t_softerror = error; - return 0; - } - return error; - } - - tcpstat.tcps_sndtotal++; - - if (win > 0 && SEQ_GT(tp->rcv_nxt + win, tp->rcv_adv)) - tp->rcv_adv = tp->rcv_nxt + win; - tp->last_ack_sent = tp->rcv_nxt; - tp->t_flags &= ~(TF_ACKNOW | TF_DELACK); - - if (sendalot) - goto again; - - return 0; -} diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp_timer.c b/src/add-ons/kernel/network/protocols/tcp/tcp_timer.c deleted file mode 100644 index 94bf4d02d3..0000000000 --- a/src/add-ons/kernel/network/protocols/tcp/tcp_timer.c +++ /dev/null @@ -1,185 +0,0 @@ -/* tcp_timer.c */ - -#ifndef _KERNEL_MODE -#include -#endif - -#include "sys/protosw.h" -#include "netinet/in_pcb.h" -#include "netinet/tcp.h" -#include "netinet/tcp_timer.h" -#include "netinet/tcp_var.h" -#include "netinet/tcp_seq.h" -#include "netinet/tcp_fsm.h" - -#include "core_module.h" -#include "core_funcs.h" - -#ifdef _KERNEL_MODE -#include -#endif - -extern struct core_module_info *core; - -char *tcptimers[] = - { "REXMT", "PERSIST", "KEEP", "2MSL" }; - -int tcp_backoff[TCP_MAXRXTSHIFT + 1] = - { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; - -int tcp_totbackoff = 511; /* sum of tcp_backoff[] */ - -int tcp_keepidle = TCPTV_KEEP_IDLE; -int tcp_keepintvl = TCPTV_KEEPINTVL; -int tcp_maxpersistidle = TCPTV_KEEP_IDLE; /* max idle time in persist */ -int tcp_maxidle; - -void tcp_canceltimers(struct tcpcb *tp) -{ - int i; - - for (i=0; i < TCPT_NTIMERS; i++) - tp->t_timer[i] = 0; -} - -struct tcpcb * tcp_timers(struct tcpcb *tp, int timer) -{ - int rexmt; - - switch (timer) { - /* TCPT_2MSL is used for - * FIN_WAIT2 timer - * TIME_WAIT - */ - case TCPT_2MSL: - if (tp->t_state != TCPS_TIME_WAIT && - tp->t_idle <= tcp_maxidle) - tp->t_timer[TCPT_2MSL] = tcp_keepintvl; - else - tp = tcp_close(tp); - break; - /* TCPT_PERSIST is used to wait for being told it can send - * data. The window ahs been set to 0, so no data can be - * sent, but there's data waiting to be sent. when the timer - * expires we'll force a byte to be sent (despite the window - * being 0) and reset the time... - */ - case TCPT_PERSIST: - tcpstat.tcps_persisttimeo++; - tcp_setpersist(tp); - tp->t_force = 1; - tcp_output(tp); - tp->t_force = 0; - break; - /* TCPT_KEEP is used for - * send data - * drop connection if too long idle - */ - case TCPT_KEEP: - tcpstat.tcps_keeptimeo++; - if (tp->t_state < TCPS_ESTABLISHED) - goto dropit; - if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE && - tp->t_state <= TCPS_CLOSE_WAIT) { - if (tp->t_idle >= tcp_keepidle + tcp_maxidle) - goto dropit; - tcpstat.tcps_keepprobe++; - tcp_respond(tp, tp->t_template, NULL, tp->rcv_nxt, - tp->snd_una - 1, 0); - tp->t_timer[TCPT_KEEP] = tcp_keepintvl; - } else - tp->t_timer[TCPT_KEEP] = tcp_keepidle; - break; -dropit: - tcpstat.tcps_keepdrops++; - tp = tcp_drop(tp, ETIMEDOUT); - break; - /* TCPT_REXMT is the transmission timer */ - case TCPT_REXMT: - if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { - tp->t_rxtshift = TCP_MAXRXTSHIFT; - tcpstat.tcps_timeoutdrop++; - tp = tcp_drop(tp, tp->t_softerror ? tp->t_softerror : ETIMEDOUT); - break; - } - tcpstat.tcps_rexmttimeo++; - rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; - TCPT_RANGESET(tp->t_rxtcur, rexmt, tp->t_rttmin, TCPTV_REXMTMAX); - tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; - if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { - in_losing(tp->t_inpcb); - tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); - tp->t_srtt = 0; - } - tp->snd_nxt = tp->snd_una; - tp->t_rtt = 0; - { - uint win = min(tp->snd_wnd, tp->snd_cwnd) / 2/ tp->t_maxseg; - if (win < 2) - win = 2; - tp->snd_cwnd = tp->t_maxseg; - tp->snd_ssthresh = win * tp->t_maxseg; - tp->t_dupacks = 0; - } - tcp_output(tp); - break; - } - return (tp); -} - -void tcp_slowtimer(void *data) -{ - struct inpcb *ip, *ipnxt; - struct tcpcb *tp; - int i; - - tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; - - ip = tcb.inp_next; - if (!ip) - return; - for (; ip != &tcb; ip = ipnxt) { - ipnxt = ip->inp_next; - tp = intotcpcb(ip); - if (!tp) - continue; - for (i=0;i < TCPT_NTIMERS;i++) { - if (tp->t_timer[i] && --tp->t_timer[i] == 0) { - tcp_userreq(tp->t_inpcb->inp_socket, PRU_SLOWTIMO, NULL, - (struct mbuf *)i, NULL); - if (ipnxt->inp_prev != ip) - goto tpgone; - } - } - tp->t_idle++; - if (tp->t_rtt) - tp->t_rtt++; -tpgone: - ; /* mwcc wants a ; here, so it gets one */ - } - tcp_iss += TCP_ISSINCR / PR_SLOWHZ; - tcp_now++; - - return; -} - -void tcp_fasttimer(void *data) -{ - struct inpcb *inp; - struct tcpcb *tp; - - inp = tcb.inp_next; - if (inp) { - for (; inp != &tcb; inp = inp->inp_next) { - if ((tp = (struct tcpcb*)inp->inp_ppcb) && - (tp->t_flags & TF_DELACK)) { - tp->t_flags &= ~TF_DELACK; - tp->t_flags |= TF_ACKNOW; - tcpstat.tcps_delack++; - tcp_output(tp); - } - } - } - - return; -} diff --git a/src/add-ons/kernel/network/protocols/udp/Jamfile b/src/add-ons/kernel/network/protocols/udp/Jamfile deleted file mode 100644 index cebb310aa2..0000000000 --- a/src/add-ons/kernel/network/protocols/udp/Jamfile +++ /dev/null @@ -1,24 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network protocols udp ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders net ; - -KernelAddon udp : kernel obos_network protocols : - udp.c -; - -# Installation -HaikuInstall install-networking - : /boot/home/config/add-ons/kernel/obos_network/protocols - : udp ; - -Package haiku-networkingkit-cvs : - udp : - boot home config add-ons kernel obos_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/udp/udp.c b/src/add-ons/kernel/network/protocols/udp/udp.c deleted file mode 100644 index 0d6d04148e..0000000000 --- a/src/add-ons/kernel/network/protocols/udp/udp.c +++ /dev/null @@ -1,425 +0,0 @@ -/* udp.c - */ - -#ifndef _KERNEL_MODE -#include -#endif - -#include -#include "net_misc.h" -#include "protocols.h" -#include -#include -#include -#include -#include "sys/domain.h" -#include "sys/protosw.h" -#include -#include -#include -#include - -#include "core_module.h" -#include "net_module.h" -#include "core_funcs.h" -#include "icmp_module.h" - -#include -status_t std_ops(int32 op, ...); -#define NET_UDP_MODULE_NAME NETWORK_MODULES_ROOT "protocols/udp" - -/* Private variables */ -static struct core_module_info *core = NULL; -static struct protosw *proto[IPPROTO_MAX]; -static struct inpcb udb; /* head of the UDP PCB list! */ -static int udpcksum = 1; /* do we calculate the UDP checksum? */ -static struct udpstat udpstat; -static uint32 udp_sendspace; /* size of send buffer */ -static uint32 udp_recvspace; /* size of recieve buffer */ -static struct icmp_module_info *icmp = NULL; - -static struct in_addr zeroin_addr = {0}; - -/* Private but used globally, need to make thread safe... tls??? */ -static struct inpcb *udp_last_inpcb = NULL; -static struct sockaddr_in udp_in; - -#if SHOW_DEBUG -static void dump_udp(struct mbuf *buf) -{ - struct ip *ip = mtod(buf, struct ip*); - struct udphdr *udp = (struct udphdr*)((caddr_t)ip + (ip->ip_hl * 4)); - - printf("udp_header :\n"); - printf(" : src_port : %d\n", ntohs(udp->uh_sport)); - printf(" : dst_port : %d\n", ntohs(udp->uh_dport)); - printf(" : udp length : %d bytes\n", ntohs(udp->uh_ulen)); - printf(" : udp sum : %d\n", ntohs(udp->uh_sum)); -} -#endif /* SHOW_DEBUG */ - -static int udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr, - struct mbuf *control) -{ - struct udpiphdr *ui; - uint16 len = m->m_pkthdr.len; - uint16 hdrlen = len + (uint16)sizeof(struct udpiphdr); - struct in_addr laddr; - int error = 0; - - if (control) - m_freem(control); - - if (addr) { - laddr = inp->laddr; - if (inp->faddr.s_addr != INADDR_ANY) { - error = EISCONN; - goto release; - } - error = in_pcbconnect(inp, addr); - if (error) - goto release; - - } else { - if (inp->faddr.s_addr == INADDR_ANY) { - error = ENOTCONN; - goto release; - } - } - - M_PREPEND(m, (int) sizeof(*ui)); - if (!m) { - error = ENOMEM; - goto release; - } - - ui = mtod(m, struct udpiphdr *); - ui->ui_next = ui->ui_prev = NULL; - ui->ui_x1 = 0; - ui->ui_pr = IPPROTO_UDP; - ui->ui_len = htons(len + sizeof(struct udphdr)); - ui->ui_src = inp->laddr; - ui->ui_dst = inp->faddr; - ui->ui_sport = inp->lport; - ui->ui_dport = inp->fport; - ui->ui_ulen = ui->ui_len; - ui->ui_sum = 0; - - if (udpcksum) - ui->ui_sum = in_cksum(m, hdrlen, 0); - - if (ui->ui_sum == 0) - ui->ui_sum = 0xffff; - - ((struct ip*)ui)->ip_len = hdrlen; - ((struct ip*)ui)->ip_ttl = 64; /* XXX - Fix this! */ - ((struct ip*)ui)->ip_tos = 0; /* XXX - Fix this! */ - - - /* XXX - add multicast options when available! */ - error = proto[IPPROTO_IP]->pr_output(m, - inp->inp_options, &inp->inp_route, - inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), - NULL /* inp->inp_moptions */ ); - - if (addr) { - in_pcbdisconnect(inp); /* remove temporary route */ - inp->laddr = laddr; - } - - return error; - -release: - m_freem(m); - return error; -} - -static int udp_userreq(struct socket *so, int req, - struct mbuf *m, struct mbuf *addr, struct mbuf *ctrl) -{ - struct inpcb *inp = sotoinpcb(so); - int error = 0; - - if (req == PRU_CONTROL) - return in_control(so, (int)m, (caddr_t)addr, (struct ifnet *)ctrl); - - if (inp == NULL && req != PRU_ATTACH) { - error = EINVAL; - goto release; - } - - switch (req) { - case PRU_ATTACH: - /* we don't replace an existing inpcb! */ - if (inp != NULL) { - error = EINVAL; - break; - } - error = in_pcballoc(so, &udb); /* udp head */ - if (error) - break; - error = soreserve(so, udp_sendspace, udp_recvspace); - if (error) - break; - /* XXX - this is a hack! This should be the default ip TTL */ - ((struct inpcb*) so->so_pcb)->inp_ip.ip_ttl = 64; - break; - case PRU_DETACH: - /* This should really be protected when in kernel... */ - if (inp == udp_last_inpcb) - udp_last_inpcb = &udb; - in_pcbdetach(inp); - break; - case PRU_BIND: - /* XXX - locking */ - error = in_pcbbind(inp, addr); - break; - case PRU_SEND: - /* we can use this as we're in the same module... */ - return udp_output(inp, m, addr, ctrl); - case PRU_LISTEN: - error = EINVAL;//EOPNOTSUPP; - break; - case PRU_CONNECT: - if (inp->faddr.s_addr != INADDR_ANY) { - error = EISCONN; - break; - } - error = in_pcbconnect(inp, addr); - if (error == 0) - socket_set_connected(so); - break; - case PRU_CONNECT2: - error = EINVAL;//EOPNOTSUPP; - break; - case PRU_ACCEPT: - error = EINVAL;//EOPNOTSUPP; - break; - case PRU_DISCONNECT: - if (inp->faddr.s_addr == INADDR_ANY) { - error = ENOTCONN; - break; - } - in_pcbdisconnect(inp); - inp->laddr.s_addr = INADDR_ANY; - so->so_state &= ~SS_ISCONNECTED; - break; - case PRU_SOCKADDR: - in_setsockaddr(inp, addr); - break; - case PRU_PEERADDR: - in_setpeeraddr(inp, addr); - break; - case PRU_SENSE: - /* will we ever see one of these???? */ - /* generated by an fstat on bsd... */ - return 0; - default: - printf("Unknown options passed to udp_userreq (%d)\n", req); - } - -release: - if (ctrl) { - printf("UDP control retained!\n"); - m_freem(ctrl); - } - if (m) - m_freem(m); - - return error; -} - -static void udp_input(struct mbuf *buf, int hdrlen) -{ - struct ip *ip = mtod(buf, struct ip*); - struct udphdr *udp = (struct udphdr*)((caddr_t)ip + hdrlen); - uint16 ck = 0; - int len; - struct ip saved_ip; - struct mbuf *opts = NULL; - struct inpcb *inp = NULL; - -#if SHOW_DEBUG - dump_udp(buf); -#endif - /* check and adjust sizes as required... */ - len = ntohs(udp->uh_ulen) + hdrlen; - saved_ip = *ip; - - if (udpcksum && udp->uh_sum) { - ((struct ipovly*)ip)->ih_next = ((struct ipovly*)ip)->ih_prev = NULL; - ((struct ipovly*)ip)->ih_x1 = 0; - ((struct ipovly*)ip)->ih_len = udp->uh_ulen; - /* XXX - if we have options we need to be careful when calculating the - * checksum here... - */ - if ((ck = in_cksum(buf, len, 0)) != 0) { - udpstat.udps_badsum++; - m_freem(buf); - printf("udp_input: UDP Checksum check failed. (%d over %ld bytes)\n", ck, len + sizeof(*ip)); - return; - } - } - inp = udp_last_inpcb; - - if (inp == NULL || - inp->lport != udp->uh_dport || - inp->fport != udp->uh_sport || - inp->faddr.s_addr != ip->ip_src.s_addr || - inp->laddr.s_addr != ip->ip_dst.s_addr) { - - inp = in_pcblookup(&udb, ip->ip_src, udp->uh_sport, - ip->ip_dst, udp->uh_dport, INPLOOKUP_WILDCARD); - if (inp) - udp_last_inpcb = inp; - } - if (!inp) { - atomic_add((vint32 *)&udpstat.udps_noport, 1); - if (buf->m_flags & (M_BCAST | M_MCAST)) { - atomic_add((vint32 *)&udpstat.udps_noportbcast, 1); - goto bad; - } - *ip = saved_ip; - ip->ip_len += hdrlen; - icmp->error(buf, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); - return; - } - - udp_in.sin_port = udp->uh_sport; - udp_in.sin_addr = ip->ip_src; - - if (inp->inp_flags & INP_CONTROLOPT) { - printf("INP Control Options to process!\n"); - /* XXX - add code to do this... */ - } - - hdrlen += sizeof(struct udphdr); - buf->m_len -= hdrlen; - buf->m_pkthdr.len -= hdrlen; - buf->m_data += hdrlen; - - if (sockbuf_appendaddr(&inp->inp_socket->so_rcv, (struct sockaddr*)&udp_in, - buf, opts) == 0) { - goto bad; - } - sorwakeup(inp->inp_socket); - return; - -bad: - if (opts) - m_freem(opts); - m_freem(buf); - return; -} - -static void udp_notify(struct inpcb *inp, int err) -{ - inp->inp_socket->so_error = err; - sorwakeup(inp->inp_socket); - sowwakeup(inp->inp_socket); -} - -static void udp_ctlinput(int cmd, struct sockaddr *sa, void *ipp) -{ - struct ip *ip = (struct ip*)ipp; - struct udphdr *uh; - - if (!PRC_IS_REDIRECT(cmd) && - ((uint)cmd >= PRC_NCMDS || inetctlerrmap(cmd) == 0)) - return; - if (ip) { - uh = (struct udphdr *)((char *) ip + (ip->ip_hl << 2)); - in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport, cmd, udp_notify); - } else - in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify); -} - -static void udp_init(void) -{ - udb.inp_prev = udb.inp_next = &udb; - udp_sendspace = 9216; /* default size */ - udp_recvspace = 41600; /* default size */ - udp_in.sin_family = AF_INET; - udp_in.sin_len = sizeof(udp_in); - memset(&udpstat, 0, sizeof(udpstat)); - - memset(proto, 0, sizeof(struct protosw *) * IPPROTO_MAX); - add_protosw(proto, NET_LAYER2); -} - -static struct protosw my_proto = { - "UDP Module", - NET_UDP_MODULE_NAME, - SOCK_DGRAM, - NULL, - IPPROTO_UDP, - PR_ATOMIC | PR_ADDR, - NET_LAYER3, - - &udp_init, - &udp_input, - NULL, /* pr_output */ - &udp_userreq, - NULL, /* pr_sysctl */ - &udp_ctlinput, - NULL, /* pr_ctloutput */ - - NULL, - NULL -}; - -static int udp_module_init(void *cpp) -{ - if (cpp) - core = cpp; - add_domain(NULL, AF_INET); - add_protocol(&my_proto, AF_INET); - - if (!icmp) - get_module(NET_ICMP_MODULE_NAME, (module_info **) &icmp); - - return 0; -} - -static int udp_module_stop(void) -{ - remove_protocol(&my_proto); - remove_domain(AF_INET); - return 0; -} - -struct kernel_net_module_info protocol_info = { - { - NET_UDP_MODULE_NAME, - 0, // B_KEEP_LOADED, // phoudoin: Why??? - std_ops - }, - udp_module_init, - udp_module_stop, - NULL -}; - -// #pragma mark - - -_EXPORT status_t std_ops(int32 op, ...) -{ - switch(op) { - case B_MODULE_INIT: - get_module(NET_CORE_MODULE_NAME, (module_info **) &core); - if (!core) - return B_ERROR; - return B_OK; - - case B_MODULE_UNINIT: - break; - - default: - return B_ERROR; - } - return B_OK; -} - -_EXPORT module_info *modules[] = { - (module_info *) &protocol_info, - NULL -}; diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 0e80c89667..001c4ad365 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -157,7 +157,7 @@ SubInclude HAIKU_TOP src bin less ; SubInclude HAIKU_TOP src bin listdev ; SubInclude HAIKU_TOP src bin make ; SubInclude HAIKU_TOP src bin makebootable ; -SubInclude HAIKU_TOP src bin makeudfimage ; +#SubInclude HAIKU_TOP src bin makeudfimage ; SubInclude HAIKU_TOP src bin mkdos ; SubInclude HAIKU_TOP src bin patch ; SubInclude HAIKU_TOP src bin pc ; @@ -175,13 +175,7 @@ SubInclude HAIKU_TOP src bin zic ; SubInclude HAIKU_TOP src bin rcs ; # Network command line tools -SubInclude HAIKU_TOP src bin arp ; -SubInclude HAIKU_TOP src bin ifconfig ; -SubInclude HAIKU_TOP src bin pppconfig ; -SubInclude HAIKU_TOP src bin ppp_up ; -SubInclude HAIKU_TOP src bin ping ; -SubInclude HAIKU_TOP src bin route ; -SubInclude HAIKU_TOP src bin traceroute ; +SubInclude HAIKU_TOP src bin network ; # Compression command line tools SubInclude HAIKU_TOP src bin unzip ; diff --git a/src/bin/arp/arp.c b/src/bin/arp/arp.c deleted file mode 100644 index 4a52d8decd..0000000000 --- a/src/bin/arp/arp.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Copyright (c) 1984, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Sun Microsystems, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * arp - display, set, and delete arp table entries - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -int delete (const char *, const char *); -void search(in_addr_t addr, void (*action)(struct sockaddr_dl *sdl, - struct sockaddr_inarp *sin, struct rt_msghdr *rtm)); -void print_entry(struct sockaddr_dl *sdl, - struct sockaddr_inarp *sin, struct rt_msghdr *rtm); -void nuke_entry(struct sockaddr_dl *sdl, - struct sockaddr_inarp *sin, struct rt_msghdr *rtm); -void ether_print __P((const u_char *)); -int file (char *); -int get (const char *); -int getinetaddr (const char *, struct in_addr *); -void getsocket (void); -int rtmsg (int); -int set (int, char **); -void usage (void); -void err(int error, char *msg); - -static int pid; -static int nflag; /* no reverse dns lookups */ -static int aflag; /* do it for all entries */ -static int s = -1; - -/* which function we're supposed to do */ -#define F_GET 1 -#define F_SET 2 -#define F_FILESET 3 -#define F_DELETE 4 - -void err(int error, char *msg) -{ - printf("Error: %s\n", msg); - printf("Code: %d\n", error); - printf("Desc: %s\n", strerror(error)); - exit(-1); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - int ch, func, rtn; - - pid = getpid(); - opterr = 0; - func = 0; - - while ((ch = getopt(argc, argv, "andsf")) != -1) { - switch ((char)ch) { - case 'a': - aflag = 1; - break; - case 'n': - nflag = 1; - break; - case 'd': - if (func) - usage(); - func = F_DELETE; - break; - case 's': - if (func) - usage(); - func = F_SET; - break; - case 'f': - if (func) - usage(); - func = F_FILESET; - break; - default: - usage(); - break; - } - } - argc -= optind; - argv += optind; - - if (!func) - func = F_GET; - rtn = 0; - - switch (func) { - case F_GET: - if (aflag && argc == 0) - search(0, print_entry); - else if (!aflag && argc == 1) - rtn = get(argv[0]); - else - usage(); - break; - case F_SET: - if (argc < 2 || argc > 5) - usage(); - rtn = set(argc, argv) ? 1 : 0; - break; - case F_DELETE: - if (aflag && argc == 0) - search(0, nuke_entry); - else if (!aflag && argc == 1) - rtn = delete(argv[0], argv[1]); - else - usage(); - break; - case F_FILESET: - if (argc != 1) - usage(); - rtn = file(argv[0]); - break; - } - return (rtn); -} - -/* - * Process a file to set standard arp entries - */ -int -file(name) - char *name; -{ - char line[100], arg[5][50], *args[5]; - int i, retval; - FILE *fp; - - if ((fp = fopen(name, "r")) == NULL) { - printf("cannot open %s", name); - exit(1); - } - args[0] = &arg[0][0]; - args[1] = &arg[1][0]; - args[2] = &arg[2][0]; - args[3] = &arg[3][0]; - args[4] = &arg[4][0]; - retval = 0; - while (fgets(line, 100, fp) != NULL) { - i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1], arg[2], - arg[3], arg[4]); - if (i < 2) { - printf("bad line: %s", line); - retval = 1; - continue; - } - if (set(i, args)) - retval = 1; - } - fclose(fp); - return (retval); -} - -void -getsocket() -{ - if (s >= 0) - return; - s = socket(PF_ROUTE, SOCK_RAW, 0); - if (s < 0) - err(1, "socket"); -} - -struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; -struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m; -struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; -int expire_time, flags, export_only, doing_proxy, found_entry; -struct { - struct rt_msghdr m_rtm; - char m_space[512]; -} m_rtmsg; - -/* - * Set an individual arp entry - */ -int -set(argc, argv) - int argc; - char **argv; -{ - register struct sockaddr_inarp *sin; - register struct sockaddr_dl *sdl; - register struct rt_msghdr *rtm; - u_char *eaddr; - struct ether_addr *ea; - char *host = argv[0]; - - sin = &sin_m; - rtm = &(m_rtmsg.m_rtm); - eaddr = argv[1]; - - getsocket(); - argc -= 2; - argv += 2; - sdl_m = blank_sdl; /* struct copy */ - sin_m = blank_sin; /* struct copy */ - if (getinetaddr(host, &sin->sin_addr) == -1) - return (1); - ea = ether_aton(eaddr); - if (ea == NULL) { - printf("invalid ethernet address: %s\n", eaddr); - exit(-1); - } - memcpy(LLADDR(&sdl_m), ea, sizeof(*ea)); - sdl_m.sdl_alen = 6; - doing_proxy = flags = export_only = expire_time = 0; - while (argc-- > 0) { - if (strncmp(argv[0], "temp", 4) == 0) { - struct timeval time; - (void)gettimeofday(&time, 0); - expire_time = time.tv_sec + 20 * 60; - if (flags & RTF_PERMANENT_ARP) { - /* temp or permanent, not both */ - usage(); - return (0); - } - } - else if (strncmp(argv[0], "pub", 3) == 0) { - flags |= RTF_ANNOUNCE; - doing_proxy = SIN_PROXY; - } - else if (strncmp(argv[0], "permanent", 9) == 0) { - flags |= RTF_PERMANENT_ARP; - if (expire_time != 0) { - /* temp or permanent, not both */ - usage(); - return (0); - } - } else if (strncmp(argv[0], "trail", 5) == 0) { - (void)printf( - "%s: Sending trailers is no longer supported\n", - host); - } - argv++; - } -tryagain: - if (rtmsg(RTM_GET) < 0) { - printf("%s\n", host); - return (1); - } - sin = (struct sockaddr_inarp *)(rtm + 1); - sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin); - if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { - if (sdl->sdl_family == AF_LINK && - (rtm->rtm_flags & RTF_LLINFO) && - !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { - case IFT_ETHER: -/* - case IFT_FDDI: - case IFT_ISO88023: - case IFT_ISO88024: - case IFT_ISO88025: -*/ - goto overwrite; - } - if (doing_proxy == 0) { - (void)printf("set: can only proxy for %s\n", host); - return (1); - } - if (sin_m.sin_other & SIN_PROXY) { - (void)printf( - "set: proxy entry exists for non 802 device\n"); - return (1); - } - sin_m.sin_other = SIN_PROXY; - export_only = 1; - goto tryagain; - } -overwrite: - if (sdl->sdl_family != AF_LINK) { - (void)printf("cannot intuit interface index and type for %s\n", - host); - return (1); - } - sdl_m.sdl_type = sdl->sdl_type; - sdl_m.sdl_index = sdl->sdl_index; - return (rtmsg(RTM_ADD)); -} - -/* - * Display an individual arp entry - */ -int -get(host) - const char *host; -{ - struct sockaddr_inarp *sin; - - sin = &sin_m; - sin_m = blank_sin; /* struct copy */ - if (getinetaddr(host, &sin->sin_addr) == -1) - exit(1); - search(sin->sin_addr.s_addr, print_entry); - if (found_entry == 0) { - (void)printf("%s (%s) -- no entry\n", host, - inet_ntoa(sin->sin_addr)); - return (1); - } - return (0); -} - -/* - * Delete an arp entry - */ -int -delete(host, info) - const char *host; - const char *info; -{ - register struct sockaddr_inarp *sin; - register struct rt_msghdr *rtm; - struct sockaddr_dl *sdl; - - sin = &sin_m; - rtm = &m_rtmsg.m_rtm; - - if (info && strncmp(info, "pro", 3) ) - export_only = 1; - getsocket(); - sin_m = blank_sin; /* struct copy */ - if (getinetaddr(host, &sin->sin_addr) == -1) - return (1); -tryagain: - if (rtmsg(RTM_GET) < 0) { - printf("%s\n", host); - return (1); - } - sin = (struct sockaddr_inarp *)(rtm + 1); - sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin); - if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { - if (sdl->sdl_family == AF_LINK && - (rtm->rtm_flags & RTF_LLINFO) && - !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { - case IFT_ETHER: -/* - case IFT_FDDI: - case IFT_ISO88023: - case IFT_ISO88024: - case IFT_ISO88025: -*/ - goto delete; - } - } - if (sin_m.sin_other & SIN_PROXY) { - printf("delete: can't locate %s\n", host); - return (1); - } else { - sin_m.sin_other = SIN_PROXY; - goto tryagain; - } -delete: - if (sdl->sdl_family != AF_LINK) { - (void)printf("cannot locate %s\n", host); - return (1); - } - if (rtmsg(RTM_DELETE)) - return (1); - (void)printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); - return (0); -} - -/* - * Search the entire arp table, and do some action on matching entries. - */ -void -search(addr, action) - in_addr_t addr; - void (*action)(struct sockaddr_dl *sdl, - struct sockaddr_inarp *sin, - struct rt_msghdr *rtm); -{ - int mib[6]; - size_t needed; - char *lim, *buf, *next; - struct rt_msghdr *rtm; - struct sockaddr_inarp *sin; - struct sockaddr_dl *sdl; - extern int h_errno; - - //mib[0] = CTL_NET; - mib[0] = PF_ROUTE; - mib[1] = 0; - mib[2] = AF_INET; - mib[3] = NET_RT_FLAGS; - mib[4] = RTF_LLINFO; - if (sysctl(mib, 5, NULL, &needed, NULL, 0) < 0) - err(1, "route-sysctl-estimate"); - if (needed == 0) - return; - if ((buf = malloc(needed)) == NULL) - err(1, "malloc"); - if (sysctl(mib, 5, buf, &needed, NULL, 0) < 0) - err(1, "actual retrieval of routing table"); - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - sin = (struct sockaddr_inarp *)(rtm + 1); - sdl = (struct sockaddr_dl *)(sin + 1); - if (addr) { - if (addr != sin->sin_addr.s_addr) - continue; - found_entry = 1; - } - (*action)(sdl, sin, rtm); - } -} - -/* - * Display an arp entry - */ -void -print_entry(sdl, sin, rtm) - struct sockaddr_dl *sdl; - struct sockaddr_inarp *sin; - struct rt_msghdr *rtm; -{ - char *host; - extern int h_errno; - struct hostent *hp; - - if (nflag == 0) - hp = gethostbyaddr((caddr_t)&(sin->sin_addr), - sizeof(sin->sin_addr), AF_INET); - else - hp = 0; - if (hp) - host = hp->h_name; - else { - host = "?"; - if (h_errno == TRY_AGAIN) - nflag = 1; - } - (void)printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); - if (sdl->sdl_alen) - ether_print(LLADDR(sdl)); - else - (void)printf("(incomplete)"); - if (rtm->rtm_flags & RTF_PERMANENT_ARP) - (void)printf(" permanent"); - if (rtm->rtm_rmx.rmx_expire == 0) - (void)printf(" static"); - if (sin->sin_other & SIN_PROXY) - (void)printf(" published (proxy only)"); - if (rtm->rtm_addrs & RTA_NETMASK) { - sin = (struct sockaddr_inarp *) - (sdl->sdl_len + (char *)sdl); - if (sin->sin_addr.s_addr == 0xffffffff) - (void)printf(" published"); - if (sin->sin_len != 8) - (void)printf("(weird)"); - } - printf("\n"); -} - -/* - * Nuke an arp entry - */ -void -nuke_entry(sdl, sin, rtm) - struct sockaddr_dl *sdl; - struct sockaddr_inarp *sin; - struct rt_msghdr *rtm; -{ - char ip[20]; - - strncpy(ip, inet_ntoa(sin->sin_addr), sizeof(ip)); - delete(ip, NULL); -} - -void -ether_print(cp) - const u_char *cp; -{ - (void)printf("%02x:%02x:%02x:%02x:%02x:%02x", - cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); -} - -void -usage() -{ - (void)fprintf(stderr, "usage: arp [-n] hostname\n"); - (void)fprintf(stderr, "usage: arp [-n] -a\n"); - (void)fprintf(stderr, "usage: arp -d hostname\n"); - (void)fprintf(stderr, "usage: arp -d -a\n"); - (void)fprintf(stderr, - "usage: arp -s hostname ether_addr [temp | permanent] [pub]\n"); - (void)fprintf(stderr, "usage: arp -f filename\n"); - exit(1); -} - -int -rtmsg(cmd) - int cmd; -{ - static int seq; - int rlen; - register struct rt_msghdr *rtm; - register char *cp; - register int l; - - rtm = &m_rtmsg.m_rtm; - cp = m_rtmsg.m_space; - errno = 0; - - if (cmd == RTM_DELETE) - goto doit; - (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); - rtm->rtm_flags = flags; - rtm->rtm_version = RTM_VERSION; - - switch (cmd) { - default: - printf("internal wrong cmd\n"); - exit(-1); - /*NOTREACHED*/ - case RTM_ADD: - rtm->rtm_addrs |= RTA_GATEWAY; - rtm->rtm_rmx.rmx_expire = expire_time; - rtm->rtm_inits = RTV_EXPIRE; - rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); - sin_m.sin_other = 0; - if (doing_proxy) { - if (export_only) - sin_m.sin_other = SIN_PROXY; - else { - rtm->rtm_addrs |= RTA_NETMASK; - rtm->rtm_flags &= ~RTF_HOST; - } - } - /* FALLTHROUGH */ - case RTM_GET: - rtm->rtm_addrs |= RTA_DST; - } -#define NEXTADDR(w, s) \ - if (rtm->rtm_addrs & (w)) { \ - (void)memcpy(cp, &s, sizeof(s)); cp += sizeof(s);} - - NEXTADDR(RTA_DST, sin_m); - NEXTADDR(RTA_GATEWAY, sdl_m); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm->rtm_msglen = cp - (char *)&m_rtmsg; -doit: - l = rtm->rtm_msglen; - rtm->rtm_seq = ++seq; - rtm->rtm_type = cmd; - if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { - if (errno != ESRCH || cmd != RTM_DELETE) { - printf("writing to routing socket\n"); - return (-1); - } - } - do { - l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); - } while (l > 0 && (rtm->rtm_seq != seq)); /* || rtm->rtm_pid != pid)); */ - if (l < 0) - printf("read from routing socket\n"); - return (0); -} - -int -getinetaddr(host, inap) - const char *host; - struct in_addr *inap; -{ - struct hostent *hp; - - if (inet_aton(host, inap) == 1) - return (0); - if ((hp = gethostbyname(host)) == NULL) { - /* should be hstrerror and h_errno */ - printf("%s: %s\n", host, strerror(errno)); - return (-1); - } - (void)memcpy(inap, hp->h_addr, sizeof(*inap)); - return (0); -} diff --git a/src/bin/ifconfig/ifconfig.c b/src/bin/ifconfig/ifconfig.c deleted file mode 100644 index ceb2e7b43f..0000000000 --- a/src/bin/ifconfig/ifconfig.c +++ /dev/null @@ -1,628 +0,0 @@ -/* ifconfig.c */ - -#include -#include -#include -#include /* for exit() */ -#include -#include - -#include "netinet/in.h" -#include "sys/socket.h" -#include "sys/sockio.h" -#include "arpa/inet.h" -#include "net/if.h" -#include "net/if_dl.h" - -#define version "0.2.1 pre-alpha" -#define NEXTARG 0xffffff - -/* globals */ -int sock; /* the socket we're using */ -int flags = 0; /* interface flags */ -int setaddr; -struct ifreq ifr; /* our interface information */ -struct ifreq ridreq; /* ?? */ -struct ifaliasreq addreq; /* aliases details */ -struct sockaddr_in netmask; /* the netmask */ -int mflag; -int newaddr = 0; /* do we have a new address? */ -int doalias; /* do we process alias information */ -int clearaddr; /* are we clearing the address? */ -char name[IFNAMSIZ]; /* the name of the interface we're using */ - -/* we only deal with a single interface at once, so these globals - * refer to their respective information for that interface - */ -int af = AF_INET; /* address family we're dealing with */ -int metric; /* the metric */ -int mtu; /* mtu vlaue */ - -/* forward declarations... */ -int getinfo(struct ifreq *ifr); -void setifaddr(char *addr, int param); -void setifflags(char *vname, int value); -void setifnetmask(char *addr); -void setifmetric(char *val); -void setifmtu(char *val, int d); -void in_status(int force); -void in_getaddr(char *s, int which); -void in_getprefix(char *plen, int which); -void status(int link); -void printif(struct ifreq *ifrm, int ifaliases); -void usage(void); - -/* The commands we recognise... */ -struct _cmd_ { - char *c_name; /* what the command line will say */ - int c_parameter; /* the parameter, NEXTARG = next argv */ - void (*c_func)(); /* the function to call */ -} cmds [] = { - {"up", IFF_UP, setifflags}, - {"down", -IFF_UP, setifflags}, - {"netmask", NEXTARG, setifnetmask}, - {"metric", NEXTARG, setifmetric}, - {"mtu", NEXTARG, setifmtu}, - {NULL, /*src*/0, setifaddr }, -// {NULL, /*dst*/0, setifdstaddr }, - {NULL, 0, NULL} -}; - -/* Known address families - thus far ONLY AF_INET */ -/* XXX - it'd be very cool if we could have a way of doing this - * by modules/add-ons :) - */ -const struct afswtch { - char *af_name; - short af_af; - void (*af_status)(); - void (*af_getaddr)(); - void (*af_getprefix)(); - u_long af_difaddr; - u_long af_aifaddr; - caddr_t af_ridreq; - caddr_t af_addreq; -} afs[] = { -#define C(x) ((caddr_t) &x) - { "inet", AF_INET, in_status, in_getaddr, in_getprefix, - SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, - { 0, 0, 0, 0 } -}; - -const struct afswtch *afp; /*the address family being set or asked about*/ - -void usage(void) -{ - fprintf(stderr, "OpenBeOS Network Team: ifconfig: version %s\n", version); - fprintf(stderr, "usage: ifconfig [ -m ] [ -a ] [ -A ] [ interface ]\n" - "\t[ [af] [ address [ dest_addr ] ] [ up ] [ down ] " - "[ netmask mask ] ]\n" - "\t[ metric n ]\n" - "\t[ mtu n ]\n" - " ifconfig [-a | -A | -am | -Am] [ af ]\n" - " ifconfig -m interface [af]\n"); - exit(1); -} - -static void err(int exitval, char *where) -{ - printf("error: %s: error %d [%s]\n", where, errno, strerror(errno)); - exit(exitval); -} - -static void errx(int exitval, char *fmt_string, char *value) -{ - printf("error: "); - printf(fmt_string, value); - exit(exitval); -} - -static void warn(char *what) -{ - printf("warning: %s: error %d [%s]\n", what, errno, strerror(errno)); -} - -int main(int argc, char **argv) -{ - int aflag = 0, ifaliases = 0; - const struct afswtch *rafp = NULL; - int i; - - mflag = 0; - - if (argc < 2) - usage(); - argc--, argv++; /* skip app name */ - - /* handle common optins and get the interface name */ - if (!strcmp(*argv, "-a")) - aflag = 1; - else if (!strcmp(*argv, "-A")) { - aflag = 1; - ifaliases = 1; - } else if (!strcmp(*argv, "-ma") || !strcmp(*argv, "-am")) { - aflag = 1; - mflag = 1; - } - else if (!strcmp(*argv, "-mA") || !strcmp(*argv, "-Am")) { - aflag = 1; - ifaliases = 1; - mflag = 1; - } - else if (!strcmp(*argv, "-m")) { - mflag = 1; - argc--, argv++; - if (argc < 1) - usage(); - (void) strcpy(name, *argv); - } else - (void) strcpy(name, *argv); - argc--, argv++; - - /* Try to establish the address family we're talking about - * and set the appropriate structure of commands into the - * pointer afp; - */ - if (argc > 0) { - for (afp = rafp = afs; rafp->af_name; rafp++) - if (strcmp(rafp->af_name, *argv) == 0) { - afp = rafp; argc--; argv++; - break; - } - rafp = afp; - af = ifr.ifr_addr.sa_family = rafp->af_af; - } - - if (argc > 0) { - for (afp = rafp = afs; rafp->af_name; rafp++) - if (strcmp(rafp->af_name, *argv) == 0) { - printf("afp: %s\n", *argv); - afp = rafp; argc--; argv++; - break; - } - rafp = afp; - af = ifr.ifr_addr.sa_family = rafp->af_af; - } - - if (aflag) { - if (argc > 0) - usage(); - printif(NULL, ifaliases); - exit(0); - } - - /* put the name in the ifr structure */ - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - /* if there's no more arguments then print information - * on the named interface */ - if (argc == 0) { - printif(&ifr, 1); - exit(0); - } - - /* we've probably got something to do, so get the information */ - if (getinfo(&ifr) < 0) - exit(1); - - while (argc > 0) { - const struct _cmd_ *p; - - for (p = cmds; p->c_name; p++) - if (strcmp(*argv, p->c_name) == 0) - break; - /* we've found a command! */ - if (p->c_name == NULL && setaddr) { - printf("pc->name = NULL!\n"); - for (i = setaddr; i > 0; i--) { - p++; - if (p->c_func == NULL) - err(1, "extra address not accepted"); - } - } - if (p->c_func) { - if (p->c_parameter == NEXTARG) { - if (argv[1] == NULL) - errx(1, "'%s' requires argument", - p->c_name); - (*p->c_func)(argv[1]); - argc--, argv++; - } else - (*p->c_func)(*argv, p->c_parameter); - } - - argc--, argv++; - } - if (clearaddr) { - int ret; - strncpy(rafp->af_ridreq, name, sizeof(ifr.ifr_name)); - if ((ret = ioctl(sock, rafp->af_difaddr, rafp->af_ridreq)) < 0) { - if (errno == EADDRNOTAVAIL && (doalias >= 0)) { - /* means no previous address for interface */ - } else - warn("SIOCDIFADDR"); - } - } - if (newaddr) { - strncpy(rafp->af_addreq, name, sizeof(ifr.ifr_name)); - if (ioctl(sock, rafp->af_aifaddr, rafp->af_addreq) < 0) - warn("SIOCAIFADDR"); - } - exit(0); -} - -static void getsock(int naf) -{ - static int oaf = -1; - - if (oaf == naf) - return; - if (oaf != -1) - close(sock); - sock = socket(naf, SOCK_DGRAM, 0); - if (sock < 0) - oaf = -1; - else - oaf = naf; -} - -int getinfo(struct ifreq *ifr) -{ - getsock(af); - if (sock < 0) - err(1, "socket"); - if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) < 0) { - warn("SIOCGIFFLAGS"); - return (-1); - } - flags = ifr->ifr_flags; - if (ioctl(sock, SIOCGIFMETRIC, (caddr_t)ifr) < 0) { - warn("SIOCGIFMETRIC"); - metric = 0; - } else - metric = ifr->ifr_metric; - if (ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) < 0) - mtu = 0; - else - mtu = ifr->ifr_mtu; - return (0); -} - -void printif(struct ifreq *ifrm, int ifaliases) -{ - char *inbuf = NULL; - struct ifconf ifc; - struct ifreq ifreq, *ifrp; - int i, siz, len = 8192; - int count = 0, noinet = 1; - char ifrbuf[8192]; - - getsock(af); - if (sock < 0) - err(1, "socket"); - while (1) { - ifc.ifc_len = len; - ifc.ifc_buf = inbuf = realloc(inbuf, len); - if (inbuf == NULL) - err(1, "malloc"); - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - err(1, "SIOCGIFCONF"); - if ((int) (ifc.ifc_len + sizeof(ifreq)) < len) - break; - len *= 2; - } - ifrp = ifc.ifc_req; - ifreq.ifr_name[0] = '\0'; - for (i = 0; i < ifc.ifc_len; ) { - ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i); - memcpy(ifrbuf, ifrp, sizeof(*ifrp)); - siz = ((struct ifreq *)ifrbuf)->ifr_addr.sa_len; - if (siz < (int) sizeof(ifrp->ifr_addr)) - siz = sizeof(ifrp->ifr_addr); - siz += sizeof(ifrp->ifr_name); - i += siz; - /* avoid alignment issue */ - if ((int) sizeof(ifrbuf) < siz) - err(1, "ifr too big"); - memcpy(ifrbuf, ifrp, siz); - ifrp = (struct ifreq *)ifrbuf; - - if (ifrm && strncmp(ifrm->ifr_name, ifrp->ifr_name, - sizeof(ifrp->ifr_name))) - continue; - strncpy(name, ifrp->ifr_name, sizeof(ifrp->ifr_name)); - if (ifrp->ifr_addr.sa_family == AF_LINK) { - ifreq = ifr = *ifrp; - if (getinfo(&ifreq) < 0) - continue; - status(1); - count++; - noinet = 1; - continue; - } - if (!strncmp(ifreq.ifr_name, ifrp->ifr_name, - sizeof(ifrp->ifr_name))) { - const struct afswtch *p; - - if (ifrp->ifr_addr.sa_family == AF_INET && - ifaliases == 0 && noinet == 0) - continue; - ifr = *ifrp; - if ((p = afp) != NULL) { - if (ifr.ifr_addr.sa_family == p->af_af) - (*p->af_status)(1); - } else { - for (p = afs; p->af_name; p++) { - if (ifr.ifr_addr.sa_family == p->af_af) - (*p->af_status)(0); - } - } - count++; - if (ifrp->ifr_addr.sa_family == AF_INET) - noinet = 0; - continue; - } - } - free(inbuf); - if (count == 0) { - fprintf(stderr, "%s: no such interface\n", name); - exit(1); - } -} - -#define RIDADDR 0 -#define ADDR 1 -#define MASK 2 -#define DSTADDR 3 - -/*ARGSUSED*/ -void setifaddr(char *addr, int param) -{ - /* - * Delay the ioctl to set the interface addr until flags are all set. - * The address interpretation may depend on the flags, - * and the flags may change when the address is set. - */ - setaddr++; - newaddr = 1; - if (doalias == 0) - clearaddr = 1; - (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR)); -} - -void setifnetmask(char *addr) -{ - (*afp->af_getaddr)(addr, MASK); -} - -/* - * Note: doing an SIOCIGIFFLAGS scribbles on the union portion - * of the ifreq structure, which may confuse other parts of ifconfig. - * Make a private copy so we can avoid that. - */ -void setifflags(char *vname, int value) -{ - struct ifreq my_ifr; - - memcpy((char *)&my_ifr, (char *)&ifr, sizeof(struct ifreq)); - - if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) - err(1, "SIOCGIFFLAGS"); - strncpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); - flags = my_ifr.ifr_flags; - - if (value < 0) { - value = -value; - flags &= ~value; - } else - flags |= value; - my_ifr.ifr_flags = flags; - if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) - err(1, "SIOCSIFFLAGS"); -} - -void setifmetric(char *val) -{ - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - ifr.ifr_metric = atoi(val); - if (ioctl(sock, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) - warn("SIOCSIFMETRIC"); -} - -void setifmtu(char *val, int d) -{ - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - ifr.ifr_mtu = atoi(val); - if (ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr) < 0) - warn("SIOCSIFMTU"); -} - - -#define SIN(x) ((struct sockaddr_in *) &(x)) -struct sockaddr_in *sintab[] = { -SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr), -SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)}; - -void in_getaddr(char *s, int which) -{ - struct sockaddr_in *sin = sintab[which]; -/* - struct hostent *hp; - struct netent *np; -*/ - sin->sin_len = sizeof(*sin); - if (which != MASK) - sin->sin_family = AF_INET; - - if (inet_aton(s, &sin->sin_addr) == 0) { -/* -XXX - we don't have these yet! - - if ((hp = gethostbyname(s))) - memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); - else if ((np = getnetbyname(s))) - sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); - else -*/ - errx(1, "%s: bad value", s); - } -} - -void in_status(int force) -{ - struct sockaddr_in *sin, sin2; - - getsock(AF_INET); - if (sock < 0) { - if (errno == EPROTONOSUPPORT) - return; - err(1, "socket"); - } - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - sin = (struct sockaddr_in *)&ifr.ifr_addr; - - /* - * We keep the interface address and reset it before each - * ioctl() so we can get ifaliases information (as opposed - * to the primary interface netmask/dstaddr/broadaddr, if - * the ifr_addr field is zero). - */ - memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2)); - - printf("\tinet %s ", inet_ntoa(sin->sin_addr)); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - if (ioctl(sock, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) { - if (errno != EADDRNOTAVAIL) - warn("SIOCGIFNETMASK"); - memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); - } else - netmask.sin_addr = - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; - if (flags & IFF_POINTOPOINT) { - memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2)); - if (ioctl(sock, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) { - if (errno == EADDRNOTAVAIL) - memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); - else - warn("SIOCGIFDSTADDR"); - } - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - sin = (struct sockaddr_in *)&ifr.ifr_dstaddr; - printf("--> %s ", inet_ntoa(sin->sin_addr)); - } - printf("netmask 0x%08lx ", ntohl(netmask.sin_addr.s_addr)); - if (flags & IFF_BROADCAST) { - memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2)); - if (ioctl(sock, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) { - if (errno == EADDRNOTAVAIL) - memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); - else - warn("SIOCGIFBRDADDR"); - } - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - sin = (struct sockaddr_in *)&ifr.ifr_addr; - if (sin->sin_addr.s_addr != 0) - printf("broadcast %s", inet_ntoa(sin->sin_addr)); - } - putchar('\n'); -} -/* - 1 IFF_UP = 0x0001, - 2 IFF_DOWN = 0x0002, - 3 IFF_PROMISC = 0x0004, - 4 IFF_RUNNING = 0x0008, - 5 IFF_MULTICAST = 0x0010, - 6 IFF_BROADCAST = 0x0020, - 7 IFF_POINTOPOINT = 0x0040, - 8 IFF_NOARP = 0x0080, - 9 IFF_LOOPBACK = 0x0100, - 10 IFF_DEBUG = 0x0200, - 11 IFF_LINK0 = 0x0400, - 12 IFF_LINK1 = 0x0800, - 13 IFF_LINK2 = 0x1000, - 14 IFF_SIMPLEX = 0x2000 -*/ -#define IFFBITS \ -"\017\1UP\2DOWN\3PROMISC\4RUNNING\5MULTICAST\6BROADCAST\7POINTOPOINT\10NOARP\ -\11LOOPBACK\12DEBUG\13LINK0\14LINK1\15LINK2\16SIMPLEX" - - -/* - * Print a value a la the %b format of the kernel's printf - */ -static void printb(char *s, uint16 v, char *bits) -{ - int i, any = 0; - char c; - - if (bits && *bits == 8) - printf("%s=%o", s, v); - else - printf("%s=%x", s, v); - bits++; - if (bits) { - putchar('<'); - while ((i = *bits++)) { - if (v & (1 << (i-1))) { - if (any) - putchar(','); - any = 1; - for (; (c = *bits) > 32; bits++) - putchar(c); - } else - for (; *bits > 32; bits++) - ; - } - putchar('>'); - } -} - -void in_getprefix(char *plen, int which) -{ - struct sockaddr_in *sin = sintab[which]; - u_char *cp; - int len = strtol(plen, (char **)NULL, 10); - - if ((len < 0) || (len > 32)) - errx(1, "%s: bad value", plen); - sin->sin_len = sizeof(*sin); - if (which != MASK) - sin->sin_family = AF_INET; - if ((len == 0) || (len == 32)) { - memset(&sin->sin_addr, 0xff, sizeof(struct in_addr)); - return; - } - memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr)); - for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8) - *cp++ = 0xff; - if (len) - *cp = 0xff << (8 - len); -} - -/* - * Print the status of the interface. If an address family was - * specified, show it and it only; otherwise, show them all. - */ -void status(int link) -{ - const struct afswtch *p = afp; - - printf("%s: ", name); - printb("flags", flags, IFFBITS); - if (metric) - printf(" metric %d", metric); - if (mtu) - printf(" mtu %d", mtu); - putchar('\n'); - - if (link == 0) { - if ((p = afp) != NULL) { - (*p->af_status)(1); - } else for (p = afs; p->af_name; p++) { - ifr.ifr_addr.sa_family = p->af_af; - (*p->af_status)(0); - } - } - -// phys_status(0); -} - diff --git a/src/bin/network/Jamfile b/src/bin/network/Jamfile new file mode 100644 index 0000000000..ca98c36775 --- /dev/null +++ b/src/bin/network/Jamfile @@ -0,0 +1,10 @@ +SubDir HAIKU_TOP src bin network ; + +SubInclude HAIKU_TOP src bin network arp ; +SubInclude HAIKU_TOP src bin network ftp ; +SubInclude HAIKU_TOP src bin network ifconfig ; +#SubInclude HAIKU_TOP src bin network pppconfig ; +#SubInclude HAIKU_TOP src bin network ppp_up ; +SubInclude HAIKU_TOP src bin network ping ; +SubInclude HAIKU_TOP src bin network route ; +SubInclude HAIKU_TOP src bin network traceroute ; diff --git a/src/bin/arp/Jamfile b/src/bin/network/arp/Jamfile similarity index 83% rename from src/bin/arp/Jamfile rename to src/bin/network/arp/Jamfile index d108a6535f..5fb71b5735 100644 --- a/src/bin/arp/Jamfile +++ b/src/bin/network/arp/Jamfile @@ -1,4 +1,4 @@ -SubDir HAIKU_TOP src bin arp ; +SubDir HAIKU_TOP src bin network arp ; SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ; @@ -9,10 +9,11 @@ if $(TARGET_PLATFORM) != haiku { } UsePrivateHeaders net ; +UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; BinCommand arp : - arp.c - : libnetwork.so $(SELECT_UNAME_ETC_LIB) ; + arp.cpp + : $(NETWORK_LIBS) $(SELECT_UNAME_ETC_LIB) ; # Installation -- in the test directory for the time being HaikuInstall install-networking @@ -29,3 +30,4 @@ Package haiku-networkingkit-cvs : arp : # boot home config bin ; boot home Desktop haiku-networkingkit ; + diff --git a/src/bin/network/arp/arp.cpp b/src/bin/network/arp/arp.cpp new file mode 100644 index 0000000000..44308f6f5b --- /dev/null +++ b/src/bin/network/arp/arp.cpp @@ -0,0 +1,461 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include + +#include +#include + +#include +#include +//#include +//#include +//#include +#include +//#include +//#include + +#include +#include +#include +#include +#include +#include + + +extern const char* __progname; +const char* kProgramName = __progname; + + +enum modes { + ARP_LIST = 0, + ARP_DELETE, + ARP_SET, + ARP_SET_FROM_FILE, + ARP_FLUSH, +}; + + +static const char * +ethernet_address_to_string(uint8 *address) +{ + static char string[64]; + snprintf(string, sizeof(string), "%02x:%02x:%02x:%02x:%02x:%02x", + address[0], address[1], address[2], address[3], address[4], address[5]); + return string; +} + + +static bool +parse_ethernet_address(const char *string, uint8 *address) +{ + return sscanf(string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &address[0], &address[1], + &address[2], &address[3], &address[4], &address[5]) == 6; +} + + +static bool +parse_inet_address(const char* string, sockaddr_in& address) +{ + in_addr inetAddress; + if (inet_aton(string, &inetAddress) != 1) + return false; + + address.sin_family = AF_INET; + address.sin_len = sizeof(struct sockaddr_in); + address.sin_port = 0; + address.sin_addr = inetAddress; + memset(&address.sin_zero[0], 0, sizeof(address.sin_zero)); + + return true; +} + + +static void +check_for_arp_syscall(void) +{ + uint32 version = 0; + status_t status = _kern_generic_syscall(ARP_SYSCALLS, B_SYSCALL_INFO, + &version, sizeof(version)); + if (status != B_OK) { + // the launch speedup module is not available + fprintf(stderr, "\"ARP\" module not available.\n"); + exit(1); + } +} + + +void +usage(int status) +{ + printf("usage: %s [] [] [] [temp] [pub]\n" + " %s -f \n" + "Where can be the one of:\n" + " -s - sets an entry in the ARP cache\n" + " -d - deletes the specified ARP cache entry\n" + " -a - list all entries [default]\n" + " -f - read ARP entries from file\n" + "The ethernet address is specified by six hex bytes separated by colons.\n" + "When setting a new ARP cache entry, \"temp\" creates a temporary entry\n" + "that will be removed after a timeout, and \"pub\" will cause ARP to\n" + "answer to ARP requests for this entry.\n\n" + "Example:\n" + "\t%s -s 192.168.0.2 00:09:ab:cd:ef:12 pub\n", + kProgramName, kProgramName, kProgramName); + + exit(status); +} + + +bool +set_flags(uint32 &flags, const char *argument) +{ + if (!strcmp(argument, "temp") || !strcmp(argument, "temporary")) + flags &= ~ARP_FLAG_PERMANENT; + else if (!strcmp(argument, "pub") || !strcmp(argument, "publish")) + flags |= ARP_FLAG_PUBLISH; + else if (!strcmp(argument, "reject")) + flags |= ARP_FLAG_REJECT; + else + return false; + + return true; +} + + +static char * +next_argument(char **_line) +{ + char *start = *_line; + if (!start[0]) + return NULL; + + char *end = start; + while (end[0] && !isspace(end[0])) { + end++; + } + + if (end[0]) { + // skip all whitespace until next argument (or end of line) + end[0] = '\0'; + end++; + + while (end[0] && isspace(end[0])) { + end++; + } + } + + *_line = end; + return start; +} + + +// #pragma mark - + + +void +list_entry(arp_control &control) +{ + in_addr address; + address.s_addr = control.address; + printf("%15s %s", inet_ntoa(address), + ethernet_address_to_string(control.ethernet_address)); + + if (control.flags != 0) { + const struct { + int value; + const char *name; + } kFlags[] = { + {ARP_FLAG_PERMANENT, "permanent"}, + {ARP_FLAG_LOCAL, "local"}, + {ARP_FLAG_PUBLISH, "publish"}, + {ARP_FLAG_REJECT, "reject"}, + }; + bool first = true; + + for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) { + if ((control.flags & kFlags[i].value) != 0) { + if (first) { + printf(" "); + first = false; + } else + putchar(' '); + printf(kFlags[i].name); + } + } + } + + putchar('\n'); +} + + +void +list_entries(sockaddr_in *address) +{ + arp_control control; + status_t status; + + if (address != NULL) { + control.address = address->sin_addr.s_addr; + status = _kern_generic_syscall(ARP_SYSCALLS, ARP_GET_ENTRY, + &control, sizeof(arp_control)); + if (status != B_OK) { + fprintf(stderr, "%s: ARP entry does not exist.\n", kProgramName); + exit(1); + } + + list_entry(control); + return; + } + + control.cookie = 0; + while (_kern_generic_syscall(ARP_SYSCALLS, ARP_GET_ENTRIES, + &control, sizeof(arp_control)) == B_OK) { + list_entry(control); + } +} + + +void +delete_entry(sockaddr_in *address) +{ + arp_control control; + control.address = address->sin_addr.s_addr; + + status_t status = _kern_generic_syscall(ARP_SYSCALLS, ARP_DELETE_ENTRY, + &control, sizeof(arp_control)); + if (status != B_OK) { + fprintf(stderr, "%s: Could not delete ARP entry: %s\n", + kProgramName, strerror(status)); + exit(1); + } +} + + +status_t +set_entry(sockaddr_in *address, uint8 *ethernetAddress, uint32 flags) +{ + arp_control control; + control.address = address->sin_addr.s_addr; + memcpy(control.ethernet_address, ethernetAddress, ETHER_ADDRESS_LENGTH); + control.flags = flags; + + return _kern_generic_syscall(ARP_SYSCALLS, ARP_SET_ENTRY, + &control, sizeof(arp_control)); +} + + +int +set_entries_from_file(const char *filename) +{ + FILE *file = fopen(filename, "r"); + if (file == NULL) { + fprintf(stderr, "%s: Could not open file: %s\n", kProgramName, strerror(errno)); + return 1; + } + + int32 counter = 0; + char line[4096]; + + while (fgets(line, sizeof(line), file) != NULL) { + counter++; + + // comments and empty lines are allowed + if (line[0] == '#' || !strcmp(line, "\n")) + continue; + + // parse hostname + + char *rest = line; + const char *argument = next_argument(&rest); + if (argument == NULL) { + fprintf(stderr, "%s: Line %ld is invalid (missing hostname).\n", + kProgramName, counter); + continue; + } + + sockaddr_in address; + if (!parse_inet_address(argument, address)) { + // get host by name + struct hostent *host = gethostbyname(argument); + if (host == NULL) { + fprintf(stderr, "%s: Line %ld, host \"%s\" is not known in the IPv4 domain: %s\n", + kProgramName, counter, argument, strerror(errno)); + continue; + } + if (host->h_addrtype != AF_INET) { + fprintf(stderr, "%s: Line %ld, host \"%s\" is not known in the IPv4 domain.\n", + kProgramName, counter, argument); + continue; + } + + address.sin_family = AF_INET; + address.sin_len = sizeof(sockaddr_in); + address.sin_addr.s_addr = *(in_addr_t *)host->h_addr; + } + + // parse ethernet MAC address + + argument = next_argument(&rest); + if (argument == NULL) { + fprintf(stderr, "%s: Line %ld is invalid (missing ethernet address).\n", + kProgramName, counter); + continue; + } + + uint8 ethernetAddress[6]; + if (!parse_ethernet_address(argument, ethernetAddress)) { + fprintf(stderr, "%s: Line %ld, \"%s\" is not a valid ethernet address.\n", + kProgramName, counter, argument); + continue; + } + + // parse other options + + uint32 flags = ARP_FLAG_PERMANENT; + while ((argument = next_argument(&rest)) != NULL) { + if (!set_flags(flags, argument)) { + fprintf(stderr, "%s: Line %ld, ignoring invalid flag \"%s\".\n", + kProgramName, counter, argument); + } + } + + status_t status = set_entry(&address, ethernetAddress, flags); + if (status != B_OK) { + fprintf(stderr, "%s: Line %ld, ARP entry could not been set: %s\n", + kProgramName, counter, strerror(status)); + } + } + + fclose(file); + return 0; +} + + +// #pragma mark - + + +int +main(int argc, char** argv) +{ + if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) + usage(0); + + int32 mode = ARP_LIST; + int32 i = 1; + + if (argc > 1 && argv[1][0] == '-') { + if (!strcmp(argv[1], "-d")) { + // delete entry + if (argc != 3) + usage(1); + + mode = ARP_DELETE; + } else if (!strcmp(argv[1], "-s")) { + // set entry + if (argc < 4) + usage(1); + + mode = ARP_SET; + } else if (!strcmp(argv[1], "-a")) { + // list all + if (argc != 2) + usage(1); + + mode = ARP_LIST; + } else if (!strcmp(argv[1], "-F")) { + // flush all entries + if (argc != 2) + usage(1); + + mode = ARP_FLUSH; + } else if (!strcmp(argv[1], "-f")) { + // set from file + if (argc != 3) + usage(1); + + check_for_arp_syscall(); + return set_entries_from_file(argv[2]); + } else { + fprintf(stderr, "%s: Unknown option %s\n", kProgramName, argv[1]); + usage(1); + } + + i++; + } + + // parse hostname + + const char *hostname = argv[i]; + sockaddr_in address; + + if (hostname != NULL && !parse_inet_address(hostname, address)) { + // get host by name + struct hostent *host = gethostbyname(hostname); + if (host == NULL) { + fprintf(stderr, "%s: Host \"%s\" is not known in the IPv4 domain: %s\n", + kProgramName, hostname, strerror(errno)); + return 1; + } + if (host->h_addrtype != AF_INET) { + fprintf(stderr, "%s: Host \"%s\" is not known in the IPv4 domain.\n", + kProgramName, hostname); + return 1; + } + + address.sin_family = AF_INET; + address.sin_len = sizeof(sockaddr_in); + address.sin_addr.s_addr = *(in_addr_t *)host->h_addr; + } + + // parse other options in case of ARP_SET + + uint8 ethernetAddress[6]; + uint32 flags = ARP_FLAG_PERMANENT; + + if (mode == ARP_SET) { + if (!parse_ethernet_address(argv[3], ethernetAddress)) { + fprintf(stderr, "%s: \"%s\" is not a valid ethernet address.\n", + kProgramName, argv[3]); + return 1; + } + + for (int32 i = 4; i < argc; i++) { + if (!set_flags(flags, argv[i])) { + fprintf(stderr, "%s: Flag \"%s\" is invalid.\n", + kProgramName, argv[i]); + return 1; + } + } + } + + check_for_arp_syscall(); + + switch (mode) { + case ARP_SET: + { + status_t status = set_entry(&address, ethernetAddress, flags); + if (status != B_OK) { + fprintf(stderr, "%s: ARP entry could not been set: %s\n", + kProgramName, strerror(status)); + return 1; + } + break; + } + case ARP_DELETE: + delete_entry(&address); + break; + case ARP_LIST: + list_entries(hostname ? &address : NULL); + break; + } + + return 0; +} + diff --git a/src/bin/network/ftp/Jamfile b/src/bin/network/ftp/Jamfile new file mode 100644 index 0000000000..4d43a4d9f3 --- /dev/null +++ b/src/bin/network/ftp/Jamfile @@ -0,0 +1,41 @@ +SubDir HAIKU_TOP src bin network ftp ; + +SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ; + +if $(TARGET_PLATFORM) != haiku { + UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; + # We need the public network headers also when not compiling for Haiku. + # Unfortunately we get more than we want, namely all POSIX headers. +} + +UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; + +BinCommand ftp : + cmds.c + cmdtab.c + complete.c + domacro.c + fetch.c + ftp.c + main.c + progressbar.c + ruserpass.c + util.c + : libtermcap.a libedit.a libncurses.a libutil.a libbsd.so $(NETWORK_LIBS) +; + +# Installation -- in the test directory for the time being +HaikuInstall install-networking + : [ FDirName $(HAIKU_TEST_DIR) kits net ] + : ftp ; + +HaikuInstall install-userland-networking + : [ FDirName $(HAIKU_TEST_DIR) kits net userland ] + : ftp + : installed-userland-networking +; + +Package haiku-networkingkit-cvs : + ftp : +# boot home config bin ; + boot home Desktop haiku-networkingkit ; diff --git a/src/bin/network/ftp/Makefile b/src/bin/network/ftp/Makefile new file mode 100644 index 0000000000..79cc5a6060 --- /dev/null +++ b/src/bin/network/ftp/Makefile @@ -0,0 +1,28 @@ +# $NetBSD: Makefile,v 1.30 2005/02/11 15:13:28 jmc Exp $ +# from: @(#)Makefile 8.2 (Berkeley) 4/3/94 + +.include + +PROG= ftp +SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c \ + progressbar.c ruserpass.c util.c + +# Uncomment the following to provide defaults for gate-ftp operation +# +#CPPFLAGS+=-DGATE_SERVER=\"ftp-gw.host\" # -DGATE_PORT=21 + +.if defined(SMALLPROG) +CPPFLAGS+=-DNO_EDITCOMPLETE -DNO_ABOUT -DNO_AUTH -DNO_HELP -DNO_STATUS +.else +LDADD+= -ledit -ltermcap +DPADD+= ${LIBEDIT} ${LIBTERMCAP} +.endif + +.if (!defined(SMALLPROG) || defined(SMALLPROG_INET6)) && (${USE_INET6} != "no") +CPPFLAGS+= -DINET6 +.endif + +cmds.o fetch.o: version.h +main.o: ftp_var.h + +.include diff --git a/src/bin/network/ftp/Makefile.in b/src/bin/network/ftp/Makefile.in new file mode 100644 index 0000000000..bb60f10867 --- /dev/null +++ b/src/bin/network/ftp/Makefile.in @@ -0,0 +1,43 @@ +# +# $Id: Makefile.in,v 1.8 2000/08/08 07:04:27 lukem Exp $ +# + +srcdir = @srcdir@ +VPATH = @srcdir@ +SHELL = /bin/sh + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ +transform = @program_transform_name@ + +mandircat1 = ${mandir}/cat1 + +CC = @CC@ +CFLAGS = -I${srcdir} -I${srcdir}/.. -I. -I.. @INCLUDES@ @CFLAGS@ +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ + +INSTALL = @INSTALL@ + +PROG = ftp +OBJS = cmds.o cmdtab.o complete.o domacro.o fetch.o ftp.o main.o \ + ruserpass.o util.o + +all: ${PROG} + +install: all + -mkdir -p ${bindir} + ${INSTALL} -m 555 ${PROG} ${bindir}/`echo ${PROG}|sed '$(transform)'` + -mkdir -p ${mandircat1} + ${INSTALL} -m 444 ${srcdir}/${PROG}.cat1 ${mandircat1}/`echo ${PROG}|sed '$(transform)'`.1 + +${PROG}: ${OBJS} @LIBDEPENDS@ + ${CC} ${CFLAGS} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBS} + +clean: + rm -f core ${PROG} ${OBJS} + +distclean: clean + rm -f Makefile diff --git a/src/bin/network/ftp/cmds.c b/src/bin/network/ftp/cmds.c new file mode 100644 index 0000000000..d584ba33d3 --- /dev/null +++ b/src/bin/network/ftp/cmds.c @@ -0,0 +1,2746 @@ +/* $NetBSD: cmds.c,v 1.112 2005/04/11 01:49:31 lukem Exp $ */ + +/*- + * Copyright (c) 1996-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) 1997 and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * FTP User Program -- Command Routines. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" +#include "version.h" + +struct types { + char *t_name; + char *t_mode; + int t_type; + char *t_arg; +} types[] = { + { "ascii", "A", TYPE_A, 0 }, + { "binary", "I", TYPE_I, 0 }, + { "image", "I", TYPE_I, 0 }, + { "ebcdic", "E", TYPE_E, 0 }, + { "tenex", "L", TYPE_L, bytename }, + { NULL } +}; + +sigjmp_buf jabort; +const char *mname; + +static int confirm(const char *, const char *); + +static const char *doprocess(char *, size_t, const char *, int, int, int); +static const char *domap(char *, size_t, const char *); +static const char *docase(char *, size_t, const char *); +static const char *dotrans(char *, size_t, const char *); + +static int +confirm(const char *cmd, const char *file) +{ + char line[BUFSIZ]; + + if (!interactive || confirmrest) + return (1); + while (1) { + fprintf(ttyout, "%s %s [anpqy?]? ", cmd, file); + (void)fflush(ttyout); + if (fgets(line, sizeof(line), stdin) == NULL) { + mflag = 0; + fprintf(ttyout, "\nEOF received; %s aborted\n", mname); + clearerr(stdin); + return (0); + } + switch (tolower((unsigned char)*line)) { + case 'a': + confirmrest = 1; + fprintf(ttyout, + "Prompting off for duration of %s.\n", cmd); + break; + case 'p': + interactive = 0; + fputs("Interactive mode: off.\n", ttyout); + break; + case 'q': + mflag = 0; + fprintf(ttyout, "%s aborted.\n", mname); + /* FALLTHROUGH */ + case 'n': + return (0); + case '?': + fprintf(ttyout, + " confirmation options:\n" + "\ta answer `yes' for the duration of %s\n" + "\tn answer `no' for this file\n" + "\tp turn off `prompt' mode\n" + "\tq stop the current %s\n" + "\ty answer `yes' for this file\n" + "\t? this help list\n", + cmd, cmd); + continue; /* back to while(1) */ + } + return (1); + } + /* NOTREACHED */ +} + +/* + * Set transfer type. + */ +void +settype(int argc, char *argv[]) +{ + struct types *p; + int comret; + + if (argc == 0 || argc > 2) { + char *sep; + + fprintf(ttyout, "usage: %s [", argv[0]); + sep = " "; + for (p = types; p->t_name; p++) { + fprintf(ttyout, "%s%s", sep, p->t_name); + sep = " | "; + } + fputs(" ]\n", ttyout); + code = -1; + return; + } + if (argc < 2) { + fprintf(ttyout, "Using %s mode to transfer files.\n", typename); + code = 0; + return; + } + for (p = types; p->t_name; p++) + if (strcmp(argv[1], p->t_name) == 0) + break; + if (p->t_name == 0) { + fprintf(ttyout, "%s: unknown mode.\n", argv[1]); + code = -1; + return; + } + if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) + comret = command("TYPE %s %s", p->t_mode, p->t_arg); + else + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) { + (void)strlcpy(typename, p->t_name, sizeof(typename)); + curtype = type = p->t_type; + } +} + +/* + * Internal form of settype; changes current type in use with server + * without changing our notion of the type for data transfers. + * Used to change to and from ascii for listings. + */ +void +changetype(int newtype, int show) +{ + struct types *p; + int comret, oldverbose = verbose; + + if (newtype == 0) + newtype = TYPE_I; + if (newtype == curtype) + return; + if (debug == 0 && show == 0) + verbose = 0; + for (p = types; p->t_name; p++) + if (newtype == p->t_type) + break; + if (p->t_name == 0) { + warnx("internal error: unknown type %d.", newtype); + return; + } + if (newtype == TYPE_L && bytename[0] != '\0') + comret = command("TYPE %s %s", p->t_mode, bytename); + else + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) + curtype = newtype; + verbose = oldverbose; +} + +char *stype[] = { + "type", + "", + 0 +}; + +/* + * Set binary transfer type. + */ +/*VARARGS*/ +void +setbinary(int argc, char *argv[]) +{ + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + stype[1] = "binary"; + settype(2, stype); +} + +/* + * Set ascii transfer type. + */ +/*VARARGS*/ +void +setascii(int argc, char *argv[]) +{ + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + stype[1] = "ascii"; + settype(2, stype); +} + +/* + * Set tenex transfer type. + */ +/*VARARGS*/ +void +settenex(int argc, char *argv[]) +{ + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + stype[1] = "tenex"; + settype(2, stype); +} + +/* + * Set file transfer mode. + */ +/*ARGSUSED*/ +void +setftmode(int argc, char *argv[]) +{ + + if (argc != 2) { + fprintf(ttyout, "usage: %s mode-name\n", argv[0]); + code = -1; + return; + } + fprintf(ttyout, "We only support %s mode, sorry.\n", modename); + code = -1; +} + +/* + * Set file transfer format. + */ +/*ARGSUSED*/ +void +setform(int argc, char *argv[]) +{ + + if (argc != 2) { + fprintf(ttyout, "usage: %s format\n", argv[0]); + code = -1; + return; + } + fprintf(ttyout, "We only support %s format, sorry.\n", formname); + code = -1; +} + +/* + * Set file transfer structure. + */ +/*ARGSUSED*/ +void +setstruct(int argc, char *argv[]) +{ + + if (argc != 2) { + fprintf(ttyout, "usage: %s struct-mode\n", argv[0]); + code = -1; + return; + } + fprintf(ttyout, "We only support %s structure, sorry.\n", structname); + code = -1; +} + +/* + * Send a single file. + */ +void +put(int argc, char *argv[]) +{ + char buf[MAXPATHLEN]; + char *cmd; + int loc = 0; + char *locfile; + const char *remfile; + + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } + if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file"))) + goto usage; + if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { + usage: + fprintf(ttyout, "usage: %s local-file [remote-file]\n", + argv[0]); + code = -1; + return; + } + if ((locfile = globulize(argv[1])) == NULL) { + code = -1; + return; + } + remfile = argv[2]; + if (loc) /* If argv[2] is a copy of the old argv[1], update it */ + remfile = locfile; + cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); + remfile = doprocess(buf, sizeof(buf), remfile, + 0, loc && ntflag, loc && mapflag); + sendrequest(cmd, locfile, remfile, + locfile != argv[1] || remfile != argv[2]); + free(locfile); +} + +static const char * +doprocess(char *dst, size_t dlen, const char *src, + int casef, int transf, int mapf) +{ + if (casef) + src = docase(dst, dlen, src); + if (transf) + src = dotrans(dst, dlen, src); + if (mapf) + src = domap(dst, dlen, src); + return src; +} + +/* + * Send multiple files. + */ +void +mput(int argc, char *argv[]) +{ + int i; + sigfunc oldintr; + int ointer; + const char *tp; + + if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) { + fprintf(ttyout, "usage: %s local-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = xsignal(SIGINT, mintr); + if (sigsetjmp(jabort, 1)) + mabort(); + if (proxy) { + char *cp; + + while ((cp = remglob(argv, 0, NULL)) != NULL) { + if (*cp == '\0' || !connected) { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + char buf[MAXPATHLEN]; + tp = doprocess(buf, sizeof(buf), cp, + mcase, ntflag, mapflag); + sendrequest((sunique) ? "STOU" : "STOR", + cp, tp, cp != tp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mput")) { + mflag++; + } + interactive = ointer; + } + } + } + goto cleanupmput; + } + for (i = 1; i < argc && connected; i++) { + char **cpp; + glob_t gl; + int flags; + + if (!doglob) { + if (mflag && confirm(argv[0], argv[i])) { + char buf[MAXPATHLEN]; + tp = doprocess(buf, sizeof(buf), argv[i], + 0, ntflag, mapflag); + sendrequest((sunique) ? "STOU" : "STOR", + argv[i], tp, tp != argv[i] || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mput")) { + mflag++; + } + interactive = ointer; + } + } + continue; + } + + memset(&gl, 0, sizeof(gl)); + flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; + if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { + warnx("%s: not found", argv[i]); + globfree(&gl); + continue; + } + for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected; + cpp++) { + if (mflag && confirm(argv[0], *cpp)) { + char buf[MAXPATHLEN]; + tp = *cpp; + tp = doprocess(buf, sizeof(buf), *cpp, + 0, ntflag, mapflag); + sendrequest((sunique) ? "STOU" : "STOR", + *cpp, tp, *cpp != tp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mput")) { + mflag++; + } + interactive = ointer; + } + } + } + globfree(&gl); + } + cleanupmput: + (void)xsignal(SIGINT, oldintr); + mflag = 0; +} + +void +reget(int argc, char *argv[]) +{ + + (void)getit(argc, argv, 1, "r+"); +} + +void +get(int argc, char *argv[]) +{ + + (void)getit(argc, argv, 0, restart_point ? "r+" : "w" ); +} + +/* + * Receive one file. + * If restartit is 1, restart the xfer always. + * If restartit is -1, restart the xfer only if the remote file is newer. + */ +int +getit(int argc, char *argv[], int restartit, const char *mode) +{ + int loc, rval; + char *remfile, *olocfile; + const char *locfile; + char buf[MAXPATHLEN]; + + loc = rval = 0; + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } + if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file"))) + goto usage; + if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { + usage: + fprintf(ttyout, "usage: %s remote-file [local-file]\n", + argv[0]); + code = -1; + return (0); + } + remfile = argv[1]; + if ((olocfile = globulize(argv[2])) == NULL) { + code = -1; + return (0); + } + locfile = doprocess(buf, sizeof(buf), olocfile, + loc && mcase, loc && ntflag, loc && mapflag); + if (restartit) { + struct stat stbuf; + int ret; + + if (! features[FEAT_REST_STREAM]) { + fprintf(ttyout, + "Restart is not supported by the remote server.\n"); + return (0); + } + ret = stat(locfile, &stbuf); + if (restartit == 1) { + if (ret < 0) { + warn("local: %s", locfile); + goto freegetit; + } + restart_point = stbuf.st_size; + } else { + if (ret == 0) { + time_t mtime; + + mtime = remotemodtime(argv[1], 0); + if (mtime == -1) + goto freegetit; + if (stbuf.st_mtime >= mtime) { + rval = 1; + goto freegetit; + } + } + } + } + + recvrequest("RETR", locfile, remfile, mode, + remfile != argv[1] || locfile != argv[2], loc); + restart_point = 0; + freegetit: + (void)free(olocfile); + return (rval); +} + +/* ARGSUSED */ +void +mintr(int signo) +{ + + alarmtimer(0); + if (fromatty) + write(fileno(ttyout), "\n", 1); + siglongjmp(jabort, 1); +} + +void +mabort(void) +{ + int ointer, oconf; + + if (mflag && fromatty) { + ointer = interactive; + oconf = confirmrest; + interactive = 1; + confirmrest = 0; + if (confirm("Continue with", mname)) { + interactive = ointer; + confirmrest = oconf; + return; + } + interactive = ointer; + confirmrest = oconf; + } + mflag = 0; +} + +/* + * Get multiple files. + */ +void +mget(int argc, char *argv[]) +{ + sigfunc oldintr; + int ointer; + char *cp; + const char *tp; + int restartit; + + if (argc == 0 || + (argc == 1 && !another(&argc, &argv, "remote-files"))) { + fprintf(ttyout, "usage: %s remote-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + restart_point = 0; + restartit = 0; + if (strcmp(argv[0], "mreget") == 0) { + if (! features[FEAT_REST_STREAM]) { + fprintf(ttyout, + "Restart is not supported by the remote server.\n"); + return; + } + restartit = 1; + } + oldintr = xsignal(SIGINT, mintr); + if (sigsetjmp(jabort, 1)) + mabort(); + while ((cp = remglob(argv, proxy, NULL)) != NULL) { + char buf[MAXPATHLEN]; + if (*cp == '\0' || !connected) { + mflag = 0; + continue; + } + if (! mflag) + continue; + if (! fileindir(cp, localcwd)) { + fprintf(ttyout, "Skipping non-relative filename `%s'\n", + cp); + continue; + } + if (!confirm(argv[0], cp)) + continue; + tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag); + if (restartit) { + struct stat stbuf; + + if (stat(tp, &stbuf) == 0) + restart_point = stbuf.st_size; + else + warn("stat %s", tp); + } + recvrequest("RETR", tp, cp, restart_point ? "r+" : "w", + tp != cp || !interactive, 1); + restart_point = 0; + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mget")) + mflag++; + interactive = ointer; + } + } + (void)xsignal(SIGINT, oldintr); + mflag = 0; +} + +/* + * Read list of filenames from a local file and get those + */ +void +fget(int argc, char *argv[]) +{ + char *buf, *mode; + FILE *fp; + + if (argc != 2) { + fprintf(ttyout, "usage: %s localfile\n", argv[0]); + code = -1; + return; + } + + fp = fopen(argv[1], "r"); + if (fp == NULL) { + fprintf(ttyout, "Cannot open source file %s\n", argv[1]); + code = -1; + return; + } + + argv[0] = "get"; + mode = restart_point ? "r+" : "w"; + + for (; + (buf = fparseln(fp, NULL, NULL, "\0\0\0", 0)) != NULL; + free(buf)) { + if (buf[0] == '\0') + continue; + argv[1] = buf; + (void)getit(argc, argv, 0, mode); + } + fclose(fp); +} + +char * +onoff(int bool) +{ + + return (bool ? "on" : "off"); +} + +/* + * Show status. + */ +/*ARGSUSED*/ +void +status(int argc, char *argv[]) +{ + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } +#ifndef NO_STATUS + if (connected) + fprintf(ttyout, "Connected %sto %s.\n", + connected == -1 ? "and logged in" : "", hostname); + else + fputs("Not connected.\n", ttyout); + if (!proxy) { + pswitch(1); + if (connected) { + fprintf(ttyout, "Connected for proxy commands to %s.\n", + hostname); + } + else { + fputs("No proxy connection.\n", ttyout); + } + pswitch(0); + } + fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), + *gateserver ? gateserver : "(none)", gateport); + fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", + onoff(passivemode), onoff(activefallback)); + fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", + modename, typename, formname, structname); + fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", + onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); + fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", + onoff(sunique), onoff(runique)); + fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); + fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), + onoff(crflag)); + if (ntflag) { + fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); + } + else { + fputs("Ntrans: off.\n", ttyout); + } + if (mapflag) { + fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); + } + else { + fputs("Nmap: off.\n", ttyout); + } + fprintf(ttyout, + "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", + onoff(hash), mark, onoff(progress)); + fprintf(ttyout, + "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", + onoff(rate_get), rate_get, rate_get_incr); + fprintf(ttyout, + "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", + onoff(rate_put), rate_put, rate_put_incr); + fprintf(ttyout, + "Socket buffer sizes: send %d, receive %d.\n", + sndbuf_size, rcvbuf_size); + fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport)); + fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), + epsv4bad ? " (disabled for this connection)" : ""); + fprintf(ttyout, "Command line editing: %s.\n", +#ifdef NO_EDITCOMPLETE + "support not compiled in" +#else /* !def NO_EDITCOMPLETE */ + onoff(editing) +#endif /* !def NO_EDITCOMPLETE */ + ); + if (macnum > 0) { + int i; + + fputs("Macros:\n", ttyout); + for (i=0; i 3) { + fprintf(ttyout, + "usage: %s [ on | off | gateserver [port] ]\n", argv[0]); + code = -1; + return; + } else if (argc < 2) { + gatemode = !gatemode; + } else { + if (argc == 2 && strcasecmp(argv[1], "on") == 0) + gatemode = 1; + else if (argc == 2 && strcasecmp(argv[1], "off") == 0) + gatemode = 0; + else { + if (argc == 3) + gateport = xstrdup(argv[2]); + (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf)); + gateserver = gsbuf; + gatemode = 1; + } + } + if (gatemode && (gateserver == NULL || *gateserver == '\0')) { + fprintf(ttyout, + "Disabling gate-ftp mode - no gate-ftp server defined.\n"); + gatemode = 0; + } else { + fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", + onoff(gatemode), *gateserver ? gateserver : "(none)", + gateport); + } + code = gatemode; +} + +/* + * Toggle metacharacter interpretation on local file names. + */ +/*VARARGS*/ +void +setglob(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &doglob, "Globbing"); +} + +/* + * Toggle preserving modification times on retrieved files. + */ +/*VARARGS*/ +void +setpreserve(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &preserve, "Preserve modification times"); +} + +/* + * Set debugging mode on/off and/or set level of debugging. + */ +/*VARARGS*/ +void +setdebug(int argc, char *argv[]) +{ + if (argc == 0 || argc > 2) { + fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n", + argv[0]); + code = -1; + return; + } else if (argc == 2) { + if (strcasecmp(argv[1], "on") == 0) + debug = 1; + else if (strcasecmp(argv[1], "off") == 0) + debug = 0; + else { + int val; + + val = strsuftoi(argv[1]); + if (val < 0) { + fprintf(ttyout, "%s: bad debugging value.\n", + argv[1]); + code = -1; + return; + } + debug = val; + } + } else + debug = !debug; + if (debug) + options |= SO_DEBUG; + else + options &= ~SO_DEBUG; + fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug); + code = debug > 0; +} + +/* + * Set current working directory on remote machine. + */ +void +cd(int argc, char *argv[]) +{ + int r; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "remote-directory"))) { + fprintf(ttyout, "usage: %s remote-directory\n", argv[0]); + code = -1; + return; + } + r = command("CWD %s", argv[1]); + if (r == ERROR && code == 500) { + if (verbose) + fputs("CWD command not recognized, trying XCWD.\n", + ttyout); + r = command("XCWD %s", argv[1]); + } + if (r == COMPLETE) { + dirchange = 1; + updateremotecwd(); + } +} + +/* + * Set current working directory on local machine. + */ +void +lcd(int argc, char *argv[]) +{ + char *locdir; + + code = -1; + if (argc == 1) { + argc++; + argv[1] = localhome; + } + if (argc != 2) { + fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]); + return; + } + if ((locdir = globulize(argv[1])) == NULL) + return; + if (chdir(locdir) == -1) + warn("lcd %s", locdir); + else { + updatelocalcwd(); + if (localcwd[0]) { + fprintf(ttyout, "Local directory now: %s\n", localcwd); + code = 0; + } else { + fprintf(ttyout, "Unable to determine local directory\n"); + } + } + (void)free(locdir); +} + +/* + * Delete a single file. + */ +void +delete(int argc, char *argv[]) +{ + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "remote-file"))) { + fprintf(ttyout, "usage: %s remote-file\n", argv[0]); + code = -1; + return; + } + if (command("DELE %s", argv[1]) == COMPLETE) + dirchange = 1; +} + +/* + * Delete multiple files. + */ +void +mdelete(int argc, char *argv[]) +{ + sigfunc oldintr; + int ointer; + char *cp; + + if (argc == 0 || + (argc == 1 && !another(&argc, &argv, "remote-files"))) { + fprintf(ttyout, "usage: %s [remote-files]\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = xsignal(SIGINT, mintr); + if (sigsetjmp(jabort, 1)) + mabort(); + while ((cp = remglob(argv, 0, NULL)) != NULL) { + if (*cp == '\0') { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + if (command("DELE %s", cp) == COMPLETE) + dirchange = 1; + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mdelete")) { + mflag++; + } + interactive = ointer; + } + } + } + (void)xsignal(SIGINT, oldintr); + mflag = 0; +} + +/* + * Rename a remote file. + */ +void +renamefile(int argc, char *argv[]) +{ + + if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name"))) + goto usage; + if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { + usage: + fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]); + code = -1; + return; + } + if (command("RNFR %s", argv[1]) == CONTINUE && + command("RNTO %s", argv[2]) == COMPLETE) + dirchange = 1; +} + +/* + * Get a directory listing of remote files. + * Supports being invoked as: + * cmd runs + * --- ---- + * dir, ls LIST + * mlsd MLSD + * nlist NLST + * pdir, pls LIST |$PAGER + * mmlsd MLSD |$PAGER + */ +void +ls(int argc, char *argv[]) +{ + const char *cmd; + char *remdir, *locfile; + int freelocfile, pagecmd, mlsdcmd; + + remdir = NULL; + locfile = "-"; + freelocfile = pagecmd = mlsdcmd = 0; + /* + * the only commands that start with `p' are + * the `pager' versions. + */ + if (argv[0][0] == 'p') + pagecmd = 1; + if (strcmp(argv[0] + pagecmd , "mlsd") == 0) { + if (! features[FEAT_MLST]) { + fprintf(ttyout, + "MLSD is not supported by the remote server.\n"); + return; + } + mlsdcmd = 1; + } + if (argc == 0) + goto usage; + + if (mlsdcmd) + cmd = "MLSD"; + else if (strcmp(argv[0] + pagecmd, "nlist") == 0) + cmd = "NLST"; + else + cmd = "LIST"; + + if (argc > 1) + remdir = argv[1]; + if (argc > 2) + locfile = argv[2]; + if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) { + usage: + if (pagecmd || mlsdcmd) + fprintf(ttyout, + "usage: %s [remote-path]\n", argv[0]); + else + fprintf(ttyout, + "usage: %s [remote-path [local-file]]\n", + argv[0]); + code = -1; + goto freels; + } + + if (pagecmd) { + char *p; + int len; + + p = getoptionvalue("pager"); + if (EMPTYSTRING(p)) + p = DEFAULTPAGER; + len = strlen(p) + 2; + locfile = xmalloc(len); + locfile[0] = '|'; + (void)strlcpy(locfile + 1, p, len - 1); + freelocfile = 1; + } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') { + mname = argv[0]; + if ((locfile = globulize(locfile)) == NULL || + !confirm("output to local-file:", locfile)) { + code = -1; + goto freels; + } + freelocfile = 1; + } + recvrequest(cmd, locfile, remdir, "w", 0, 0); + freels: + if (freelocfile && locfile) + (void)free(locfile); +} + +/* + * Get a directory listing of multiple remote files. + */ +void +mls(int argc, char *argv[]) +{ + sigfunc oldintr; + int ointer, i; + int dolist; + char *mode, *dest, *odest; + + if (argc == 0) + goto usage; + if (argc < 2 && !another(&argc, &argv, "remote-files")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "local-file")) { + usage: + fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]); + code = -1; + return; + } + odest = dest = argv[argc - 1]; + argv[argc - 1] = NULL; + mname = argv[0]; + if (strcmp(dest, "-") && *dest != '|') + if (((dest = globulize(dest)) == NULL) || + !confirm("output to local-file:", dest)) { + code = -1; + return; + } + dolist = strcmp(argv[0], "mls"); + mflag = 1; + oldintr = xsignal(SIGINT, mintr); + if (sigsetjmp(jabort, 1)) + mabort(); + for (i = 1; mflag && i < argc-1 && connected; i++) { + mode = (i == 1) ? "w" : "a"; + recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode, + 0, 0); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", argv[0])) { + mflag++; + } + interactive = ointer; + } + } + (void)xsignal(SIGINT, oldintr); + mflag = 0; + if (dest != odest) /* free up after globulize() */ + free(dest); +} + +/* + * Do a shell escape + */ +/*ARGSUSED*/ +void +shell(int argc, char *argv[]) +{ + pid_t pid; + sigfunc oldintr; + char shellnam[MAXPATHLEN], *shell, *namep; + int wait_status; + + if (argc == 0) { + fprintf(ttyout, "usage: %s [command [args]]\n", argv[0]); + code = -1; + return; + } + oldintr = xsignal(SIGINT, SIG_IGN); + if ((pid = fork()) == 0) { + for (pid = 3; pid < 20; pid++) + (void)close(pid); + (void)xsignal(SIGINT, SIG_DFL); + shell = getenv("SHELL"); + if (shell == NULL) + shell = _PATH_BSHELL; + namep = strrchr(shell, '/'); + if (namep == NULL) + namep = shell; + else + namep++; + (void)strlcpy(shellnam, namep, sizeof(shellnam)); + if (debug) { + fputs(shell, ttyout); + putc('\n', ttyout); + } + if (argc > 1) { + execl(shell, shellnam, "-c", altarg, (char *)0); + } + else { + execl(shell, shellnam, (char *)0); + } + warn("%s", shell); + code = -1; + exit(1); + } + if (pid > 0) + while (wait(&wait_status) != pid) + ; + (void)xsignal(SIGINT, oldintr); + if (pid == -1) { + warn("Try again later"); + code = -1; + } else + code = 0; +} + +/* + * Send new user information (re-login) + */ +void +user(int argc, char *argv[]) +{ + char acct[80]; + int n, aflag = 0; + + if (argc == 0) + goto usage; + if (argc < 2) + (void)another(&argc, &argv, "username"); + if (argc < 2 || argc > 4) { + usage: + fprintf(ttyout, "usage: %s username [password [account]]\n", + argv[0]); + code = -1; + return; + } + n = command("USER %s", argv[1]); + if (n == CONTINUE) { + if (argc < 3) { + argv[2] = getpass("Password: "); + argc++; + } + n = command("PASS %s", argv[2]); + } + if (n == CONTINUE) { + if (argc < 4) { + (void)fputs("Account: ", ttyout); + (void)fflush(ttyout); + if (fgets(acct, sizeof(acct) - 1, stdin) == NULL) { + fprintf(ttyout, + "\nEOF received; login aborted.\n"); + clearerr(stdin); + code = -1; + return; + } + acct[strlen(acct) - 1] = '\0'; + argv[3] = acct; argc++; + } + n = command("ACCT %s", argv[3]); + aflag++; + } + if (n != COMPLETE) { + fputs("Login failed.\n", ttyout); + return; + } + if (!aflag && argc == 4) { + (void)command("ACCT %s", argv[3]); + } + connected = -1; + getremoteinfo(); +} + +/* + * Print working directory on remote machine. + */ +/*VARARGS*/ +void +pwd(int argc, char *argv[]) +{ + + code = -1; + if (argc != 1) { + fprintf(ttyout, "usage: %s\n", argv[0]); + return; + } + if (! remotecwd[0]) + updateremotecwd(); + if (! remotecwd[0]) + fprintf(ttyout, "Unable to determine remote directory\n"); + else { + fprintf(ttyout, "Remote directory: %s\n", remotecwd); + code = 0; + } +} + +/* + * Print working directory on local machine. + */ +void +lpwd(int argc, char *argv[]) +{ + + code = -1; + if (argc != 1) { + fprintf(ttyout, "usage: %s\n", argv[0]); + return; + } + if (! localcwd[0]) + updatelocalcwd(); + if (! localcwd[0]) + fprintf(ttyout, "Unable to determine local directory\n"); + else { + fprintf(ttyout, "Local directory: %s\n", localcwd); + code = 0; + } +} + +/* + * Make a directory. + */ +void +makedir(int argc, char *argv[]) +{ + int r; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "directory-name"))) { + fprintf(ttyout, "usage: %s directory-name\n", argv[0]); + code = -1; + return; + } + r = command("MKD %s", argv[1]); + if (r == ERROR && code == 500) { + if (verbose) + fputs("MKD command not recognized, trying XMKD.\n", + ttyout); + r = command("XMKD %s", argv[1]); + } + if (r == COMPLETE) + dirchange = 1; +} + +/* + * Remove a directory. + */ +void +removedir(int argc, char *argv[]) +{ + int r; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "directory-name"))) { + fprintf(ttyout, "usage: %s directory-name\n", argv[0]); + code = -1; + return; + } + r = command("RMD %s", argv[1]); + if (r == ERROR && code == 500) { + if (verbose) + fputs("RMD command not recognized, trying XRMD.\n", + ttyout); + r = command("XRMD %s", argv[1]); + } + if (r == COMPLETE) + dirchange = 1; +} + +/* + * Send a line, verbatim, to the remote machine. + */ +void +quote(int argc, char *argv[]) +{ + + if (argc == 0 || + (argc == 1 && !another(&argc, &argv, "command line to send"))) { + fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); + code = -1; + return; + } + quote1("", argc, argv); +} + +/* + * Send a SITE command to the remote machine. The line + * is sent verbatim to the remote machine, except that the + * word "SITE" is added at the front. + */ +void +site(int argc, char *argv[]) +{ + + if (argc == 0 || + (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){ + fprintf(ttyout, "usage: %s line-to-send\n", argv[0]); + code = -1; + return; + } + quote1("SITE ", argc, argv); +} + +/* + * Turn argv[1..argc) into a space-separated string, then prepend initial text. + * Send the result as a one-line command and get response. + */ +void +quote1(const char *initial, int argc, char *argv[]) +{ + int i; + char buf[BUFSIZ]; /* must be >= sizeof(line) */ + + (void)strlcpy(buf, initial, sizeof(buf)); + for (i = 1; i < argc; i++) { + (void)strlcat(buf, argv[i], sizeof(buf)); + if (i < (argc - 1)) + (void)strlcat(buf, " ", sizeof(buf)); + } + if (command("%s", buf) == PRELIM) { + while (getreply(0) == PRELIM) + continue; + } + dirchange = 1; +} + +void +do_chmod(int argc, char *argv[]) +{ + + if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode"))) + goto usage; + if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { + usage: + fprintf(ttyout, "usage: %s mode remote-file\n", argv[0]); + code = -1; + return; + } + (void)command("SITE CHMOD %s %s", argv[1], argv[2]); +} + +#define COMMAND_1ARG(argc, argv, cmd) \ + if (argc == 1) \ + command(cmd); \ + else \ + command(cmd " %s", argv[1]) + +void +do_umask(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc == 0) { + fprintf(ttyout, "usage: %s [umask]\n", argv[0]); + code = -1; + return; + } + verbose = 1; + COMMAND_1ARG(argc, argv, "SITE UMASK"); + verbose = oldverbose; +} + +void +idlecmd(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc < 1 || argc > 2) { + fprintf(ttyout, "usage: %s [seconds]\n", argv[0]); + code = -1; + return; + } + verbose = 1; + COMMAND_1ARG(argc, argv, "SITE IDLE"); + verbose = oldverbose; +} + +/* + * Ask the other side for help. + */ +void +rmthelp(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + verbose = 1; + COMMAND_1ARG(argc, argv, "HELP"); + verbose = oldverbose; +} + +/* + * Terminate session and exit. + * May be called with 0, NULL. + */ +/*VARARGS*/ +void +quit(int argc, char *argv[]) +{ + + /* this may be called with argc == 0, argv == NULL */ + if (argc == 0 && argv != NULL) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + if (connected) + disconnect(0, NULL); + pswitch(1); + if (connected) + disconnect(0, NULL); + exit(0); +} + +/* + * Terminate session, but don't exit. + * May be called with 0, NULL. + */ +void +disconnect(int argc, char *argv[]) +{ + + /* this may be called with argc == 0, argv == NULL */ + if (argc == 0 && argv != NULL) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + if (!connected) + return; + (void)command("QUIT"); + cleanuppeer(); +} + +void +account(int argc, char *argv[]) +{ + char *ap; + + if (argc == 0 || argc > 2) { + fprintf(ttyout, "usage: %s [password]\n", argv[0]); + code = -1; + return; + } + else if (argc == 2) + ap = argv[1]; + else + ap = getpass("Account:"); + (void)command("ACCT %s", ap); +} + +sigjmp_buf abortprox; + +void +proxabort(int notused) +{ + + sigint_raised = 1; + alarmtimer(0); + if (!proxy) { + pswitch(1); + } + if (connected) { + proxflag = 1; + } + else { + proxflag = 0; + } + pswitch(0); + siglongjmp(abortprox, 1); +} + +void +doproxy(int argc, char *argv[]) +{ + struct cmd *c; + int cmdpos; + sigfunc oldintr; + + if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) { + fprintf(ttyout, "usage: %s command\n", argv[0]); + code = -1; + return; + } + c = getcmd(argv[1]); + if (c == (struct cmd *) -1) { + fputs("?Ambiguous command.\n", ttyout); + code = -1; + return; + } + if (c == 0) { + fputs("?Invalid command.\n", ttyout); + code = -1; + return; + } + if (!c->c_proxy) { + fputs("?Invalid proxy command.\n", ttyout); + code = -1; + return; + } + if (sigsetjmp(abortprox, 1)) { + code = -1; + return; + } + oldintr = xsignal(SIGINT, proxabort); + pswitch(1); + if (c->c_conn && !connected) { + fputs("Not connected.\n", ttyout); + pswitch(0); + (void)xsignal(SIGINT, oldintr); + code = -1; + return; + } + cmdpos = strcspn(line, " \t"); + if (cmdpos > 0) /* remove leading "proxy " from input buffer */ + memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); + argv[1] = c->c_name; + (*c->c_handler)(argc-1, argv+1); + if (connected) { + proxflag = 1; + } + else { + proxflag = 0; + } + pswitch(0); + (void)xsignal(SIGINT, oldintr); +} + +void +setcase(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &mcase, "Case mapping"); +} + +/* + * convert the given name to lower case if it's all upper case, into + * a static buffer which is returned to the caller + */ +static const char * +docase(char *dst, size_t dlen, const char *src) +{ + size_t i; + int dochange = 1; + + for (i = 0; src[i] != '\0' && i < dlen - 1; i++) { + dst[i] = src[i]; + if (islower((unsigned char)dst[i])) + dochange = 0; + } + dst[i] = '\0'; + + if (dochange) { + for (i = 0; dst[i] != '\0'; i++) + if (isupper((unsigned char)dst[i])) + dst[i] = tolower((unsigned char)dst[i]); + } + return dst; +} + +void +setcr(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); +} + +void +setntrans(int argc, char *argv[]) +{ + + if (argc == 0 || argc > 3) { + fprintf(ttyout, "usage: %s [inchars [outchars]]\n", argv[0]); + code = -1; + return; + } + if (argc == 1) { + ntflag = 0; + fputs("Ntrans off.\n", ttyout); + code = ntflag; + return; + } + ntflag++; + code = ntflag; + (void)strlcpy(ntin, argv[1], sizeof(ntin)); + if (argc == 2) { + ntout[0] = '\0'; + return; + } + (void)strlcpy(ntout, argv[2], sizeof(ntout)); +} + +static const char * +dotrans(char *dst, size_t dlen, const char *src) +{ + const char *cp1; + char *cp2 = dst; + size_t i, ostop; + + for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) + continue; + for (cp1 = src; *cp1; cp1++) { + int found = 0; + for (i = 0; *(ntin + i) && i < 16; i++) { + if (*cp1 == *(ntin + i)) { + found++; + if (i < ostop) { + *cp2++ = *(ntout + i); + if (cp2 - dst >= dlen - 1) + goto out; + } + break; + } + } + if (!found) { + *cp2++ = *cp1; + } + } +out: + *cp2 = '\0'; + return dst; +} + +void +setnmap(int argc, char *argv[]) +{ + char *cp; + + if (argc == 1) { + mapflag = 0; + fputs("Nmap off.\n", ttyout); + code = mapflag; + return; + } + if (argc == 0 || + (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { + fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]); + code = -1; + return; + } + mapflag = 1; + code = 1; + cp = strchr(altarg, ' '); + if (proxy) { + while(*++cp == ' ') + continue; + altarg = cp; + cp = strchr(altarg, ' '); + } + *cp = '\0'; + (void)strlcpy(mapin, altarg, MAXPATHLEN); + while (*++cp == ' ') + continue; + (void)strlcpy(mapout, cp, MAXPATHLEN); +} + +static const char * +domap(char *dst, size_t dlen, const char *src) +{ + const char *cp1 = src; + char *cp2 = mapin; + const char *tp[9], *te[9]; + int i, toks[9], toknum = 0, match = 1; + + for (i=0; i < 9; ++i) { + toks[i] = 0; + } + while (match && *cp1 && *cp2) { + switch (*cp2) { + case '\\': + if (*++cp2 != *cp1) { + match = 0; + } + break; + case '$': + if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { + if (*cp1 != *(++cp2+1)) { + toks[toknum = *cp2 - '1']++; + tp[toknum] = cp1; + while (*++cp1 && *(cp2+1) + != *cp1); + te[toknum] = cp1; + } + cp2++; + break; + } + /* FALLTHROUGH */ + default: + if (*cp2 != *cp1) { + match = 0; + } + break; + } + if (match && *cp1) { + cp1++; + } + if (match && *cp2) { + cp2++; + } + } + if (!match && *cp1) /* last token mismatch */ + { + toks[toknum] = 0; + } + cp2 = dst; + *cp2 = '\0'; + cp1 = mapout; + while (*cp1) { + match = 0; + switch (*cp1) { + case '\\': + if (*(cp1 + 1)) { + *cp2++ = *++cp1; + } + break; + case '[': +LOOP: + if (*++cp1 == '$' && + isdigit((unsigned char)*(cp1+1))) { + if (*++cp1 == '0') { + const char *cp3 = src; + + while (*cp3) { + *cp2++ = *cp3++; + } + match = 1; + } + else if (toks[toknum = *cp1 - '1']) { + const char *cp3 = tp[toknum]; + + while (cp3 != te[toknum]) { + *cp2++ = *cp3++; + } + match = 1; + } + } + else { + while (*cp1 && *cp1 != ',' && + *cp1 != ']') { + if (*cp1 == '\\') { + cp1++; + } + else if (*cp1 == '$' && + isdigit((unsigned char)*(cp1+1))) { + if (*++cp1 == '0') { + const char *cp3 = src; + + while (*cp3) { + *cp2++ = *cp3++; + } + } + else if (toks[toknum = + *cp1 - '1']) { + const char *cp3=tp[toknum]; + + while (cp3 != + te[toknum]) { + *cp2++ = *cp3++; + } + } + } + else if (*cp1) { + *cp2++ = *cp1++; + } + } + if (!*cp1) { + fputs( + "nmap: unbalanced brackets.\n", + ttyout); + return (src); + } + match = 1; + cp1--; + } + if (match) { + while (*++cp1 && *cp1 != ']') { + if (*cp1 == '\\' && *(cp1 + 1)) { + cp1++; + } + } + if (!*cp1) { + fputs( + "nmap: unbalanced brackets.\n", + ttyout); + return (src); + } + break; + } + switch (*++cp1) { + case ',': + goto LOOP; + case ']': + break; + default: + cp1--; + goto LOOP; + } + break; + case '$': + if (isdigit((unsigned char)*(cp1 + 1))) { + if (*++cp1 == '0') { + const char *cp3 = src; + + while (*cp3) { + *cp2++ = *cp3++; + } + } + else if (toks[toknum = *cp1 - '1']) { + const char *cp3 = tp[toknum]; + + while (cp3 != te[toknum]) { + *cp2++ = *cp3++; + } + } + break; + } + /* intentional drop through */ + default: + *cp2++ = *cp1; + break; + } + cp1++; + } + *cp2 = '\0'; + return *dst ? dst : src; +} + +void +setpassive(int argc, char *argv[]) +{ + + if (argc == 1) { + passivemode = !passivemode; + activefallback = passivemode; + } else if (argc != 2) { + passiveusage: + fprintf(ttyout, "usage: %s [ on | off | auto ]\n", argv[0]); + code = -1; + return; + } else if (strcasecmp(argv[1], "on") == 0) { + passivemode = 1; + activefallback = 0; + } else if (strcasecmp(argv[1], "off") == 0) { + passivemode = 0; + activefallback = 0; + } else if (strcasecmp(argv[1], "auto") == 0) { + passivemode = 1; + activefallback = 1; + } else + goto passiveusage; + fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", + onoff(passivemode), onoff(activefallback)); + code = passivemode; +} + +void +setepsv4(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &epsv4, + verbose ? "EPSV/EPRT on IPv4" : NULL); + epsv4bad = 0; +} + +void +setsunique(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &sunique, "Store unique"); +} + +void +setrunique(int argc, char *argv[]) +{ + + code = togglevar(argc, argv, &runique, "Receive unique"); +} + +int +parserate(int argc, char *argv[], int cmdlineopt) +{ + int dir, max, incr, showonly; + sigfunc oldusr1, oldusr2; + + if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) { + usage: + if (cmdlineopt) + fprintf(ttyout, + "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n", + argv[0]); + else + fprintf(ttyout, + "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n", + argv[0]); + return -1; + } + dir = max = incr = showonly = 0; +#define RATE_GET 1 +#define RATE_PUT 2 +#define RATE_ALL (RATE_GET | RATE_PUT) + + if (strcasecmp(argv[1], "all") == 0) + dir = RATE_ALL; + else if (strcasecmp(argv[1], "get") == 0) + dir = RATE_GET; + else if (strcasecmp(argv[1], "put") == 0) + dir = RATE_PUT; + else + goto usage; + + if (argc >= 3) { + if ((max = strsuftoi(argv[2])) < 0) + goto usage; + } else + showonly = 1; + + if (argc == 4) { + if ((incr = strsuftoi(argv[3])) <= 0) + goto usage; + } else + incr = DEFAULTINCR; + + oldusr1 = xsignal(SIGUSR1, SIG_IGN); + oldusr2 = xsignal(SIGUSR2, SIG_IGN); + if (dir & RATE_GET) { + if (!showonly) { + rate_get = max; + rate_get_incr = incr; + } + if (!cmdlineopt || verbose) + fprintf(ttyout, + "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", + onoff(rate_get), rate_get, rate_get_incr); + } + if (dir & RATE_PUT) { + if (!showonly) { + rate_put = max; + rate_put_incr = incr; + } + if (!cmdlineopt || verbose) + fprintf(ttyout, + "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", + onoff(rate_put), rate_put, rate_put_incr); + } + (void)xsignal(SIGUSR1, oldusr1); + (void)xsignal(SIGUSR2, oldusr2); + return 0; +} + +void +setrate(int argc, char *argv[]) +{ + + code = parserate(argc, argv, 0); +} + +/* change directory to parent directory */ +void +cdup(int argc, char *argv[]) +{ + int r; + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + r = command("CDUP"); + if (r == ERROR && code == 500) { + if (verbose) + fputs("CDUP command not recognized, trying XCUP.\n", + ttyout); + r = command("XCUP"); + } + if (r == COMPLETE) { + dirchange = 1; + updateremotecwd(); + } +} + +/* + * Restart transfer at specific point + */ +void +restart(int argc, char *argv[]) +{ + + if (argc == 0 || argc > 2) { + fprintf(ttyout, "usage: %s [restart-point]\n", argv[0]); + code = -1; + return; + } + if (! features[FEAT_REST_STREAM]) { + fprintf(ttyout, + "Restart is not supported by the remote server.\n"); + return; + } + if (argc == 2) { + off_t rp; + char *ep; + + rp = STRTOLL(argv[1], &ep, 10); + if (rp < 0 || *ep != '\0') + fprintf(ttyout, "restart: Invalid offset `%s'\n", + argv[1]); + else + restart_point = rp; + } + if (restart_point == 0) + fputs("No restart point defined.\n", ttyout); + else + fprintf(ttyout, + "Restarting at " LLF " for next get, put or append\n", + (LLT)restart_point); +} + +/* + * Show remote system type + */ +void +syst(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + verbose = 1; /* If we aren't verbose, this doesn't do anything! */ + (void)command("SYST"); + verbose = oldverbose; +} + +void +macdef(int argc, char *argv[]) +{ + char *tmp; + int c; + + if (argc == 0) + goto usage; + if (macnum == 16) { + fputs("Limit of 16 macros have already been defined.\n", + ttyout); + code = -1; + return; + } + if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { + usage: + fprintf(ttyout, "usage: %s macro_name\n", argv[0]); + code = -1; + return; + } + if (interactive) + fputs( + "Enter macro line by line, terminating it with a null line.\n", + ttyout); + (void)strlcpy(macros[macnum].mac_name, argv[1], + sizeof(macros[macnum].mac_name)); + if (macnum == 0) + macros[macnum].mac_start = macbuf; + else + macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; + tmp = macros[macnum].mac_start; + while (tmp != macbuf+4096) { + if ((c = getchar()) == EOF) { + fputs("macdef: end of file encountered.\n", ttyout); + code = -1; + return; + } + if ((*tmp = c) == '\n') { + if (tmp == macros[macnum].mac_start) { + macros[macnum++].mac_end = tmp; + code = 0; + return; + } + if (*(tmp-1) == '\0') { + macros[macnum++].mac_end = tmp - 1; + code = 0; + return; + } + *tmp = '\0'; + } + tmp++; + } + while (1) { + while ((c = getchar()) != '\n' && c != EOF) + /* LOOP */; + if (c == EOF || getchar() == '\n') { + fputs("Macro not defined - 4K buffer exceeded.\n", + ttyout); + code = -1; + return; + } + } +} + +/* + * Get size of file on remote machine + */ +void +sizecmd(int argc, char *argv[]) +{ + off_t size; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "remote-file"))) { + fprintf(ttyout, "usage: %s remote-file\n", argv[0]); + code = -1; + return; + } + size = remotesize(argv[1], 1); + if (size != -1) + fprintf(ttyout, + "%s\t" LLF "\n", argv[1], (LLT)size); + code = (size > 0); +} + +/* + * Get last modification time of file on remote machine + */ +void +modtime(int argc, char *argv[]) +{ + time_t mtime; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "remote-file"))) { + fprintf(ttyout, "usage: %s remote-file\n", argv[0]); + code = -1; + return; + } + mtime = remotemodtime(argv[1], 1); + if (mtime != -1) + fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime))); + code = (mtime > 0); +} + +/* + * Show status on remote machine + */ +void +rmtstatus(int argc, char *argv[]) +{ + + if (argc == 0) { + fprintf(ttyout, "usage: %s [remote-file]\n", argv[0]); + code = -1; + return; + } + COMMAND_1ARG(argc, argv, "STAT"); +} + +/* + * Get file if modtime is more recent than current file + */ +void +newer(int argc, char *argv[]) +{ + + if (getit(argc, argv, -1, "w")) + fprintf(ttyout, + "Local file \"%s\" is newer than remote file \"%s\".\n", + argv[2], argv[1]); +} + +/* + * Display one local file through $PAGER. + */ +void +lpage(int argc, char *argv[]) +{ + int len; + char *p, *pager, *locfile; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "local-file"))) { + fprintf(ttyout, "usage: %s local-file\n", argv[0]); + code = -1; + return; + } + if ((locfile = globulize(argv[1])) == NULL) { + code = -1; + return; + } + p = getoptionvalue("pager"); + if (EMPTYSTRING(p)) + p = DEFAULTPAGER; + len = strlen(p) + strlen(locfile) + 2; + pager = xmalloc(len); + (void)strlcpy(pager, p, len); + (void)strlcat(pager, " ", len); + (void)strlcat(pager, locfile, len); + system(pager); + code = 0; + (void)free(pager); + (void)free(locfile); +} + +/* + * Display one remote file through $PAGER. + */ +void +page(int argc, char *argv[]) +{ + int ohash, orestart_point, overbose, len; + char *p, *pager; + + if (argc == 0 || argc > 2 || + (argc == 1 && !another(&argc, &argv, "remote-file"))) { + fprintf(ttyout, "usage: %s remote-file\n", argv[0]); + code = -1; + return; + } + p = getoptionvalue("pager"); + if (EMPTYSTRING(p)) + p = DEFAULTPAGER; + len = strlen(p) + 2; + pager = xmalloc(len); + pager[0] = '|'; + (void)strlcpy(pager + 1, p, len - 1); + + ohash = hash; + orestart_point = restart_point; + overbose = verbose; + hash = restart_point = verbose = 0; + recvrequest("RETR", pager, argv[1], "r+", 1, 0); + hash = ohash; + restart_point = orestart_point; + verbose = overbose; + (void)free(pager); +} + +/* + * Set the socket send or receive buffer size. + */ +void +setxferbuf(int argc, char *argv[]) +{ + int size, dir; + + if (argc != 2) { + usage: + fprintf(ttyout, "usage: %s size\n", argv[0]); + code = -1; + return; + } + if (strcasecmp(argv[0], "sndbuf") == 0) + dir = RATE_PUT; + else if (strcasecmp(argv[0], "rcvbuf") == 0) + dir = RATE_GET; + else if (strcasecmp(argv[0], "xferbuf") == 0) + dir = RATE_ALL; + else + goto usage; + + if ((size = strsuftoi(argv[1])) == -1) + goto usage; + + if (size == 0) { + fprintf(ttyout, "%s: size must be positive.\n", argv[0]); + goto usage; + } + + if (dir & RATE_PUT) + sndbuf_size = size; + if (dir & RATE_GET) + rcvbuf_size = size; + fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n", + sndbuf_size, rcvbuf_size); + code = 0; +} + +/* + * Set or display options (defaults are provided by various env vars) + */ +void +setoption(int argc, char *argv[]) +{ + struct option *o; + + code = -1; + if (argc == 0 || (argc != 1 && argc != 3)) { + fprintf(ttyout, "usage: %s [option value]\n", argv[0]); + return; + } + +#define OPTIONINDENT ((int) sizeof("http_proxy")) + if (argc == 1) { + for (o = optiontab; o->name != NULL; o++) { + fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, + o->name, o->value ? o->value : ""); + } + } else { + o = getoption(argv[1]); + if (o == NULL) { + fprintf(ttyout, "No such option `%s'.\n", argv[1]); + return; + } + FREEPTR(o->value); + o->value = xstrdup(argv[2]); + if (verbose) + fprintf(ttyout, "Setting `%s' to `%s'.\n", + o->name, o->value); + } + code = 0; +} + +/* + * Unset an option + */ +void +unsetoption(int argc, char *argv[]) +{ + struct option *o; + + code = -1; + if (argc == 0 || argc != 2) { + fprintf(ttyout, "usage: %s option\n", argv[0]); + return; + } + + o = getoption(argv[1]); + if (o == NULL) { + fprintf(ttyout, "No such option `%s'.\n", argv[1]); + return; + } + FREEPTR(o->value); + fprintf(ttyout, "Unsetting `%s'.\n", o->name); + code = 0; +} + +/* + * Display features supported by the remote host. + */ +void +feat(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc == 0) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + if (! features[FEAT_FEAT]) { + fprintf(ttyout, + "FEAT is not supported by the remote server.\n"); + return; + } + verbose = 1; /* If we aren't verbose, this doesn't do anything! */ + (void)command("FEAT"); + verbose = oldverbose; +} + +void +mlst(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc < 1 || argc > 2) { + fprintf(ttyout, "usage: %s [remote-path]\n", argv[0]); + code = -1; + return; + } + if (! features[FEAT_MLST]) { + fprintf(ttyout, + "MLST is not supported by the remote server.\n"); + return; + } + verbose = 1; /* If we aren't verbose, this doesn't do anything! */ + COMMAND_1ARG(argc, argv, "MLST"); + verbose = oldverbose; +} + +void +opts(int argc, char *argv[]) +{ + int oldverbose = verbose; + + if (argc < 2 || argc > 3) { + fprintf(ttyout, "usage: %s command [options]\n", argv[0]); + code = -1; + return; + } + if (! features[FEAT_FEAT]) { + fprintf(ttyout, + "OPTS is not supported by the remote server.\n"); + return; + } + verbose = 1; /* If we aren't verbose, this doesn't do anything! */ + if (argc == 2) + command("OPTS %s", argv[1]); + else + command("OPTS %s %s", argv[1], argv[2]); + verbose = oldverbose; +} diff --git a/src/bin/network/ftp/cmdtab.c b/src/bin/network/ftp/cmdtab.c new file mode 100644 index 0000000000..17df630c17 --- /dev/null +++ b/src/bin/network/ftp/cmdtab.c @@ -0,0 +1,302 @@ +/* $NetBSD: cmdtab.c,v 1.44 2005/04/11 01:49:31 lukem Exp $ */ + +/*- + * Copyright (c) 1996-2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include "ftp_var.h" + +/* + * User FTP -- Command Tables. + */ + +#define HSTR static const char + +#ifndef NO_HELP +HSTR accounthelp[] = "send account command to remote server"; +HSTR appendhelp[] = "append to a file"; +HSTR asciihelp[] = "set ascii transfer type"; +HSTR beephelp[] = "beep when command completed"; +HSTR binaryhelp[] = "set binary transfer type"; +HSTR casehelp[] = "toggle mget upper/lower case id mapping"; +HSTR cdhelp[] = "change remote working directory"; +HSTR cduphelp[] = "change remote working directory to parent directory"; +HSTR chmodhelp[] = "change file permissions of remote file"; +HSTR connecthelp[] = "connect to remote ftp server"; +HSTR crhelp[] = "toggle carriage return stripping on ascii gets"; +HSTR debughelp[] = "toggle/set debugging mode"; +HSTR deletehelp[] = "delete remote file"; +HSTR disconhelp[] = "terminate ftp session"; +HSTR domachelp[] = "execute macro"; +HSTR edithelp[] = "toggle command line editing"; +HSTR epsv4help[] = "toggle use of EPSV/EPRT on IPv4 ftp"; +HSTR feathelp[] = "show FEATures supported by remote system"; +HSTR formhelp[] = "set file transfer format"; +HSTR gatehelp[] = "toggle gate-ftp; specify host[:port] to change proxy"; +HSTR globhelp[] = "toggle metacharacter expansion of local file names"; +HSTR hashhelp[] = "toggle printing `#' marks; specify number to set size"; +HSTR helphelp[] = "print local help information"; +HSTR idlehelp[] = "get (set) idle timer on remote side"; +HSTR lcdhelp[] = "change local working directory"; +HSTR lpagehelp[] = "view a local file through your pager"; +HSTR lpwdhelp[] = "print local working directory"; +HSTR lshelp[] = "list contents of remote path"; +HSTR macdefhelp[] = "define a macro"; +HSTR mdeletehelp[] = "delete multiple files"; +HSTR mgethelp[] = "get multiple files"; +HSTR mregethelp[] = "get multiple files restarting at end of local file"; +HSTR fgethelp[] = "get files using a localfile as a source of names"; +HSTR mkdirhelp[] = "make directory on the remote machine"; +HSTR mlshelp[] = "list contents of multiple remote directories"; +HSTR mlsdhelp[] = "list contents of remote directory in a machine " + "parsable form"; +HSTR mlsthelp[] = "list remote path in a machine parsable form"; +HSTR modehelp[] = "set file transfer mode"; +HSTR modtimehelp[] = "show last modification time of remote file"; +HSTR mputhelp[] = "send multiple files"; +HSTR newerhelp[] = "get file if remote file is newer than local file "; +HSTR nmaphelp[] = "set templates for default file name mapping"; +HSTR ntranshelp[] = "set translation table for default file name mapping"; +HSTR optshelp[] = "show or set options for remote commands"; +HSTR pagehelp[] = "view a remote file through your pager"; +HSTR passivehelp[] = "toggle use of passive transfer mode"; +HSTR plshelp[] = "list contents of remote path through your pager"; +HSTR pmlsdhelp[] = "list contents of remote directory in a machine " + "parsable form through your pager"; +HSTR porthelp[] = "toggle use of PORT/LPRT cmd for each data connection"; +HSTR preservehelp[] ="toggle preservation of modification time of " + "retrieved files"; +HSTR progresshelp[] ="toggle transfer progress meter"; +HSTR prompthelp[] = "force interactive prompting on multiple commands"; +HSTR proxyhelp[] = "issue command on alternate connection"; +HSTR pwdhelp[] = "print working directory on remote machine"; +HSTR quithelp[] = "terminate ftp session and exit"; +HSTR quotehelp[] = "send arbitrary ftp command"; +HSTR ratehelp[] = "set transfer rate limit (in bytes/second)"; +HSTR receivehelp[] = "receive file"; +HSTR regethelp[] = "get file restarting at end of local file"; +HSTR remotehelp[] = "get help from remote server"; +HSTR renamehelp[] = "rename file"; +HSTR resethelp[] = "clear queued command replies"; +HSTR restarthelp[]= "restart file transfer at bytecount"; +HSTR rmdirhelp[] = "remove directory on the remote machine"; +HSTR rmtstatushelp[]="show status of remote machine"; +HSTR runiquehelp[] = "toggle store unique for local files"; +HSTR sendhelp[] = "send one file"; +HSTR sethelp[] = "set or display options"; +HSTR shellhelp[] = "escape to the shell"; +HSTR sitehelp[] = "send site specific command to remote server\n" + "\t\tTry \"rhelp site\" or \"site help\" " + "for more information"; +HSTR sizecmdhelp[] = "show size of remote file"; +HSTR statushelp[] = "show current status"; +HSTR structhelp[] = "set file transfer structure"; +HSTR suniquehelp[] = "toggle store unique on remote machine"; +HSTR systemhelp[] = "show remote system type"; +HSTR tenexhelp[] = "set tenex file transfer type"; +HSTR tracehelp[] = "toggle packet tracing"; +HSTR typehelp[] = "set file transfer type"; +HSTR umaskhelp[] = "get (set) umask on remote side"; +HSTR unsethelp[] = "unset an option"; +HSTR usagehelp[] = "show command usage"; +HSTR userhelp[] = "send new user information"; +HSTR verbosehelp[] = "toggle verbose mode"; +HSTR xferbufhelp[] = "set socket send/receive buffer size"; +#endif + +HSTR empty[] = ""; + +#ifdef NO_HELP +#define H(x) empty +#else +#define H(x) x +#endif + +#ifdef NO_EDITCOMPLETE +#define CMPL(x) +#define CMPL0 +#else /* !NO_EDITCOMPLETE */ +#define CMPL(x) #x, +#define CMPL0 empty, +#endif /* !NO_EDITCOMPLETE */ + +struct cmd cmdtab[] = { + { "!", H(shellhelp), 0, 0, 0, CMPL0 shell }, + { "$", H(domachelp), 1, 0, 0, CMPL0 domacro }, + { "account", H(accounthelp), 0, 1, 1, CMPL0 account}, + { "append", H(appendhelp), 1, 1, 1, CMPL(lr) put }, + { "ascii", H(asciihelp), 0, 1, 1, CMPL0 setascii }, + { "bell", H(beephelp), 0, 0, 0, CMPL0 setbell }, + { "binary", H(binaryhelp), 0, 1, 1, CMPL0 setbinary }, + { "bye", H(quithelp), 0, 0, 0, CMPL0 quit }, + { "case", H(casehelp), 0, 0, 1, CMPL0 setcase }, + { "cd", H(cdhelp), 0, 1, 1, CMPL(r) cd }, + { "cdup", H(cduphelp), 0, 1, 1, CMPL0 cdup }, + { "chmod", H(chmodhelp), 0, 1, 1, CMPL(nr) do_chmod }, + { "close", H(disconhelp), 0, 1, 1, CMPL0 disconnect }, + { "cr", H(crhelp), 0, 0, 0, CMPL0 setcr }, + { "debug", H(debughelp), 0, 0, 0, CMPL0 setdebug }, + { "delete", H(deletehelp), 0, 1, 1, CMPL(r) delete }, + { "dir", H(lshelp), 1, 1, 1, CMPL(rl) ls }, + { "disconnect", H(disconhelp), 0, 1, 1, CMPL0 disconnect }, + { "edit", H(edithelp), 0, 0, 0, CMPL0 setedit }, + { "epsv4", H(epsv4help), 0, 0, 0, CMPL0 setepsv4 }, + { "exit", H(quithelp), 0, 0, 0, CMPL0 quit }, + { "features", H(feathelp), 0, 1, 1, CMPL0 feat }, + { "fget", H(fgethelp), 1, 1, 1, CMPL(l) fget }, + { "form", H(formhelp), 0, 1, 1, CMPL0 setform }, + { "ftp", H(connecthelp), 0, 0, 1, CMPL0 setpeer }, + { "gate", H(gatehelp), 0, 0, 0, CMPL0 setgate }, + { "get", H(receivehelp), 1, 1, 1, CMPL(rl) get }, + { "glob", H(globhelp), 0, 0, 0, CMPL0 setglob }, + { "hash", H(hashhelp), 0, 0, 0, CMPL0 sethash }, + { "help", H(helphelp), 0, 0, 1, CMPL(C) help }, + { "idle", H(idlehelp), 0, 1, 1, CMPL0 idlecmd }, + { "image", H(binaryhelp), 0, 1, 1, CMPL0 setbinary }, + { "lcd", H(lcdhelp), 0, 0, 0, CMPL(l) lcd }, + { "less", H(pagehelp), 1, 1, 1, CMPL(r) page }, + { "lpage", H(lpagehelp), 0, 0, 0, CMPL(l) lpage }, + { "lpwd", H(lpwdhelp), 0, 0, 0, CMPL0 lpwd }, + { "ls", H(lshelp), 1, 1, 1, CMPL(rl) ls }, + { "macdef", H(macdefhelp), 0, 0, 0, CMPL0 macdef }, + { "mdelete", H(mdeletehelp), 1, 1, 1, CMPL(R) mdelete }, + { "mdir", H(mlshelp), 1, 1, 1, CMPL(R) mls }, + { "mget", H(mgethelp), 1, 1, 1, CMPL(R) mget }, + { "mkdir", H(mkdirhelp), 0, 1, 1, CMPL(r) makedir }, + { "mls", H(mlshelp), 1, 1, 1, CMPL(R) mls }, + { "mlsd", H(mlsdhelp), 1, 1, 1, CMPL(r) ls }, + { "mlst", H(mlsthelp), 1, 1, 1, CMPL(r) mlst }, + { "mode", H(modehelp), 0, 1, 1, CMPL0 setftmode }, + { "modtime", H(modtimehelp), 0, 1, 1, CMPL(r) modtime }, + { "more", H(pagehelp), 1, 1, 1, CMPL(r) page }, + { "mput", H(mputhelp), 1, 1, 1, CMPL(L) mput }, + { "mreget", H(mregethelp), 1, 1, 1, CMPL(R) mget }, + { "msend", H(mputhelp), 1, 1, 1, CMPL(L) mput }, + { "newer", H(newerhelp), 1, 1, 1, CMPL(r) newer }, + { "nlist", H(lshelp), 1, 1, 1, CMPL(rl) ls }, + { "nmap", H(nmaphelp), 0, 0, 1, CMPL0 setnmap }, + { "ntrans", H(ntranshelp), 0, 0, 1, CMPL0 setntrans }, + { "open", H(connecthelp), 0, 0, 1, CMPL0 setpeer }, + { "page", H(pagehelp), 1, 1, 1, CMPL(r) page }, + { "passive", H(passivehelp), 0, 0, 0, CMPL0 setpassive }, + { "pdir", H(plshelp), 1, 1, 1, CMPL(r) ls }, + { "pls", H(plshelp), 1, 1, 1, CMPL(r) ls }, + { "pmlsd", H(pmlsdhelp), 1, 1, 1, CMPL(r) ls }, + { "preserve", H(preservehelp),0, 0, 0, CMPL0 setpreserve }, + { "progress", H(progresshelp),0, 0, 0, CMPL0 setprogress }, + { "prompt", H(prompthelp), 0, 0, 0, CMPL0 setprompt }, + { "proxy", H(proxyhelp), 0, 0, 1, CMPL(c) doproxy }, + { "put", H(sendhelp), 1, 1, 1, CMPL(lr) put }, + { "pwd", H(pwdhelp), 0, 1, 1, CMPL0 pwd }, + { "quit", H(quithelp), 0, 0, 0, CMPL0 quit }, + { "quote", H(quotehelp), 1, 1, 1, CMPL0 quote }, + { "rate", H(ratehelp), 0, 0, 0, CMPL0 setrate }, + { "rcvbuf", H(xferbufhelp), 0, 0, 0, CMPL0 setxferbuf }, + { "recv", H(receivehelp), 1, 1, 1, CMPL(rl) get }, + { "reget", H(regethelp), 1, 1, 1, CMPL(rl) reget }, + { "remopts", H(optshelp), 0, 1, 1, CMPL0 opts }, + { "rename", H(renamehelp), 0, 1, 1, CMPL(rr) renamefile }, + { "reset", H(resethelp), 0, 1, 1, CMPL0 reset }, + { "restart", H(restarthelp), 1, 1, 1, CMPL0 restart }, + { "rhelp", H(remotehelp), 0, 1, 1, CMPL0 rmthelp }, + { "rmdir", H(rmdirhelp), 0, 1, 1, CMPL(r) removedir }, + { "rstatus", H(rmtstatushelp),0, 1, 1, CMPL(r) rmtstatus }, + { "runique", H(runiquehelp), 0, 0, 1, CMPL0 setrunique }, + { "send", H(sendhelp), 1, 1, 1, CMPL(lr) put }, + { "sendport", H(porthelp), 0, 0, 0, CMPL0 setport }, + { "set", H(sethelp), 0, 0, 0, CMPL(o) setoption }, + { "site", H(sitehelp), 0, 1, 1, CMPL0 site }, + { "size", H(sizecmdhelp), 1, 1, 1, CMPL(r) sizecmd }, + { "sndbuf", H(xferbufhelp), 0, 0, 0, CMPL0 setxferbuf }, + { "status", H(statushelp), 0, 0, 1, CMPL0 status }, + { "struct", H(structhelp), 0, 1, 1, CMPL0 setstruct }, + { "sunique", H(suniquehelp), 0, 0, 1, CMPL0 setsunique }, + { "system", H(systemhelp), 0, 1, 1, CMPL0 syst }, + { "tenex", H(tenexhelp), 0, 1, 1, CMPL0 settenex }, + { "throttle", H(ratehelp), 0, 0, 0, CMPL0 setrate }, + { "trace", H(tracehelp), 0, 0, 0, CMPL0 settrace }, + { "type", H(typehelp), 0, 1, 1, CMPL0 settype }, + { "umask", H(umaskhelp), 0, 1, 1, CMPL0 do_umask }, + { "unset", H(unsethelp), 0, 0, 0, CMPL(o) unsetoption }, + { "usage", H(usagehelp), 0, 0, 1, CMPL(C) help }, + { "user", H(userhelp), 0, 1, 1, CMPL0 user }, + { "verbose", H(verbosehelp), 0, 0, 0, CMPL0 setverbose }, + { "xferbuf", H(xferbufhelp), 0, 0, 0, CMPL0 setxferbuf }, + { "?", H(helphelp), 0, 0, 1, CMPL(C) help }, + { 0 }, +}; + +struct option optiontab[] = { + { "anonpass", NULL }, + { "ftp_proxy", NULL }, + { "http_proxy", NULL }, + { "no_proxy", NULL }, + { "pager", NULL }, + { "prompt", NULL }, + { "rprompt", NULL }, + { 0 }, +}; diff --git a/src/bin/network/ftp/complete.c b/src/bin/network/ftp/complete.c new file mode 100644 index 0000000000..e30aa79ed0 --- /dev/null +++ b/src/bin/network/ftp/complete.c @@ -0,0 +1,432 @@ +/* $NetBSD: complete.c,v 1.38 2000/05/01 10:35:17 lukem Exp $ */ + +/*- + * Copyright (c) 1997-2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * FTP user program - command and file completion routines + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +#ifndef NO_EDITCOMPLETE + +static int comparstr (const void *, const void *); +static unsigned char complete_ambiguous (char *, int, StringList *); +static unsigned char complete_command (char *, int); +static unsigned char complete_local (char *, int); +static unsigned char complete_option (char *, int); +static unsigned char complete_remote (char *, int); + +static int +comparstr(const void *a, const void *b) +{ + return (strcmp(*(const char **)a, *(const char **)b)); +} + +/* + * Determine if complete is ambiguous. If unique, insert. + * If no choices, error. If unambiguous prefix, insert that. + * Otherwise, list choices. words is assumed to be filtered + * to only contain possible choices. + * Args: + * word word which started the match + * list list by default + * words stringlist containing possible matches + * Returns a result as per el_set(EL_ADDFN, ...) + */ +static unsigned char +complete_ambiguous(char *word, int list, StringList *words) +{ + char insertstr[MAXPATHLEN]; + char *lastmatch, *p; + int i, j; + size_t matchlen, wordlen; + + wordlen = strlen(word); + if (words->sl_cur == 0) + return (CC_ERROR); /* no choices available */ + + if (words->sl_cur == 1) { /* only once choice available */ + p = words->sl_str[0] + wordlen; + if (*p == '\0') /* at end of word? */ + return (CC_REFRESH); + ftpvis(insertstr, sizeof(insertstr), p, strlen(p)); + if (el_insertstr(el, insertstr) == -1) + return (CC_ERROR); + else + return (CC_REFRESH); + } + + if (!list) { + matchlen = 0; + lastmatch = words->sl_str[0]; + matchlen = strlen(lastmatch); + for (i = 1 ; i < words->sl_cur ; i++) { + for (j = wordlen ; j < strlen(words->sl_str[i]); j++) + if (lastmatch[j] != words->sl_str[i][j]) + break; + if (j < matchlen) + matchlen = j; + } + if (matchlen > wordlen) { + ftpvis(insertstr, sizeof(insertstr), + lastmatch + wordlen, matchlen - wordlen); + if (el_insertstr(el, insertstr) == -1) + return (CC_ERROR); + else + return (CC_REFRESH_BEEP); + } + } + + putc('\n', ttyout); + qsort(words->sl_str, words->sl_cur, sizeof(char *), comparstr); + list_vertical(words); + return (CC_REDISPLAY); +} + +/* + * Complete a command + */ +static unsigned char +complete_command(char *word, int list) +{ + struct cmd *c; + StringList *words; + size_t wordlen; + unsigned char rv; + + words = xsl_init(); + wordlen = strlen(word); + + for (c = cmdtab; c->c_name != NULL; c++) { + if (wordlen > strlen(c->c_name)) + continue; + if (strncmp(word, c->c_name, wordlen) == 0) + xsl_add(words, c->c_name); + } + + rv = complete_ambiguous(word, list, words); + if (rv == CC_REFRESH) { + if (el_insertstr(el, " ") == -1) + rv = CC_ERROR; + } + sl_free(words, 0); + return (rv); +} + +/* + * Complete a local file + */ +static unsigned char +complete_local(char *word, int list) +{ + StringList *words; + char dir[MAXPATHLEN]; + char *file; + DIR *dd; + struct dirent *dp; + unsigned char rv; + size_t len; + + if ((file = strrchr(word, '/')) == NULL) { + dir[0] = '.'; + dir[1] = '\0'; + file = word; + } else { + if (file == word) { + dir[0] = '/'; + dir[1] = '\0'; + } else + (void)strlcpy(dir, word, file - word + 1); + file++; + } + if (dir[0] == '~') { + char *p; + + if ((p = globulize(dir)) == NULL) + return (CC_ERROR); + (void)strlcpy(dir, p, sizeof(dir)); + free(p); + } + + if ((dd = opendir(dir)) == NULL) + return (CC_ERROR); + + words = xsl_init(); + len = strlen(file); + + for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) { + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + +#if defined(DIRENT_MISSING_D_NAMLEN) + if (len > strlen(dp->d_name)) + continue; +#else + if (len > dp->d_namlen) + continue; +#endif + if (strncmp(file, dp->d_name, len) == 0) { + char *tcp; + + tcp = xstrdup(dp->d_name); + xsl_add(words, tcp); + } + } + closedir(dd); + + rv = complete_ambiguous(file, list, words); + if (rv == CC_REFRESH) { + struct stat sb; + char path[MAXPATHLEN]; + + (void)strlcpy(path, dir, sizeof(path)); + (void)strlcat(path, "/", sizeof(path)); + (void)strlcat(path, words->sl_str[0], sizeof(path)); + + if (stat(path, &sb) >= 0) { + char suffix[2] = " "; + + if (S_ISDIR(sb.st_mode)) + suffix[0] = '/'; + if (el_insertstr(el, suffix) == -1) + rv = CC_ERROR; + } + } + sl_free(words, 1); + return (rv); +} +/* + * Complete an option + */ +static unsigned char +complete_option(char *word, int list) +{ + struct option *o; + StringList *words; + size_t wordlen; + unsigned char rv; + + words = xsl_init(); + wordlen = strlen(word); + + for (o = optiontab; o->name != NULL; o++) { + if (wordlen > strlen(o->name)) + continue; + if (strncmp(word, o->name, wordlen) == 0) + xsl_add(words, o->name); + } + + rv = complete_ambiguous(word, list, words); + if (rv == CC_REFRESH) { + if (el_insertstr(el, " ") == -1) + rv = CC_ERROR; + } + sl_free(words, 0); + return (rv); +} + +/* + * Complete a remote file + */ +static unsigned char +complete_remote(char *word, int list) +{ + static StringList *dirlist; + static char lastdir[MAXPATHLEN]; + StringList *words; + char dir[MAXPATHLEN]; + char *file, *cp; + int i; + unsigned char rv; + + char *dummyargv[] = { "complete", NULL, NULL }; + dummyargv[1] = dir; + + if ((file = strrchr(word, '/')) == NULL) { + dir[0] = '\0'; + file = word; + } else { + cp = file; + while (*cp == '/' && cp > word) + cp--; + (void)strlcpy(dir, word, cp - word + 2); + file++; + } + + if (dirchange || dirlist == NULL || + strcmp(dir, lastdir) != 0) { /* dir not cached */ + char *emesg; + + if (dirlist != NULL) + sl_free(dirlist, 1); + dirlist = xsl_init(); + + mflag = 1; + emesg = NULL; + while ((cp = remglob(dummyargv, 0, &emesg)) != NULL) { + char *tcp; + + if (!mflag) + continue; + if (*cp == '\0') { + mflag = 0; + continue; + } + tcp = strrchr(cp, '/'); + if (tcp) + tcp++; + else + tcp = cp; + tcp = xstrdup(tcp); + xsl_add(dirlist, tcp); + } + if (emesg != NULL) { + fprintf(ttyout, "\n%s\n", emesg); + return (CC_REDISPLAY); + } + (void)strlcpy(lastdir, dir, sizeof(lastdir)); + dirchange = 0; + } + + words = xsl_init(); + for (i = 0; i < dirlist->sl_cur; i++) { + cp = dirlist->sl_str[i]; + if (strlen(file) > strlen(cp)) + continue; + if (strncmp(file, cp, strlen(file)) == 0) + xsl_add(words, cp); + } + rv = complete_ambiguous(file, list, words); + sl_free(words, 0); + return (rv); +} + +/* + * Generic complete routine + */ +unsigned char +complete(EditLine *el, int ch) +{ + static char word[FTPBUFLEN]; + static int lastc_argc, lastc_argo; + + struct cmd *c; + const LineInfo *lf; + int celems, dolist, cmpltype; + size_t len; + + lf = el_line(el); + len = lf->lastchar - lf->buffer; + if (len >= sizeof(line)) + return (CC_ERROR); + (void)strlcpy(line, lf->buffer, len + 1); + cursor_pos = line + (lf->cursor - lf->buffer); + lastc_argc = cursor_argc; /* remember last cursor pos */ + lastc_argo = cursor_argo; + makeargv(); /* build argc/argv of current line */ + + if (cursor_argo >= sizeof(word)) + return (CC_ERROR); + + dolist = 0; + /* if cursor and word is same, list alternatives */ + if (lastc_argc == cursor_argc && lastc_argo == cursor_argo + && strncmp(word, margv[cursor_argc] ? margv[cursor_argc] : "", + cursor_argo) == 0) + dolist = 1; + else if (cursor_argc < margc) + (void)strlcpy(word, margv[cursor_argc], cursor_argo + 1); + word[cursor_argo] = '\0'; + + if (cursor_argc == 0) + return (complete_command(word, dolist)); + + c = getcmd(margv[0]); + if (c == (struct cmd *)-1 || c == 0) + return (CC_ERROR); + celems = strlen(c->c_complete); + + /* check for 'continuation' completes (which are uppercase) */ + if ((cursor_argc > celems) && (celems > 0) + && isupper((unsigned char) c->c_complete[celems-1])) + cursor_argc = celems; + + if (cursor_argc > celems) + return (CC_ERROR); + + cmpltype = c->c_complete[cursor_argc - 1]; + switch (cmpltype) { + case 'c': /* command complete */ + case 'C': + return (complete_command(word, dolist)); + case 'l': /* local complete */ + case 'L': + return (complete_local(word, dolist)); + case 'n': /* no complete */ + case 'N': /* no complete */ + return (CC_ERROR); + case 'o': /* local complete */ + case 'O': + return (complete_option(word, dolist)); + case 'r': /* remote complete */ + case 'R': + if (connected != -1) { + fputs("\nMust be logged in to complete.\n", + ttyout); + return (CC_REDISPLAY); + } + return (complete_remote(word, dolist)); + default: + errx(1, "unknown complete type `%c'", cmpltype); + return (CC_ERROR); + } + /* NOTREACHED */ +} + +#endif /* !NO_EDITCOMPLETE */ diff --git a/src/bin/network/ftp/config.h b/src/bin/network/ftp/config.h new file mode 100644 index 0000000000..aedb48a593 --- /dev/null +++ b/src/bin/network/ftp/config.h @@ -0,0 +1,276 @@ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ +/* $Id: config.h.in,v 1.28 2002/06/10 08:10:33 lukem Exp $ */ + + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* #undef _ALL_SOURCE */ +#endif + +/* Define if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ + +/* Define if the `getpgrp' function takes no argument. */ +#define GETPGRP_VOID 1 + +/* Define if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Define if your Fortran 77 compiler doesn't accept -c and -o together. */ +/* #undef F77_NO_MINUS_C_MINUS_O */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to the type of arg1 for select(). */ +/* #undef SELECT_TYPE_ARG1 */ + +/* Define to the type of args 2, 3 and 4 for select(). */ +/* #undef SELECT_TYPE_ARG234 */ + +/* Define to the type of arg5 for select(). */ +/* #undef SELECT_TYPE_ARG5 */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define if the closedir function returns void instead of int. */ +/* #undef VOID_CLOSEDIR */ + +/* The number of bytes in a off_t. */ +#define SIZEOF_OFF_T 8 + +/* Define if you have the err function. */ +/* #undef HAVE_ERR */ + +/* Define if you have the fgetln function. */ +#define HAVE_FGETLN 1 + +/* Define if you have the fparseln function. */ +/* #undef HAVE_FPARSELN */ + +/* Define if you have the fseeko function. */ +#define HAVE_FSEEKO 1 + +/* Define if you have the getaddrinfo function. */ +/* #undef HAVE_GETADDRINFO */ + +/* Define if you have the gethostbyname2 function. */ +/* #undef HAVE_GETHOSTBYNAME2 */ + +/* Define if you have the getnameinfo function. */ +/* #undef HAVE_GETNAMEINFO */ + +/* Define if you have the getpassphrase function. */ +/* #undef HAVE_GETPASSPHRASE */ + +/* Define if you have the getpgrp function. */ +#define HAVE_GETPGRP 1 + +/* Define if you have the inet_ntop function. */ +/* #undef HAVE_INET_NTOP */ + +/* Define if you have the inet_pton function. */ +/* #undef HAVE_INET_PTON */ + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the mkstemp function. */ +#define HAVE_MKSTEMP 1 + +/* Define if you have the poll function. */ +/* #undef HAVE_POLL */ + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the setprogname function. */ +/* #undef HAVE_SETPROGNAME */ + +/* Define if you have the sl_init function. */ +/* #undef HAVE_SL_INIT */ + +/* Define if you have the snprintf function. */ +#define HAVE_SNPRINTF 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strlcat function. */ +#define HAVE_STRLCAT 1 + +/* Define if you have the strlcpy function. */ +#define HAVE_STRLCPY 1 + +/* Define if you have the strptime function. */ +/* #undef HAVE_STRPTIME */ + +/* Define if you have the strsep function. */ +/* #undef HAVE_STRSEP */ + +/* Define if you have the strtoll function. */ +#define HAVE_STRTOLL 1 + +/* Define if you have the strunvis function. */ +/* #undef HAVE_STRUNVIS */ + +/* Define if you have the strvis function. */ +/* #undef HAVE_STRVIS */ + +/* Define if you have the timegm function. */ +/* #undef HAVE_TIMEGM */ + +/* Define if you have the usleep function. */ +/* #undef HAVE_USLEEP */ + +/* Define if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the header file. */ +#define HAVE_ERR_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_PATHS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_POLL_H */ + +/* Define if you have the header file. */ +#define HAVE_REGEX_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_POLL_H */ + +/* Define if you have the header file. */ +#define HAVE_TERMCAP_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_UTIL_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_VIS_H */ + +/* Define if you have the nsl library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define if you have the socket library (-lsocket). */ +#define HAVE_LIBSOCKET 1 + +/* Define if you have the tinfo library (-ltinfo). */ +/* #undef HAVE_LIBTINFO */ + +/* Define if you have the util library (-lutil). */ +/* #undef HAVE_LIBUTIL */ + +/* Define if your compiler supports `long long' */ +#define HAVE_LONG_LONG 1 + +/* Define if *printf() uses %qd to print `long long' (otherwise uses %lld) */ +/* #undef HAVE_PRINTF_QD */ + +/* Define if in_port_t exists */ +#define HAVE_IN_PORT_T 1 + +/* Define if sa_family_t exists in */ +/* #undef HAVE_SA_FAMILY_T */ + +/* Define if struct sockaddr.sa_len exists (implies sockaddr_in.sin_len, etc) */ +#define HAVE_SOCKADDR_SA_LEN 1 + +/* Define if socklen_t exists */ +/* #undef HAVE_SOCKLEN_T */ + +/* Define if AF_INET6 exists in */ +#define HAVE_AF_INET6 1 + +/* Define if `struct sockaddr_in6' exists in */ +/* #undef HAVE_SOCKADDR_IN6 */ + +/* Define if `struct addrinfo' exists in */ +#define HAVE_ADDRINFO 1 + +/* + * Define if contains AI_NUMERICHOST et al. + * Systems which only implement RFC2133 will need this. + */ +/* #undef HAVE_RFC2553_NETDB */ + +/* Define if `struct direct' has a d_namlen element */ +/* #undef HAVE_D_NAMLEN */ + +/* Define if h_errno exists in */ +#define HAVE_H_ERRNO_D 1 + +/* Define if fclose() is declared in */ +#define HAVE_FCLOSE_D 1 + +/* Define if getpass() is declared in or */ +/* #undef HAVE_GETPASS_D */ + +/* Define if optarg is declared in or */ +#define HAVE_OPTARG_D 1 + +/* Define if optind is declared in or */ +#define HAVE_OPTIND_D 1 + +/* Define if pclose() is declared in */ +#define HAVE_PCLOSE_D 1 + +/* Define if `long long' is supported and sizeof(off_t) >= 8 */ +#define HAVE_QUAD_SUPPORT 1 + +/* Define if strptime() is declared in */ +/* #undef HAVE_STRPTIME_D */ + +/* + * Define this if compiling with SOCKS (the firewall traversal library). + * Also, you must define connect, getsockname, bind, accept, listen, and + * select to their R-versions. + */ +/* #undef SOCKS */ +/* #undef SOCKS4 */ +/* #undef SOCKS5 */ +/* #undef connect */ +/* #undef getsockname */ +/* #undef bind */ +/* #undef accept */ +/* #undef listen */ +/* #undef select */ +/* #undef dup */ +/* #undef dup2 */ +/* #undef fclose */ +/* #undef gethostbyname */ +/* #undef getpeername */ +/* #undef read */ +/* #undef recv */ +/* #undef recvfrom */ +/* #undef rresvport */ +/* #undef send */ +/* #undef sendto */ +/* #undef shutdown */ +/* #undef write */ diff --git a/src/bin/network/ftp/domacro.c b/src/bin/network/ftp/domacro.c new file mode 100644 index 0000000000..3849d00ef6 --- /dev/null +++ b/src/bin/network/ftp/domacro.c @@ -0,0 +1,136 @@ +/* $NetBSD: domacro.c,v 1.20 2003/08/07 11:13:53 agc Exp $ */ + +/* + * Copyright (c) 1985, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include "ftp_var.h" + +void +domacro(int argc, char *argv[]) +{ + int i, j, count = 2, loopflg = 0; + char *cp1, *cp2, line2[FTPBUFLEN]; + struct cmd *c; + + if ((argc == 0 && argv != NULL) || + (argc < 2 && !another(&argc, &argv, "macro name"))) { + fprintf(ttyout, "usage: %s macro_name [args]\n", argv[0]); + code = -1; + return; + } + for (i = 0; i < macnum; ++i) { + if (!strncmp(argv[1], macros[i].mac_name, 9)) + break; + } + if (i == macnum) { + fprintf(ttyout, "'%s' macro not found.\n", argv[1]); + code = -1; + return; + } + (void)strlcpy(line2, line, sizeof(line2)); + TOP: + cp1 = macros[i].mac_start; + while (cp1 != macros[i].mac_end) { + while (isspace((unsigned char)*cp1)) + cp1++; + cp2 = line; + while (*cp1 != '\0') { + switch(*cp1) { + case '\\': + *cp2++ = *++cp1; + break; + case '$': + if (isdigit((unsigned char)*(cp1+1))) { + j = 0; + while (isdigit((unsigned char)*++cp1)) + j = 10*j + *cp1 - '0'; + cp1--; + if (argc - 2 >= j) { + (void)strlcpy(cp2, argv[j+1], + sizeof(line) - (cp2 - line)); + cp2 += strlen(argv[j+1]); + } + break; + } + if (*(cp1+1) == 'i') { + loopflg = 1; + cp1++; + if (count < argc) { + (void)strlcpy(cp2, argv[count], + sizeof(line) - (cp2 - line)); + cp2 += strlen(argv[count]); + } + break; + } + /* intentional drop through */ + default: + *cp2++ = *cp1; + break; + } + if (*cp1 != '\0') + cp1++; + } + *cp2 = '\0'; + makeargv(); + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + fputs("?Ambiguous command.\n", ttyout); + code = -1; + } else if (c == 0) { + fputs("?Invalid command.\n", ttyout); + code = -1; + } else if (c->c_conn && !connected) { + fputs("Not connected.\n", ttyout); + code = -1; + } else { + if (verbose) { + fputs(line, ttyout); + putc('\n', ttyout); + } + margv[0] = c->c_name; + (*c->c_handler)(margc, margv); + if (bell && c->c_bell) + (void)putc('\007', ttyout); + (void)strlcpy(line, line2, sizeof(line)); + makeargv(); + argc = margc; + argv = margv; + } + if (cp1 != macros[i].mac_end) + cp1++; + } + if (loopflg && ++count < argc) + goto TOP; +} diff --git a/src/bin/network/ftp/extern.h b/src/bin/network/ftp/extern.h new file mode 100644 index 0000000000..3070e9552e --- /dev/null +++ b/src/bin/network/ftp/extern.h @@ -0,0 +1,259 @@ +/* $NetBSD: extern.h,v 1.67 2005/05/14 15:26:43 lukem Exp $ */ + +/*- + * Copyright (c) 1996-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1994 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.3 (Berkeley) 10/9/94 + */ + +/* + * Copyright (C) 1997 and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct sockaddr; +struct tm; +struct addrinfo; + +typedef int sa_family_t; + +void abort_remote(FILE *); +void abort_squared(int); +void abortpt(int); +void abortxfer(int); +void account(int, char **); +void ai_unmapped(struct addrinfo *); +int another(int *, char ***, const char *); +int auto_fetch(int, char **); +int auto_put(int, char **, const char *); +void blkfree(char **); +void cd(int, char **); +void cdup(int, char **); +void changetype(int, int); +void cleanuppeer(void); +void cmdabort(int); +void cmdtimeout(int); +void cmdscanner(void); +int command(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +#ifndef NO_EDITCOMPLETE +unsigned char complete(EditLine *, int); +void controlediting(void); +#endif /* !NO_EDITCOMPLETE */ +void crankrate(int); +FILE *dataconn(const char *); +void delete(int, char **); +void disconnect(int, char **); +void do_chmod(int, char **); +void do_umask(int, char **); +void domacro(int, char **); +void doproxy(int, char **); +void feat(int, char **); +void fget(int, char **); +int fileindir(const char *, const char *); +int foregroundproc(void); +void formatbuf(char *, size_t, const char *); +void ftpvis(char *, size_t, const char *, size_t); +int ftp_login(const char *, const char *, const char *); +void get(int, char **); +struct cmd *getcmd(const char *); +int getit(int, char **, int, const char *); +struct option *getoption(const char *); +char *getoptionvalue(const char *); +void getremoteinfo(void); +int getreply(int); +char *globulize(const char *); +char *gunique(const char *); +void help(int, char **); +char *hookup(char *, char *); +void idlecmd(int, char **); +int initconn(void); +void intr(int); +int isipv6addr(const char *); +void list_vertical(StringList *); +void lcd(int, char **); +void lostpeer(int); +void lpage(int, char **); +void lpwd(int, char **); +void ls(int, char **); +void mabort(void); +void macdef(int, char **); +void makeargv(void); +void makedir(int, char **); +void mdelete(int, char **); +void mget(int, char **); +void mintr(int); +void mls(int, char **); +void mlst(int, char **); +void modtime(int, char **); +void mput(int, char **); +char *onoff(int); +void opts(int, char **); +void newer(int, char **); +void page(int, char **); +int parseport(const char *, int); +int parserate(int, char **, int); +char *prompt(void); +void proxabort(int); +void proxtrans(const char *, const char *, const char *); +void psabort(int); +void pswitch(int); +void put(int, char **); +void pwd(int, char **); +void quit(int, char **); +void quote(int, char **); +void quote1(const char *, int, char **); +void recvrequest(const char *, const char *, const char *, + const char *, int, int); +void reget(int, char **); +char *remglob(char **, int, char **); +time_t remotemodtime(const char *, int); +off_t remotesize(const char *, int); +void removedir(int, char **); +void renamefile(int, char **); +void reset(int, char **); +void restart(int, char **); +void rmthelp(int, char **); +void rmtstatus(int, char **); +char *rprompt(void); +int ruserpass(const char *, const char **, const char **, + const char **); +void sendrequest(const char *, const char *, const char *, int); +void setascii(int, char **); +void setbell(int, char **); +void setbinary(int, char **); +void setcase(int, char **); +void setcr(int, char **); +void setdebug(int, char **); +void setedit(int, char **); +void setepsv4(int, char **); +void setform(int, char **); +void setftmode(int, char **); +void setgate(int, char **); +void setglob(int, char **); +void sethash(int, char **); +void setnmap(int, char **); +void setntrans(int, char **); +void setoption(int, char **); +void setpassive(int, char **); +void setpeer(int, char **); +void setport(int, char **); +void setpreserve(int, char **); +void setprogress(int, char **); +void setprompt(int, char **); +void setrate(int, char **); +void setrunique(int, char **); +void setstruct(int, char **); +void setsunique(int, char **); +void settenex(int, char **); +void settrace(int, char **); +void setttywidth(int); +void settype(int, char **); +void setupsockbufsize(int); +void setverbose(int, char **); +void setxferbuf(int, char **); +void shell(int, char **); +void site(int, char **); +void sizecmd(int, char **); +char *slurpstring(void); +void status(int, char **); +int strsuftoi(const char *); +void syst(int, char **); +int togglevar(int, char **, int *, const char *); +void unsetoption(int, char **); +void updatelocalcwd(void); +void updateremotecwd(void); +void usage(void); +void user(int, char **); +int xconnect(int, const struct sockaddr *, socklen_t); +int xlisten(int, int); +int xpoll(struct pollfd *, int, int); +void *xmalloc(size_t); +StringList *xsl_init(void); +void xsl_add(StringList *, char *); +char *xstrdup(const char *); diff --git a/src/bin/network/ftp/fetch.c b/src/bin/network/ftp/fetch.c new file mode 100644 index 0000000000..bee3a06e11 --- /dev/null +++ b/src/bin/network/ftp/fetch.c @@ -0,0 +1,1831 @@ +/* $NetBSD: fetch.c,v 1.158 2005/05/14 15:26:43 lukem Exp $ */ + +/*- + * Copyright (c) 1997-2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Scott Aaron Bamford. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * FTP User Program -- Command line file retrieval + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" +#include "version.h" + +typedef enum { + UNKNOWN_URL_T=-1, + HTTP_URL_T, + FTP_URL_T, + FILE_URL_T, + CLASSIC_URL_T +} url_t; + +void aborthttp(int); +#ifndef NO_AUTH +static int auth_url(const char *, char **, const char *, const char *); +static void base64_encode(const unsigned char *, size_t, unsigned char *); +#endif +static int go_fetch(const char *); +static int fetch_ftp(const char *); +static int fetch_url(const char *, const char *, char *, char *); +static const char *match_token(const char **, const char *); +static int parse_url(const char *, const char *, url_t *, char **, + char **, char **, char **, in_port_t *, char **); +static void url_decode(char *); + +static int redirect_loop; + + +#define STRNEQUAL(a,b) (strncasecmp((a), (b), sizeof((b))-1) == 0) +#define ISLWS(x) ((x)=='\r' || (x)=='\n' || (x)==' ' || (x)=='\t') +#define SKIPLWS(x) do { while (ISLWS((*x))) x++; } while (0) + + +#define ABOUT_URL "about:" /* propaganda */ +#define FILE_URL "file://" /* file URL prefix */ +#define FTP_URL "ftp://" /* ftp URL prefix */ +#define HTTP_URL "http://" /* http URL prefix */ + + +/* + * Determine if token is the next word in buf (case insensitive). + * If so, advance buf past the token and any trailing LWS, and + * return a pointer to the token (in buf). Otherwise, return NULL. + * token may be preceeded by LWS. + * token must be followed by LWS or NUL. (I.e, don't partial match). + */ +static const char * +match_token(const char **buf, const char *token) +{ + const char *p, *orig; + size_t tlen; + + tlen = strlen(token); + p = *buf; + SKIPLWS(p); + orig = p; + if (strncasecmp(p, token, tlen) != 0) + return NULL; + p += tlen; + if (*p != '\0' && !ISLWS(*p)) + return NULL; + SKIPLWS(p); + orig = *buf; + *buf = p; + return orig; +} + +#ifndef NO_AUTH +/* + * Generate authorization response based on given authentication challenge. + * Returns -1 if an error occurred, otherwise 0. + * Sets response to a malloc(3)ed string; caller should free. + */ +static int +auth_url(const char *challenge, char **response, const char *guser, + const char *gpass) +{ + const char *cp, *scheme; + char *ep, *clear, *realm; + char user[BUFSIZ], *pass; + int rval; + size_t len, clen, rlen; + + *response = NULL; + clear = realm = NULL; + rval = -1; + cp = challenge; + scheme = "Basic"; /* only support Basic authentication */ + + if (debug) + fprintf(ttyout, "auth_url: challenge `%s'\n", challenge); + + if (! match_token(&cp, scheme)) { + warnx("Unsupported authentication challenge - `%s'", + challenge); + goto cleanup_auth_url; + } + +#define REALM "realm=\"" + if (STRNEQUAL(cp, REALM)) + cp += sizeof(REALM) - 1; + else { + warnx("Unsupported authentication challenge - `%s'", + challenge); + goto cleanup_auth_url; + } +/* XXX: need to improve quoted-string parsing to support \ quoting, etc. */ + if ((ep = strchr(cp, '\"')) != NULL) { + size_t len = ep - cp; + + realm = (char *)xmalloc(len + 1); + (void)strlcpy(realm, cp, len + 1); + } else { + warnx("Unsupported authentication challenge - `%s'", + challenge); + goto cleanup_auth_url; + } + + fprintf(ttyout, "Username for `%s': ", realm); + if (guser != NULL) { + (void)strlcpy(user, guser, sizeof(user)); + fprintf(ttyout, "%s\n", user); + } else { + (void)fflush(ttyout); + if (fgets(user, sizeof(user) - 1, stdin) == NULL) { + clearerr(stdin); + goto cleanup_auth_url; + } + user[strlen(user) - 1] = '\0'; + } + if (gpass != NULL) + pass = (char *)gpass; + else + pass = getpass("Password: "); + + clen = strlen(user) + strlen(pass) + 2; /* user + ":" + pass + "\0" */ + clear = (char *)xmalloc(clen); + (void)strlcpy(clear, user, clen); + (void)strlcat(clear, ":", clen); + (void)strlcat(clear, pass, clen); + if (gpass == NULL) + memset(pass, 0, strlen(pass)); + + /* scheme + " " + enc + "\0" */ + rlen = strlen(scheme) + 1 + (clen + 2) * 4 / 3 + 1; + *response = (char *)xmalloc(rlen); + (void)strlcpy(*response, scheme, rlen); + len = strlcat(*response, " ", rlen); + /* use `clen - 1' to not encode the trailing NUL */ + base64_encode((unsigned char *)clear, clen - 1, + (unsigned char *)*response + len); + memset(clear, 0, clen); + rval = 0; + + cleanup_auth_url: + FREEPTR(clear); + FREEPTR(realm); + return (rval); +} + +/* + * Encode len bytes starting at clear using base64 encoding into encoded, + * which should be at least ((len + 2) * 4 / 3 + 1) in size. + */ +static void +base64_encode(const unsigned char *clear, size_t len, unsigned char *encoded) +{ + static const unsigned char enc[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned char *cp; + int i; + + cp = encoded; + for (i = 0; i < len; i += 3) { + *(cp++) = enc[((clear[i + 0] >> 2))]; + *(cp++) = enc[((clear[i + 0] << 4) & 0x30) + | ((clear[i + 1] >> 4) & 0x0f)]; + *(cp++) = enc[((clear[i + 1] << 2) & 0x3c) + | ((clear[i + 2] >> 6) & 0x03)]; + *(cp++) = enc[((clear[i + 2] ) & 0x3f)]; + } + *cp = '\0'; + while (i-- > len) + *(--cp) = '='; +} +#endif + +/* + * Decode %xx escapes in given string, `in-place'. + */ +static void +url_decode(char *url) +{ + unsigned char *p, *q; + + if (EMPTYSTRING(url)) + return; + p = q = (unsigned char *)url; + +#define HEXTOINT(x) (x - (isdigit(x) ? '0' : (islower(x) ? 'a' : 'A') - 10)) + while (*p) { + if (p[0] == '%' + && p[1] && isxdigit((unsigned char)p[1]) + && p[2] && isxdigit((unsigned char)p[2])) { + *q++ = HEXTOINT(p[1]) * 16 + HEXTOINT(p[2]); + p+=3; + } else + *q++ = *p++; + } + *q = '\0'; +} + + +/* + * Parse URL of form: + * ://[[:]@][:][/] + * Returns -1 if a parse error occurred, otherwise 0. + * It's the caller's responsibility to url_decode() the returned + * user, pass and path. + * + * Sets type to url_t, each of the given char ** pointers to a + * malloc(3)ed strings of the relevant section, and port to + * the number given, or ftpport if ftp://, or httpport if http://. + * + * If is surrounded by `[' and ']', it's parsed as an + * IPv6 address (as per RFC 2732). + * + * XXX: this is not totally RFC 1738 compliant; will have the + * leading `/' unless it's an ftp:// URL, as this makes things easier + * for file:// and http:// URLs. ftp:// URLs have the `/' between the + * host and the URL-path removed, but any additional leading slashes + * in the URL-path are retained (because they imply that we should + * later do "CWD" with a null argument). + * + * Examples: + * input URL output path + * --------- ----------- + * "ftp://host" NULL + * "http://host/" NULL + * "file://host/dir/file" "dir/file" + * "ftp://host/" "" + * "ftp://host//" NULL + * "ftp://host//dir/file" "/dir/file" + */ +static int +parse_url(const char *url, const char *desc, url_t *type, + char **user, char **pass, char **host, char **port, + in_port_t *portnum, char **path) +{ + const char *origurl; + char *cp, *ep, *thost, *tport; + size_t len; + + if (url == NULL || desc == NULL || type == NULL || user == NULL + || pass == NULL || host == NULL || port == NULL || portnum == NULL + || path == NULL) + errx(1, "parse_url: invoked with NULL argument!"); + + origurl = url; + *type = UNKNOWN_URL_T; + *user = *pass = *host = *port = *path = NULL; + *portnum = 0; + tport = NULL; + + if (STRNEQUAL(url, HTTP_URL)) { + url += sizeof(HTTP_URL) - 1; + *type = HTTP_URL_T; + *portnum = HTTP_PORT; + tport = httpport; + } else if (STRNEQUAL(url, FTP_URL)) { + url += sizeof(FTP_URL) - 1; + *type = FTP_URL_T; + *portnum = FTP_PORT; + tport = ftpport; + } else if (STRNEQUAL(url, FILE_URL)) { + url += sizeof(FILE_URL) - 1; + *type = FILE_URL_T; + } else { + warnx("Invalid %s `%s'", desc, url); + cleanup_parse_url: + FREEPTR(*user); + FREEPTR(*pass); + FREEPTR(*host); + FREEPTR(*port); + FREEPTR(*path); + return (-1); + } + + if (*url == '\0') + return (0); + + /* find [user[:pass]@]host[:port] */ + ep = strchr(url, '/'); + if (ep == NULL) + thost = xstrdup(url); + else { + len = ep - url; + thost = (char *)xmalloc(len + 1); + (void)strlcpy(thost, url, len + 1); + if (*type == FTP_URL_T) /* skip first / for ftp URLs */ + ep++; + *path = xstrdup(ep); + } + + cp = strchr(thost, '@'); /* look for user[:pass]@ in URLs */ + if (cp != NULL) { + if (*type == FTP_URL_T) + anonftp = 0; /* disable anonftp */ + *user = thost; + *cp = '\0'; + thost = xstrdup(cp + 1); + cp = strchr(*user, ':'); + if (cp != NULL) { + *cp = '\0'; + *pass = xstrdup(cp + 1); + } + url_decode(*user); + if (*pass) + url_decode(*pass); + } + +#ifdef INET6 + /* + * Check if thost is an encoded IPv6 address, as per + * RFC 2732: + * `[' ipv6-address ']' + */ + if (*thost == '[') { + cp = thost + 1; + if ((ep = strchr(cp, ']')) == NULL || + (ep[1] != '\0' && ep[1] != ':')) { + warnx("Invalid address `%s' in %s `%s'", + thost, desc, origurl); + goto cleanup_parse_url; + } + len = ep - cp; /* change `[xyz]' -> `xyz' */ + memmove(thost, thost + 1, len); + thost[len] = '\0'; + if (! isipv6addr(thost)) { + warnx("Invalid IPv6 address `%s' in %s `%s'", + thost, desc, origurl); + goto cleanup_parse_url; + } + cp = ep + 1; + if (*cp == ':') + cp++; + else + cp = NULL; + } else +#endif /* INET6 */ + if ((cp = strchr(thost, ':')) != NULL) + *cp++ = '\0'; + *host = thost; + + /* look for [:port] */ + if (cp != NULL) { + long nport; + + nport = parseport(cp, -1); + if (nport == -1) { + warnx("Unknown port `%s' in %s `%s'", + cp, desc, origurl); + goto cleanup_parse_url; + } + *portnum = nport; + tport = cp; + } + + if (tport != NULL) + *port = xstrdup(tport); + if (*path == NULL) + *path = xstrdup("/"); + + if (debug) + fprintf(ttyout, + "parse_url: user `%s' pass `%s' host %s port %s(%d) " + "path `%s'\n", + *user ? *user : "", *pass ? *pass : "", + *host ? *host : "", *port ? *port : "", + *portnum ? *portnum : -1, *path ? *path : ""); + + return (0); +} + +sigjmp_buf httpabort; + +/* + * Retrieve URL, via a proxy if necessary, using HTTP. + * If proxyenv is set, use that for the proxy, otherwise try ftp_proxy or + * http_proxy as appropriate. + * Supports HTTP redirects. + * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection + * is still open (e.g, ftp xfer with trailing /) + */ +static int +fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) +{ + struct addrinfo hints, *res, *res0 = NULL; + int error; + char hbuf[NI_MAXHOST]; + volatile sigfunc oldintr, oldintp; + volatile int s; + struct stat sb; + int ischunked, isproxy, rval, hcode; + size_t len; + static size_t bufsize; + static char *xferbuf; + const char *cp, *token; + char *ep, *buf, *savefile; + char *auth, *location, *message; + char *user, *pass, *host, *port, *path, *decodedpath; + char *puser, *ppass, *useragent; + off_t hashbytes, rangestart, rangeend, entitylen; + int (*closefunc)(FILE *); + FILE *fin, *fout; + time_t mtime; + url_t urltype; + in_port_t portnum; + + oldintr = oldintp = NULL; + closefunc = NULL; + fin = fout = NULL; + s = -1; + buf = savefile = NULL; + auth = location = message = NULL; + ischunked = isproxy = hcode = 0; + rval = 1; + user = pass = host = path = decodedpath = puser = ppass = NULL; + +#ifdef __GNUC__ /* shut up gcc warnings */ + (void)&closefunc; + (void)&fin; + (void)&fout; + (void)&buf; + (void)&savefile; + (void)&rval; + (void)&isproxy; + (void)&hcode; + (void)&ischunked; + (void)&message; + (void)&location; + (void)&auth; + (void)&decodedpath; +#endif + + if (parse_url(url, "URL", &urltype, &user, &pass, &host, &port, + &portnum, &path) == -1) + goto cleanup_fetch_url; + + if (urltype == FILE_URL_T && ! EMPTYSTRING(host) + && strcasecmp(host, "localhost") != 0) { + warnx("No support for non local file URL `%s'", url); + goto cleanup_fetch_url; + } + + if (EMPTYSTRING(path)) { + if (urltype == FTP_URL_T) { + rval = fetch_ftp(url); + goto cleanup_fetch_url; + } + if (urltype != HTTP_URL_T || outfile == NULL) { + warnx("Invalid URL (no file after host) `%s'", url); + goto cleanup_fetch_url; + } + } + + decodedpath = xstrdup(path); + url_decode(decodedpath); + + if (outfile) + savefile = xstrdup(outfile); + else { + cp = strrchr(decodedpath, '/'); /* find savefile */ + if (cp != NULL) + savefile = xstrdup(cp + 1); + else + savefile = xstrdup(decodedpath); + } + if (EMPTYSTRING(savefile)) { + if (urltype == FTP_URL_T) { + rval = fetch_ftp(url); + goto cleanup_fetch_url; + } + warnx("no file after directory (you must specify an " + "output file) `%s'", url); + goto cleanup_fetch_url; + } else { + if (debug) + fprintf(ttyout, "savefile `%s'\n", savefile); + } + + restart_point = 0; + filesize = -1; + rangestart = rangeend = entitylen = -1; + mtime = -1; + if (restartautofetch) { + if (strcmp(savefile, "-") != 0 && *savefile != '|' && + stat(savefile, &sb) == 0) + restart_point = sb.st_size; + } + if (urltype == FILE_URL_T) { /* file:// URLs */ + direction = "copied"; + fin = fopen(decodedpath, "r"); + if (fin == NULL) { + warn("Cannot open file `%s'", decodedpath); + goto cleanup_fetch_url; + } + if (fstat(fileno(fin), &sb) == 0) { + mtime = sb.st_mtime; + filesize = sb.st_size; + } + if (restart_point) { + if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { + warn("Can't lseek to restart `%s'", + decodedpath); + goto cleanup_fetch_url; + } + } + if (verbose) { + fprintf(ttyout, "Copying %s", decodedpath); + if (restart_point) + fprintf(ttyout, " (restarting at " LLF ")", + (LLT)restart_point); + fputs("\n", ttyout); + } + } else { /* ftp:// or http:// URLs */ + char *leading; + int hasleading; + + if (proxyenv == NULL) { + if (urltype == HTTP_URL_T) + proxyenv = getoptionvalue("http_proxy"); + else if (urltype == FTP_URL_T) + proxyenv = getoptionvalue("ftp_proxy"); + } + direction = "retrieved"; + if (! EMPTYSTRING(proxyenv)) { /* use proxy */ + url_t purltype; + char *phost, *ppath; + char *pport, *no_proxy; + + isproxy = 1; + + /* check URL against list of no_proxied sites */ + no_proxy = getoptionvalue("no_proxy"); + if (! EMPTYSTRING(no_proxy)) { + char *np, *np_copy; + long np_port; + size_t hlen, plen; + + np_copy = xstrdup(no_proxy); + hlen = strlen(host); + while ((cp = strsep(&np_copy, " ,")) != NULL) { + if (*cp == '\0') + continue; + if ((np = strrchr(cp, ':')) != NULL) { + *np = '\0'; + np_port = + strtol(np + 1, &ep, 10); + if (*ep != '\0') + continue; + if (np_port != portnum) + continue; + } + plen = strlen(cp); + if (hlen < plen) + continue; + if (strncasecmp(host + hlen - plen, + cp, plen) == 0) { + isproxy = 0; + break; + } + } + FREEPTR(np_copy); + if (isproxy == 0 && urltype == FTP_URL_T) { + rval = fetch_ftp(url); + goto cleanup_fetch_url; + } + } + + if (isproxy) { + if (parse_url(proxyenv, "proxy URL", &purltype, + &puser, &ppass, &phost, &pport, &portnum, + &ppath) == -1) + goto cleanup_fetch_url; + + if ((purltype != HTTP_URL_T + && purltype != FTP_URL_T) || + EMPTYSTRING(phost) || + (! EMPTYSTRING(ppath) + && strcmp(ppath, "/") != 0)) { + warnx("Malformed proxy URL `%s'", + proxyenv); + FREEPTR(phost); + FREEPTR(pport); + FREEPTR(ppath); + goto cleanup_fetch_url; + } + if (isipv6addr(host) && + strchr(host, '%') != NULL) { + warnx( +"Scoped address notation `%s' disallowed via web proxy", + host); + FREEPTR(phost); + FREEPTR(pport); + FREEPTR(ppath); + goto cleanup_fetch_url; + } + + FREEPTR(host); + host = phost; + FREEPTR(port); + port = pport; + FREEPTR(path); + path = xstrdup(url); + FREEPTR(ppath); + } + } /* ! EMPTYSTRING(proxyenv) */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + warnx("%s", gai_strerror(error)); + goto cleanup_fetch_url; + } + if (res0->ai_canonname) + host = res0->ai_canonname; + + s = -1; + for (res = res0; res; res = res->ai_next) { + /* + * see comment in hookup() + */ + ai_unmapped(res); + if (getnameinfo(res->ai_addr, res->ai_addrlen, + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) + strlcpy(hbuf, "invalid", sizeof(hbuf)); + + if (verbose && res != res0) + fprintf(ttyout, "Trying %s...\n", hbuf); + + ((struct sockaddr_in *)res->ai_addr)->sin_port = + htons(portnum); + s = socket(res->ai_family, SOCK_STREAM, + res->ai_protocol); + if (s < 0) { + warn("Can't create socket"); + continue; + } + + if (xconnect(s, res->ai_addr, res->ai_addrlen) < 0) { + warn("Connect to address `%s'", hbuf); + close(s); + s = -1; + continue; + } + + /* success */ + break; + } + + if (s < 0) { + warn("Can't connect to %s", host); + goto cleanup_fetch_url; + } + + fin = fdopen(s, "r+"); + /* + * Construct and send the request. + */ + if (verbose) + fprintf(ttyout, "Requesting %s\n", url); + leading = " ("; + hasleading = 0; + if (isproxy) { + if (verbose) { + fprintf(ttyout, "%svia %s:%s", leading, + host, port); + leading = ", "; + hasleading++; + } + fprintf(fin, "GET %s HTTP/1.0\r\n", path); + if (flushcache) + fprintf(fin, "Pragma: no-cache\r\n"); + } else { + fprintf(fin, "GET %s HTTP/1.1\r\n", path); + if (strchr(host, ':')) { + char *h, *p; + + /* + * strip off IPv6 scope identifier, since it is + * local to the node + */ + h = xstrdup(host); + if (isipv6addr(h) && + (p = strchr(h, '%')) != NULL) { + *p = '\0'; + } + fprintf(fin, "Host: [%s]", h); + free(h); + } else + fprintf(fin, "Host: %s", host); + if (portnum != HTTP_PORT) + fprintf(fin, ":%u", portnum); + fprintf(fin, "\r\n"); + fprintf(fin, "Accept: */*\r\n"); + fprintf(fin, "Connection: close\r\n"); + if (restart_point) { + fputs(leading, ttyout); + fprintf(fin, "Range: bytes=" LLF "-\r\n", + (LLT)restart_point); + fprintf(ttyout, "restarting at " LLF, + (LLT)restart_point); + leading = ", "; + hasleading++; + } + if (flushcache) + fprintf(fin, "Cache-Control: no-cache\r\n"); + } + if ((useragent=getenv("FTPUSERAGENT")) != NULL) { + fprintf(fin, "User-Agent: %s\r\n", useragent); + } else { + fprintf(fin, "User-Agent: %s/%s\r\n", + FTP_PRODUCT, FTP_VERSION); + } + if (wwwauth) { + if (verbose) { + fprintf(ttyout, "%swith authorization", + leading); + leading = ", "; + hasleading++; + } + fprintf(fin, "Authorization: %s\r\n", wwwauth); + } + if (proxyauth) { + if (verbose) { + fprintf(ttyout, + "%swith proxy authorization", leading); + leading = ", "; + hasleading++; + } + fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth); + } + if (verbose && hasleading) + fputs(")\n", ttyout); + fprintf(fin, "\r\n"); + if (fflush(fin) == EOF) { + warn("Writing HTTP request"); + goto cleanup_fetch_url; + } + + /* Read the response */ + if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) { + warn("Receiving HTTP reply"); + goto cleanup_fetch_url; + } + while (len > 0 && (ISLWS(buf[len-1]))) + buf[--len] = '\0'; + if (debug) + fprintf(ttyout, "received `%s'\n", buf); + + /* Determine HTTP response code */ + cp = strchr(buf, ' '); + if (cp == NULL) + goto improper; + else + cp++; + hcode = strtol(cp, &ep, 10); + if (*ep != '\0' && !isspace((unsigned char)*ep)) + goto improper; + message = xstrdup(cp); + + /* Read the rest of the header. */ + while (1) { + FREEPTR(buf); + if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) + == NULL) { + warn("Receiving HTTP reply"); + goto cleanup_fetch_url; + } + while (len > 0 && (ISLWS(buf[len-1]))) + buf[--len] = '\0'; + if (len == 0) + break; + if (debug) + fprintf(ttyout, "received `%s'\n", buf); + + /* + * Look for some headers + */ + + cp = buf; + + if (match_token(&cp, "Content-Length:")) { + filesize = STRTOLL(cp, &ep, 10); + if (filesize < 0 || *ep != '\0') + goto improper; + if (debug) + fprintf(ttyout, + "parsed len as: " LLF "\n", + (LLT)filesize); + + } else if (match_token(&cp, "Content-Range:")) { + if (! match_token(&cp, "bytes")) + goto improper; + + if (*cp == '*') + cp++; + else { + rangestart = STRTOLL(cp, &ep, 10); + if (rangestart < 0 || *ep != '-') + goto improper; + cp = ep + 1; + rangeend = STRTOLL(cp, &ep, 10); + if (rangeend < 0 || rangeend < rangestart) + goto improper; + cp = ep; + } + if (*cp != '/') + goto improper; + cp++; + if (*cp == '*') + cp++; + else { + entitylen = STRTOLL(cp, &ep, 10); + if (entitylen < 0) + goto improper; + cp = ep; + } + if (*cp != '\0') + goto improper; + + if (debug) { + fprintf(ttyout, "parsed range as: "); + if (rangestart == -1) + fprintf(ttyout, "*"); + else + fprintf(ttyout, LLF "-" LLF, + (LLT)rangestart, + (LLT)rangeend); + fprintf(ttyout, "/" LLF "\n", (LLT)entitylen); + } + if (! restart_point) { + warnx( + "Received unexpected Content-Range header"); + goto cleanup_fetch_url; + } + + } else if (match_token(&cp, "Last-Modified:")) { + struct tm parsed; + char *t; + + /* RFC 1123 */ + if ((t = strptime(cp, + "%a, %d %b %Y %H:%M:%S GMT", + &parsed)) + /* RFC 850 */ + || (t = strptime(cp, + "%a, %d-%b-%y %H:%M:%S GMT", + &parsed)) + /* asctime */ + || (t = strptime(cp, + "%a, %b %d %H:%M:%S %Y", + &parsed))) { + parsed.tm_isdst = -1; + if (*t == '\0') + mtime = timegm(&parsed); + if (debug && mtime != -1) { + fprintf(ttyout, + "parsed date as: %s", + ctime(&mtime)); + } + } + + } else if (match_token(&cp, "Location:")) { + location = xstrdup(cp); + if (debug) + fprintf(ttyout, + "parsed location as `%s'\n", cp); + + } else if (match_token(&cp, "Transfer-Encoding:")) { + if (match_token(&cp, "binary")) { + warnx( + "Bogus transfer encoding - `binary' (fetching anyway)"); + continue; + } + if (! (token = match_token(&cp, "chunked"))) { + warnx( + "Unsupported transfer encoding - `%s'", + token); + goto cleanup_fetch_url; + } + ischunked++; + if (debug) + fprintf(ttyout, + "using chunked encoding\n"); + + } else if (match_token(&cp, "Proxy-Authenticate:") + || match_token(&cp, "WWW-Authenticate:")) { + if (! (token = match_token(&cp, "Basic"))) { + if (debug) + fprintf(ttyout, + "skipping unknown auth scheme `%s'\n", + token); + continue; + } + FREEPTR(auth); + auth = xstrdup(token); + if (debug) + fprintf(ttyout, + "parsed auth as `%s'\n", cp); + } + + } + /* finished parsing header */ + FREEPTR(buf); + + switch (hcode) { + case 200: + break; + case 206: + if (! restart_point) { + warnx("Not expecting partial content header"); + goto cleanup_fetch_url; + } + break; + case 300: + case 301: + case 302: + case 303: + case 305: + if (EMPTYSTRING(location)) { + warnx( + "No redirection Location provided by server"); + goto cleanup_fetch_url; + } + if (redirect_loop++ > 5) { + warnx("Too many redirections requested"); + goto cleanup_fetch_url; + } + if (hcode == 305) { + if (verbose) + fprintf(ttyout, "Redirected via %s\n", + location); + rval = fetch_url(url, location, + proxyauth, wwwauth); + } else { + if (verbose) + fprintf(ttyout, "Redirected to %s\n", + location); + rval = go_fetch(location); + } + goto cleanup_fetch_url; +#ifndef NO_AUTH + case 401: + case 407: + { + char **authp; + char *auser, *apass; + + if (hcode == 401) { + authp = &wwwauth; + auser = user; + apass = pass; + } else { + authp = &proxyauth; + auser = puser; + apass = ppass; + } + if (verbose || *authp == NULL || + auser == NULL || apass == NULL) + fprintf(ttyout, "%s\n", message); + if (EMPTYSTRING(auth)) { + warnx( + "No authentication challenge provided by server"); + goto cleanup_fetch_url; + } + if (*authp != NULL) { + char reply[10]; + + fprintf(ttyout, + "Authorization failed. Retry (y/n)? "); + if (fgets(reply, sizeof(reply), stdin) + == NULL) { + clearerr(stdin); + goto cleanup_fetch_url; + } + if (tolower((unsigned char)reply[0]) != 'y') + goto cleanup_fetch_url; + auser = NULL; + apass = NULL; + } + if (auth_url(auth, authp, auser, apass) == 0) { + rval = fetch_url(url, proxyenv, + proxyauth, wwwauth); + memset(*authp, 0, strlen(*authp)); + FREEPTR(*authp); + } + goto cleanup_fetch_url; + } +#endif + default: + if (message) + warnx("Error retrieving file - `%s'", message); + else + warnx("Unknown error retrieving file"); + goto cleanup_fetch_url; + } + } /* end of ftp:// or http:// specific setup */ + + /* Open the output file. */ + if (strcmp(savefile, "-") == 0) { + fout = stdout; + } else if (*savefile == '|') { + oldintp = xsignal(SIGPIPE, SIG_IGN); + fout = popen(savefile + 1, "w"); + if (fout == NULL) { + warn("Can't run `%s'", savefile + 1); + goto cleanup_fetch_url; + } + closefunc = pclose; + } else { + if ((rangeend != -1 && rangeend <= restart_point) || + (rangestart == -1 && filesize != -1 && filesize <= restart_point)) { + /* already done */ + if (verbose) + fprintf(ttyout, "already done\n"); + rval = 0; + goto cleanup_fetch_url; + } + if (restart_point && rangestart != -1) { + if (entitylen != -1) + filesize = entitylen; + if (rangestart != restart_point) { + warnx( + "Size of `%s' differs from save file `%s'", + url, savefile); + goto cleanup_fetch_url; + } + fout = fopen(savefile, "a"); + } else + fout = fopen(savefile, "w"); + if (fout == NULL) { + warn("Can't open `%s'", savefile); + goto cleanup_fetch_url; + } + closefunc = fclose; + } + + /* Trap signals */ + if (sigsetjmp(httpabort, 1)) + goto cleanup_fetch_url; + (void)xsignal(SIGQUIT, psummary); + oldintr = xsignal(SIGINT, aborthttp); + + if (rcvbuf_size > bufsize) { + if (xferbuf) + (void)free(xferbuf); + bufsize = rcvbuf_size; + xferbuf = xmalloc(bufsize); + } + + bytes = 0; + hashbytes = mark; + progressmeter(-1); + + /* Finally, suck down the file. */ + do { + long chunksize; + + chunksize = 0; + /* read chunksize */ + if (ischunked) { + if (fgets(xferbuf, bufsize, fin) == NULL) { + warnx("Unexpected EOF reading chunksize"); + goto cleanup_fetch_url; + } + chunksize = strtol(xferbuf, &ep, 16); + + /* + * XXX: Work around bug in Apache 1.3.9 and + * 1.3.11, which incorrectly put trailing + * space after the chunksize. + */ + while (*ep == ' ') + ep++; + + if (strcmp(ep, "\r\n") != 0) { + warnx("Unexpected data following chunksize"); + goto cleanup_fetch_url; + } + if (debug) + fprintf(ttyout, "got chunksize of " LLF "\n", + (LLT)chunksize); + if (chunksize == 0) + break; + } + /* transfer file or chunk */ + while (1) { + struct timeval then, now, td; + off_t bufrem; + + if (rate_get) + (void)gettimeofday(&then, NULL); + bufrem = rate_get ? rate_get : bufsize; + if (ischunked) + bufrem = MIN(chunksize, bufrem); + while (bufrem > 0) { + len = fread(xferbuf, sizeof(char), + MIN(bufsize, bufrem), fin); + if (len <= 0) + goto chunkdone; + bytes += len; + bufrem -= len; + if (fwrite(xferbuf, sizeof(char), len, fout) + != len) { + warn("Writing `%s'", savefile); + goto cleanup_fetch_url; + } + if (hash && !progress) { + while (bytes >= hashbytes) { + (void)putc('#', ttyout); + hashbytes += mark; + } + (void)fflush(ttyout); + } + if (ischunked) { + chunksize -= len; + if (chunksize <= 0) + break; + } + } + if (rate_get) { + while (1) { + (void)gettimeofday(&now, NULL); + timersub(&now, &then, &td); + if (td.tv_sec > 0) + break; + usleep(1000000 - td.tv_usec); + } + } + if (ischunked && chunksize <= 0) + break; + } + /* read CRLF after chunk*/ + chunkdone: + if (ischunked) { + if (fgets(xferbuf, bufsize, fin) == NULL) + break; + if (strcmp(xferbuf, "\r\n") != 0) { + warnx("Unexpected data following chunk"); + goto cleanup_fetch_url; + } + } + } while (ischunked); + if (hash && !progress && bytes > 0) { + if (bytes < mark) + (void)putc('#', ttyout); + (void)putc('\n', ttyout); + } + if (ferror(fin)) { + warn("Reading file"); + goto cleanup_fetch_url; + } + progressmeter(1); + (void)fflush(fout); + if (closefunc == fclose && mtime != -1) { + struct timeval tval[2]; + + (void)gettimeofday(&tval[0], NULL); + tval[1].tv_sec = mtime; + tval[1].tv_usec = 0; + (*closefunc)(fout); + fout = NULL; + + if (utimes(savefile, tval) == -1) { + fprintf(ttyout, + "Can't change modification time to %s", + asctime(localtime(&mtime))); + } + } + if (bytes > 0) + ptransfer(0); + bytes = 0; + + rval = 0; + goto cleanup_fetch_url; + + improper: + warnx("Improper response from `%s'", host); + + cleanup_fetch_url: + if (oldintr) + (void)xsignal(SIGINT, oldintr); + if (oldintp) + (void)xsignal(SIGPIPE, oldintp); + if (fin != NULL) + fclose(fin); + else if (s != -1) + close(s); + if (closefunc != NULL && fout != NULL) + (*closefunc)(fout); + if (res0) + freeaddrinfo(res0); + FREEPTR(savefile); + FREEPTR(user); + FREEPTR(pass); + FREEPTR(host); + FREEPTR(port); + FREEPTR(path); + FREEPTR(decodedpath); + FREEPTR(puser); + FREEPTR(ppass); + FREEPTR(buf); + FREEPTR(auth); + FREEPTR(location); + FREEPTR(message); + return (rval); +} + +/* + * Abort a HTTP retrieval + */ +void +aborthttp(int notused) +{ + char msgbuf[100]; + int len; + + sigint_raised = 1; + alarmtimer(0); + len = strlcpy(msgbuf, "\nHTTP fetch aborted.\n", sizeof(msgbuf)); + write(fileno(ttyout), msgbuf, len); + siglongjmp(httpabort, 1); +} + +/* + * Retrieve ftp URL or classic ftp argument using FTP. + * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection + * is still open (e.g, ftp xfer with trailing /) + */ +static int +fetch_ftp(const char *url) +{ + char *cp, *xargv[5], rempath[MAXPATHLEN]; + char *host, *path, *dir, *file, *user, *pass; + char *port; + int dirhasglob, filehasglob, oautologin, rval, type, xargc; + in_port_t portnum; + url_t urltype; + + host = path = dir = file = user = pass = NULL; + port = NULL; + rval = 1; + type = TYPE_I; + + if (STRNEQUAL(url, FTP_URL)) { + if ((parse_url(url, "URL", &urltype, &user, &pass, + &host, &port, &portnum, &path) == -1) || + (user != NULL && *user == '\0') || + EMPTYSTRING(host)) { + warnx("Invalid URL `%s'", url); + goto cleanup_fetch_ftp; + } + /* + * Note: Don't url_decode(path) here. We need to keep the + * distinction between "/" and "%2F" until later. + */ + + /* check for trailing ';type=[aid]' */ + if (! EMPTYSTRING(path) && (cp = strrchr(path, ';')) != NULL) { + if (strcasecmp(cp, ";type=a") == 0) + type = TYPE_A; + else if (strcasecmp(cp, ";type=i") == 0) + type = TYPE_I; + else if (strcasecmp(cp, ";type=d") == 0) { + warnx( + "Directory listing via a URL is not supported"); + goto cleanup_fetch_ftp; + } else { + warnx("Invalid suffix `%s' in URL `%s'", cp, + url); + goto cleanup_fetch_ftp; + } + *cp = 0; + } + } else { /* classic style `[user@]host:[file]' */ + urltype = CLASSIC_URL_T; + host = xstrdup(url); + cp = strchr(host, '@'); + if (cp != NULL) { + *cp = '\0'; + user = host; + anonftp = 0; /* disable anonftp */ + host = xstrdup(cp + 1); + } + cp = strchr(host, ':'); + if (cp != NULL) { + *cp = '\0'; + path = xstrdup(cp + 1); + } + } + if (EMPTYSTRING(host)) + goto cleanup_fetch_ftp; + + /* Extract the file and (if present) directory name. */ + dir = path; + if (! EMPTYSTRING(dir)) { + /* + * If we are dealing with classic `[user@]host:[path]' syntax, + * then a path of the form `/file' (resulting from input of the + * form `host:/file') means that we should do "CWD /" before + * retrieving the file. So we set dir="/" and file="file". + * + * But if we are dealing with URLs like `ftp://host/path' then + * a path of the form `/file' (resulting from a URL of the form + * `ftp://host//file') means that we should do `CWD ' (with an + * empty argument) before retrieving the file. So we set + * dir="" and file="file". + * + * If the path does not contain / at all, we set dir=NULL. + * (We get a path without any slashes if we are dealing with + * classic `[user@]host:[file]' or URL `ftp://host/file'.) + * + * In all other cases, we set dir to a string that does not + * include the final '/' that separates the dir part from the + * file part of the path. (This will be the empty string if + * and only if we are dealing with a path of the form `/file' + * resulting from an URL of the form `ftp://host//file'.) + */ + cp = strrchr(dir, '/'); + if (cp == dir && urltype == CLASSIC_URL_T) { + file = cp + 1; + dir = "/"; + } else if (cp != NULL) { + *cp++ = '\0'; + file = cp; + } else { + file = dir; + dir = NULL; + } + } else + dir = NULL; + if (urltype == FTP_URL_T && file != NULL) { + url_decode(file); + /* but still don't url_decode(dir) */ + } + if (debug) + fprintf(ttyout, + "fetch_ftp: user `%s' pass `%s' host %s port %s " + "path `%s' dir `%s' file `%s'\n", + user ? user : "", pass ? pass : "", + host ? host : "", port ? port : "", + path ? path : "", + dir ? dir : "", file ? file : ""); + + dirhasglob = filehasglob = 0; + if (doglob && urltype == CLASSIC_URL_T) { + if (! EMPTYSTRING(dir) && strpbrk(dir, "*?[]{}") != NULL) + dirhasglob = 1; + if (! EMPTYSTRING(file) && strpbrk(file, "*?[]{}") != NULL) + filehasglob = 1; + } + + /* Set up the connection */ + if (connected) + disconnect(0, NULL); + xargv[0] = (char *)getprogname(); /* XXX discards const */ + xargv[1] = host; + xargv[2] = NULL; + xargc = 2; + if (port) { + xargv[2] = port; + xargv[3] = NULL; + xargc = 3; + } + oautologin = autologin; + /* don't autologin in setpeer(), use ftp_login() below */ + autologin = 0; + setpeer(xargc, xargv); + autologin = oautologin; + if ((connected == 0) || + (connected == 1 && !ftp_login(host, user, pass))) { + warnx("Can't connect or login to host `%s'", host); + goto cleanup_fetch_ftp; + } + + switch (type) { + case TYPE_A: + setascii(1, xargv); + break; + case TYPE_I: + setbinary(1, xargv); + break; + default: + errx(1, "fetch_ftp: unknown transfer type %d", type); + } + + /* + * Change directories, if necessary. + * + * Note: don't use EMPTYSTRING(dir) below, because + * dir=="" means something different from dir==NULL. + */ + if (dir != NULL && !dirhasglob) { + char *nextpart; + + /* + * If we are dealing with a classic `[user@]host:[path]' + * (urltype is CLASSIC_URL_T) then we have a raw directory + * name (not encoded in any way) and we can change + * directories in one step. + * + * If we are dealing with an `ftp://host/path' URL + * (urltype is FTP_URL_T), then RFC 1738 says we need to + * send a separate CWD command for each unescaped "/" + * in the path, and we have to interpret %hex escaping + * *after* we find the slashes. It's possible to get + * empty components here, (from multiple adjacent + * slashes in the path) and RFC 1738 says that we should + * still do `CWD ' (with a null argument) in such cases. + * + * Many ftp servers don't support `CWD ', so if there's an + * error performing that command, bail out with a descriptive + * message. + * + * Examples: + * + * host: dir="", urltype=CLASSIC_URL_T + * logged in (to default directory) + * host:file dir=NULL, urltype=CLASSIC_URL_T + * "RETR file" + * host:dir/ dir="dir", urltype=CLASSIC_URL_T + * "CWD dir", logged in + * ftp://host/ dir="", urltype=FTP_URL_T + * logged in (to default directory) + * ftp://host/dir/ dir="dir", urltype=FTP_URL_T + * "CWD dir", logged in + * ftp://host/file dir=NULL, urltype=FTP_URL_T + * "RETR file" + * ftp://host//file dir="", urltype=FTP_URL_T + * "CWD ", "RETR file" + * host:/file dir="/", urltype=CLASSIC_URL_T + * "CWD /", "RETR file" + * ftp://host///file dir="/", urltype=FTP_URL_T + * "CWD ", "CWD ", "RETR file" + * ftp://host/%2F/file dir="%2F", urltype=FTP_URL_T + * "CWD /", "RETR file" + * ftp://host/foo/file dir="foo", urltype=FTP_URL_T + * "CWD foo", "RETR file" + * ftp://host/foo/bar/file dir="foo/bar" + * "CWD foo", "CWD bar", "RETR file" + * ftp://host//foo/bar/file dir="/foo/bar" + * "CWD ", "CWD foo", "CWD bar", "RETR file" + * ftp://host/foo//bar/file dir="foo//bar" + * "CWD foo", "CWD ", "CWD bar", "RETR file" + * ftp://host/%2F/foo/bar/file dir="%2F/foo/bar" + * "CWD /", "CWD foo", "CWD bar", "RETR file" + * ftp://host/%2Ffoo/bar/file dir="%2Ffoo/bar" + * "CWD /foo", "CWD bar", "RETR file" + * ftp://host/%2Ffoo%2Fbar/file dir="%2Ffoo%2Fbar" + * "CWD /foo/bar", "RETR file" + * ftp://host/%2Ffoo%2Fbar%2Ffile dir=NULL + * "RETR /foo/bar/file" + * + * Note that we don't need `dir' after this point. + */ + do { + if (urltype == FTP_URL_T) { + nextpart = strchr(dir, '/'); + if (nextpart) { + *nextpart = '\0'; + nextpart++; + } + url_decode(dir); + } else + nextpart = NULL; + if (debug) + fprintf(ttyout, "dir `%s', nextpart `%s'\n", + dir ? dir : "", + nextpart ? nextpart : ""); + if (urltype == FTP_URL_T || *dir != '\0') { + xargv[0] = "cd"; + xargv[1] = dir; + xargv[2] = NULL; + dirchange = 0; + cd(2, xargv); + if (! dirchange) { + if (*dir == '\0' && code == 500) + fprintf(stderr, +"\n" +"ftp: The `CWD ' command (without a directory), which is required by\n" +" RFC 1738 to support the empty directory in the URL pathname (`//'),\n" +" conflicts with the server's conformance to RFC 959.\n" +" Try the same URL without the `//' in the URL pathname.\n" +"\n"); + goto cleanup_fetch_ftp; + } + } + dir = nextpart; + } while (dir != NULL); + } + + if (EMPTYSTRING(file)) { + rval = -1; + goto cleanup_fetch_ftp; + } + + if (dirhasglob) { + (void)strlcpy(rempath, dir, sizeof(rempath)); + (void)strlcat(rempath, "/", sizeof(rempath)); + (void)strlcat(rempath, file, sizeof(rempath)); + file = rempath; + } + + /* Fetch the file(s). */ + xargc = 2; + xargv[0] = "get"; + xargv[1] = file; + xargv[2] = NULL; + if (dirhasglob || filehasglob) { + int ointeractive; + + ointeractive = interactive; + interactive = 0; + if (restartautofetch) + xargv[0] = "mreget"; + else + xargv[0] = "mget"; + mget(xargc, xargv); + interactive = ointeractive; + } else { + if (outfile == NULL) { + cp = strrchr(file, '/'); /* find savefile */ + if (cp != NULL) + outfile = cp + 1; + else + outfile = file; + } + xargv[2] = (char *)outfile; + xargv[3] = NULL; + xargc++; + if (restartautofetch) + reget(xargc, xargv); + else + get(xargc, xargv); + } + + if ((code / 100) == COMPLETE) + rval = 0; + + cleanup_fetch_ftp: + FREEPTR(host); + FREEPTR(path); + FREEPTR(user); + FREEPTR(pass); + return (rval); +} + +/* + * Retrieve the given file to outfile. + * Supports arguments of the form: + * "host:path", "ftp://host/path" if $ftpproxy, call fetch_url() else + * call fetch_ftp() + * "http://host/path" call fetch_url() to use HTTP + * "file:///path" call fetch_url() to copy + * "about:..." print a message + * + * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection + * is still open (e.g, ftp xfer with trailing /) + */ +static int +go_fetch(const char *url) +{ + char *proxy; + +#ifndef NO_ABOUT + /* + * Check for about:* + */ + if (STRNEQUAL(url, ABOUT_URL)) { + url += sizeof(ABOUT_URL) -1; + if (strcasecmp(url, "ftp") == 0 || + strcasecmp(url, "tnftp") == 0) { + fputs( +"This version of ftp has been enhanced by Luke Mewburn \n" +"for the NetBSD project. Execute `man ftp' for more details.\n", ttyout); + } else if (strcasecmp(url, "lukem") == 0) { + fputs( +"Luke Mewburn is the author of most of the enhancements in this ftp client.\n" +"Please email feedback to .\n", ttyout); + } else if (strcasecmp(url, "netbsd") == 0) { + fputs( +"NetBSD is a freely available and redistributable UNIX-like operating system.\n" +"For more information, see http://www.NetBSD.org/\n", ttyout); + } else if (strcasecmp(url, "version") == 0) { + fprintf(ttyout, "Version: %s %s%s\n", + FTP_PRODUCT, FTP_VERSION, +#ifdef INET6 + "" +#else + " (-IPv6)" +#endif + ); + } else { + fprintf(ttyout, "`%s' is an interesting topic.\n", url); + } + fputs("\n", ttyout); + return (0); + } +#endif + + /* + * Check for file:// and http:// URLs. + */ + if (STRNEQUAL(url, HTTP_URL) || STRNEQUAL(url, FILE_URL)) + return (fetch_url(url, NULL, NULL, NULL)); + + /* + * Try FTP URL-style and host:file arguments next. + * If ftpproxy is set with an FTP URL, use fetch_url() + * Othewise, use fetch_ftp(). + */ + proxy = getoptionvalue("ftp_proxy"); + if (!EMPTYSTRING(proxy) && STRNEQUAL(url, FTP_URL)) + return (fetch_url(url, NULL, NULL, NULL)); + + return (fetch_ftp(url)); +} + +/* + * Retrieve multiple files from the command line, + * calling go_fetch() for each file. + * + * If an ftp path has a trailing "/", the path will be cd-ed into and + * the connection remains open, and the function will return -1 + * (to indicate the connection is alive). + * If an error occurs the return value will be the offset+1 in + * argv[] of the file that caused a problem (i.e, argv[x] + * returns x+1) + * Otherwise, 0 is returned if all files retrieved successfully. + */ +int +auto_fetch(int argc, char *argv[]) +{ + volatile int argpos; + int rval; + + argpos = 0; + + if (sigsetjmp(toplevel, 1)) { + if (connected) + disconnect(0, NULL); + if (rval > 0) + rval = argpos + 1; + return (rval); + } + (void)xsignal(SIGINT, intr); + (void)xsignal(SIGPIPE, lostpeer); + + /* + * Loop through as long as there's files to fetch. + */ + for (rval = 0; (rval == 0) && (argpos < argc); argpos++) { + if (strchr(argv[argpos], ':') == NULL) + break; + redirect_loop = 0; + if (!anonftp) + anonftp = 2; /* Handle "automatic" transfers. */ + rval = go_fetch(argv[argpos]); + if (outfile != NULL && strcmp(outfile, "-") != 0 + && outfile[0] != '|') + outfile = NULL; + if (rval > 0) + rval = argpos + 1; + } + + if (connected && rval != -1) + disconnect(0, NULL); + return (rval); +} + + +int +auto_put(int argc, char **argv, const char *uploadserver) +{ + char *uargv[4], *path, *pathsep; + int uargc, rval, len; + + uargc = 0; + uargv[uargc++] = "mput"; + uargv[uargc++] = argv[0]; + uargv[2] = uargv[3] = NULL; + pathsep = NULL; + rval = 1; + + if (debug) + fprintf(ttyout, "auto_put: target `%s'\n", uploadserver); + + path = xstrdup(uploadserver); + len = strlen(path); + if (path[len - 1] != '/' && path[len - 1] != ':') { + /* + * make sure we always pass a directory to auto_fetch + */ + if (argc > 1) { /* more than one file to upload */ + int len; + + len = strlen(uploadserver) + 2; /* path + "/" + "\0" */ + free(path); + path = (char *)xmalloc(len); + (void)strlcpy(path, uploadserver, len); + (void)strlcat(path, "/", len); + } else { /* single file to upload */ + uargv[0] = "put"; + pathsep = strrchr(path, '/'); + if (pathsep == NULL) { + pathsep = strrchr(path, ':'); + if (pathsep == NULL) { + warnx("Invalid URL `%s'", path); + goto cleanup_auto_put; + } + pathsep++; + uargv[2] = xstrdup(pathsep); + pathsep[0] = '/'; + } else + uargv[2] = xstrdup(pathsep + 1); + pathsep[1] = '\0'; + uargc++; + } + } + if (debug) + fprintf(ttyout, "auto_put: URL `%s' argv[2] `%s'\n", + path, uargv[2] ? uargv[2] : ""); + + /* connect and cwd */ + rval = auto_fetch(1, &path); + free(path); + if(rval >= 0) + goto cleanup_auto_put; + + /* XXX : is this the best way? */ + if (uargc == 3) { + uargv[1] = argv[0]; + put(uargc, uargv); + goto cleanup_auto_put; + } + + for(; argv[0] != NULL; argv++) { + uargv[1] = argv[0]; + mput(uargc, uargv); + } + rval = 0; + + cleanup_auto_put: + FREEPTR(uargv[2]); + return (rval); +} diff --git a/src/bin/network/ftp/ftp.1 b/src/bin/network/ftp/ftp.1 new file mode 100644 index 0000000000..917980f408 --- /dev/null +++ b/src/bin/network/ftp/ftp.1 @@ -0,0 +1,2357 @@ +.\" $NetBSD: ftp.1,v 1.109 2005/02/20 20:54:01 wiz Exp $ +.\" +.\" Copyright (c) 1996-2004 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Luke Mewburn. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" +.\" Copyright (c) 1985, 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94 +.\" +.Dd January 15, 2005 +.Dt FTP 1 +.Os +.Sh NAME +.Nm ftp +.Nd +Internet file transfer program +.Sh SYNOPSIS +.Nm +.Op Fl 46AadefginpRtvV +.Bk -words +.Op Fl N Ar netrc +.Ek +.Bk -words +.Op Fl o Ar output +.Ek +.Bk -words +.Op Fl P Ar port +.Ek +.Bk -words +.Op Fl q Ar quittime +.Ek +.Bk -words +.Op Fl r Ar retry +.Ek +.Bk -words +.\" [-T dir,max[,inc]] +.Oo +.Fl T Xo +.Sm off +.Ar dir , +.Ar max +.Op , Ar inc +.Sm on +.Xc +.Oc +.Ek +.Bk -words +.\" [[user@]host [port]] +.Oo +.Oo Ar user Ns Li \&@ Oc Ns Ar host +.Op Ar port +.Oc +.Ek +.Bk -words +.\" [[user@]host:[path][/]] +.Sm off +.Oo +.Op Ar user Li \&@ +.Ar host Li \&: +.Op Ar path +.Op Li / +.Oc +.Sm on +.Ek +.Bk -words +.\" [file:///path] +.Sm off +.Oo +.Li file:/// Ar path +.Oc +.Sm on +.Ek +.Bk -words +.\" [ftp://[user[:password]@]host[:port]/path[/]] +.Sm off +.Oo +.Li ftp:// +.Oo Ar user +.Op Li \&: Ar password +.Li \&@ Oc +.Ar host Oo Li \&: Ar port Oc +.Li / Ar path +.Op Li / +.Op Li ;type= Ar X +.Oc +.Sm on +.Ek +.Bk -words +.\" [http://[user[:password]@]host[:port]/path] +.Sm off +.Oo +.Li http:// +.Oo Ar user +.Op Li \&: Ar password +.Li \&@ Oc +.Ar host Oo Li \&: Ar port Oc +.Li / Ar path +.Oc +.Sm on +.Ek +.Op Ar \&.\&.\&. +.Nm +.Bk -words +.Fl u Ar URL Ar file +.Ek +.Op Ar \&.\&.\&. +.Sh DESCRIPTION +.Nm +is the user interface to the Internet standard File Transfer Protocol. +The program allows a user to transfer files to and from a +remote network site. +.Pp +The last five arguments will fetch a file using the +.Tn FTP +or +.Tn HTTP +protocols, or by direct copying, into the current directory. +This is ideal for scripts. +Refer to +.Sx AUTO-FETCHING FILES +below for more information. +.Pp +Options may be specified at the command line, or to the +command interpreter. +.Bl -tag -width "port " +.It Fl 4 +Forces +.Nm +to only use IPv4 addresses. +.It Fl 6 +Forces +.Nm +to only use IPv6 addresses. +.It Fl A +Force active mode ftp. +By default, +.Nm +will try to use passive mode ftp and fall back to active mode +if passive is not supported by the server. +This option causes +.Nm +to always use an active connection. +It is only useful for connecting to very old servers that do not +implement passive mode properly. +.It Fl a +Causes +.Nm +to bypass normal login procedure, and use an anonymous login instead. +.It Fl d +Enables debugging. +.It Fl e +Disables command line editing. +This is useful for Emacs ange-ftp mode. +.It Fl f +Forces a cache reload for transfers that go through the +.Tn FTP +or +.Tn HTTP +proxies. +.It Fl g +Disables file name globbing. +.It Fl i +Turns off interactive prompting during +multiple file transfers. +.It Fl n +Restrains +.Nm +from attempting +.Dq auto-login +upon initial connection for non auto-fetch transfers. +If auto-login is enabled, +.Nm +will check the +.Pa .netrc +(see below) file in the user's home directory for an entry describing +an account on the remote machine. +If no entry exists, +.Nm +will prompt for the remote machine login name (default is the user +identity on the local machine), and, if necessary, prompt for a password +and an account with which to login. +To override the auto-login for auto-fetch transfers, specify the +username (and optionally, password) as appropriate. +.It Fl N Ar netrc +Use +.Ar netrc +instead of +.Pa ~/.netrc . +Refer to +.Sx THE .netrc FILE +for more information. +.It Fl o Ar output +When auto-fetching files, save the contents in +.Ar output . +.Ar output +is parsed according to the +.Sx FILE NAMING CONVENTIONS +below. +If +.Ar output +is not +.Sq - +or doesn't start with +.Sq \&| , +then only the first file specified will be retrieved into +.Ar output ; +all other files will be retrieved into the basename of their +remote name. +.It Fl p +Enable passive mode operation for use behind connection filtering firewalls. +This option has been deprecated as +.Nm +now tries to use passive mode by default, falling back to active mode +if the server does not support passive connections. +.It Fl P Ar port +Sets the port number to +.Ar port . +.It Fl r Ar wait +Retry the connection attempt if it failed, pausing for +.Ar wait +seconds. +.It Fl q Ar quittime +Quit if the connection has stalled for +.Ar quittime +seconds. +.It Fl R +Restart all non-proxied auto-fetches. +.It Fl t +Enables packet tracing. +.It Xo +.Fl T +.Sm off +.Ar direction , +.Ar maximum +.Op , Ar increment +.Sm on +.Xc +Set the maximum transfer rate for +.Ar direction +to +.Ar maximum +bytes/second, +and if specified, the increment to +.Ar increment +bytes/second. +Refer to +.Ic rate +for more information. +.It Fl u Ar URL file Op \&.\&.\&. +Upload files on the command line to +.Ar URL +where +.Ar URL +is one of the ftp URL types as supported by auto-fetch +(with an optional target filename for single file uploads), and +.Ar file +is one or more local files to be uploaded. +.It Fl v +Enable +.Ic verbose +and +.Ic progress . +This is the default if output is to a terminal (and in the case of +.Ic progress , +.Nm +is the foreground process). +Forces +.Nm +to show all responses from the remote server, as well +as report on data transfer statistics. +.It Fl V +Disable +.Ic verbose +and +.Ic progress , +overriding the default of enabled when output is to a terminal. +.El +.Pp +The client host with which +.Nm +is to communicate may be specified on the command line. +If this is done, +.Nm +will immediately attempt to establish a connection to an +.Tn FTP +server on that host; otherwise, +.Nm +will enter its command interpreter and await instructions +from the user. +When +.Nm +is awaiting commands from the user the prompt +.Ql ftp\*[Gt] +is provided to the user. +The following commands are recognized +by +.Nm ftp : +.Bl -tag -width Fl +.It Ic \&! Op Ar command Op Ar args +Invoke an interactive shell on the local machine. +If there are arguments, the first is taken to be a command to execute +directly, with the rest of the arguments as its arguments. +.It Ic \&$ Ar macro-name Op Ar args +Execute the macro +.Ar macro-name +that was defined with the +.Ic macdef +command. +Arguments are passed to the macro unglobbed. +.It Ic account Op Ar passwd +Supply a supplemental password required by a remote system for access +to resources once a login has been successfully completed. +If no argument is included, the user will be prompted for an account +password in a non-echoing input mode. +.It Ic append Ar local-file Op Ar remote-file +Append a local file to a file on the remote machine. +If +.Ar remote-file +is left unspecified, the local file name is used in naming the +remote file after being altered by any +.Ic ntrans +or +.Ic nmap +setting. +File transfer uses the current settings for +.Ic type , +.Ic format , +.Ic mode , +and +.Ic structure . +.It Ic ascii +Set the file transfer +.Ic type +to network +.Tn ASCII . +This is the default type. +.It Ic bell +Arrange that a bell be sounded after each file transfer +command is completed. +.It Ic binary +Set the file transfer +.Ic type +to support binary image transfer. +.It Ic bye +Terminate the +.Tn FTP +session with the remote server +and exit +.Nm ftp . +An end of file will also terminate the session and exit. +.It Ic case +Toggle remote computer file name case mapping during +.Ic get , +.Ic mget +and +.Ic mput +commands. +When +.Ic case +is on (default is off), remote computer file names with all letters in +upper case are written in the local directory with the letters mapped +to lower case. +.It Ic \&cd Ar remote-directory +Change the working directory on the remote machine +to +.Ar remote-directory . +.It Ic cdup +Change the remote machine working directory to the parent of the +current remote machine working directory. +.It Ic chmod Ar mode remote-file +Change the permission modes of the file +.Ar remote-file +on the remote +system to +.Ar mode . +.It Ic close +Terminate the +.Tn FTP +session with the remote server, and +return to the command interpreter. +Any defined macros are erased. +.It Ic \&cr +Toggle carriage return stripping during +ascii type file retrieval. +Records are denoted by a carriage return/linefeed sequence +during ascii type file transfer. +When +.Ic \&cr +is on (the default), carriage returns are stripped from this +sequence to conform with the +.Ux +single linefeed record +delimiter. +Records on +.Pf non\- Ns Ux +remote systems may contain single linefeeds; +when an ascii type transfer is made, these linefeeds may be +distinguished from a record delimiter only when +.Ic \&cr +is off. +.It Ic debug Op Ar debug-value +Toggle debugging mode. +If an optional +.Ar debug-value +is specified it is used to set the debugging level. +When debugging is on, +.Nm +prints each command sent to the remote machine, preceded +by the string +.Ql \-\-\*[Gt] +.It Ic delete Ar remote-file +Delete the file +.Ar remote-file +on the remote machine. +.It Ic dir Op Ar remote-path Op Ar local-file +Print a listing of the contents of a +directory on the remote machine. +The listing includes any system-dependent information that the server +chooses to include; for example, most +.Ux +systems will produce +output from the command +.Ql ls \-l . +If +.Ar remote-path +is left unspecified, the current working directory is used. +If interactive prompting is on, +.Nm +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic dir +output. +If no local file is specified, or if +.Ar local-file +is +.Sq Fl , +the output is sent to the terminal. +.It Ic disconnect +A synonym for +.Ic close . +.It Ic edit +Toggle command line editing, and context sensitive command and file +completion. +This is automatically enabled if input is from a terminal, and +disabled otherwise. +.It Ic epsv4 +Toggle the use of the extended +.Dv EPSV +and +.Dv EPRT +commands on IPv4 connections; first try +.Dv EPSV / +.Dv EPRT , +and then +.Dv PASV / +.Dv PORT . +This is enabled by default. +If an extended command fails then this option will be temporarily +disabled for the duration of the current connection, or until +.Ic epsv4 +is executed again. +.It Ic exit +A synonym for +.Ic bye . +.It Ic features +Display what features the remote server supports (using the +.Dv FEAT +command). +.It Ic fget Ar localfile +Retrieve the files listed in +.Ar localfile , +which has one line per filename. +.It Ic form Ar format +Set the file transfer +.Ic form +to +.Ar format . +The default (and only supported) +format is +.Dq non-print . +.It Ic ftp Ar host Op Ar port +A synonym for +.Ic open . +.It Ic gate Op Ar host Op Ar port +Toggle gate-ftp mode, which used to connect through the +TIS FWTK and Gauntlet ftp proxies. +This will not be permitted if the gate-ftp server hasn't been set +(either explicitly by the user, or from the +.Ev FTPSERVER +environment variable). +If +.Ar host +is given, +then gate-ftp mode will be enabled, and the gate-ftp server will be set to +.Ar host . +If +.Ar port +is also given, that will be used as the port to connect to on the +gate-ftp server. +.It Ic get Ar remote-file Op Ar local-file +Retrieve the +.Ar remote-file +and store it on the local machine. +If the local +file name is not specified, it is given the same +name it has on the remote machine, subject to +alteration by the current +.Ic case , +.Ic ntrans , +and +.Ic nmap +settings. +The current settings for +.Ic type , +.Ic form , +.Ic mode , +and +.Ic structure +are used while transferring the file. +.It Ic glob +Toggle filename expansion for +.Ic mdelete , +.Ic mget , +.Ic mput , +and +.Ic mreget . +If globbing is turned off with +.Ic glob , +the file name arguments +are taken literally and not expanded. +Globbing for +.Ic mput +is done as in +.Xr csh 1 . +For +.Ic mdelete , +.Ic mget , +and +.Ic mreget , +each remote file name is expanded +separately on the remote machine and the lists are not merged. +Expansion of a directory name is likely to be +different from expansion of the name of an ordinary file: +the exact result depends on the foreign operating system and ftp server, +and can be previewed by doing +.Ql mls remote-files \- +Note: +.Ic mget , +.Ic mput +and +.Ic mreget +are not meant to transfer +entire directory subtrees of files. +That can be done by +transferring a +.Xr tar 1 +archive of the subtree (in binary mode). +.It Ic hash Op Ar size +Toggle hash-sign (``#'') printing for each data block +transferred. +The size of a data block defaults to 1024 bytes. +This can be changed by specifying +.Ar size +in bytes. +Enabling +.Ic hash +disables +.Ic progress . +.It Ic help Op Ar command +Print an informative message about the meaning of +.Ar command . +If no argument is given, +.Nm +prints a list of the known commands. +.It Ic idle Op Ar seconds +Set the inactivity timer on the remote server to +.Ar seconds +seconds. +If +.Ar seconds +is omitted, the current inactivity timer is printed. +.It Ic image +A synonym for +.Ic binary . +.It Ic lcd Op Ar directory +Change the working directory on the local machine. +If +no +.Ar directory +is specified, the user's home directory is used. +.It Ic less Ar file +A synonym for +.Ic page . +.It Ic lpage Ar local-file +Display +.Ar local-file +with the program specified by the +.Ic "set pager" +option. +.It Ic lpwd +Print the working directory on the local machine. +.It Ic \&ls Op Ar remote-path Op Ar local-file +A synonym for +.Ic dir . +.It Ic macdef Ar macro-name +Define a macro. +Subsequent lines are stored as the macro +.Ar macro-name ; +a null line (consecutive newline characters +in a file or +carriage returns from the terminal) terminates macro input mode. +There is a limit of 16 macros and 4096 total characters in all +defined macros. +Macros remain defined until a +.Ic close +command is executed. +The macro processor interprets `$' and `\e' as special characters. +A `$' followed by a number (or numbers) is replaced by the +corresponding argument on the macro invocation command line. +A `$' followed by an `i' signals that macro processor that the +executing macro is to be looped. +On the first pass `$i' is +replaced by the first argument on the macro invocation command line, +on the second pass it is replaced by the second argument, and so on. +A `\e' followed by any character is replaced by that character. +Use the `\e' to prevent special treatment of the `$'. +.It Ic mdelete Op Ar remote-files +Delete the +.Ar remote-files +on the remote machine. +.It Ic mdir Ar remote-files local-file +Like +.Ic dir , +except multiple remote files may be specified. +If interactive prompting is on, +.Nm +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic mdir +output. +.It Ic mget Ar remote-files +Expand the +.Ar remote-files +on the remote machine +and do a +.Ic get +for each file name thus produced. +See +.Ic glob +for details on the filename expansion. +Resulting file names will then be processed according to +.Ic case , +.Ic ntrans , +and +.Ic nmap +settings. +Files are transferred into the local working directory, +which can be changed with +.Ql lcd directory ; +new local directories can be created with +.Ql "\&! mkdir directory" . +.It Ic mkdir Ar directory-name +Make a directory on the remote machine. +.It Ic mls Ar remote-files local-file +Like +.Ic ls , +except multiple remote files may be specified, +and the +.Ar local-file +must be specified. +If interactive prompting is on, +.Nm +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic mls +output. +.It Ic mlsd Op Ar remote-path +Display the contents of +.Ar remote-path +(which should default to the current directory if not given) +in a machine-parsable form, using +.Dv MLSD . +The format of display can be changed with +.Sq "remopts mlst ..." . +.It Ic mlst Op Ar remote-path +Display the details about +.Ar remote-path +(which should default to the current directory if not given) +in a machine-parsable form, using +.Dv MLST . +The format of display can be changed with +.Sq "remopts mlst ..." . +.It Ic mode Ar mode-name +Set the file transfer +.Ic mode +to +.Ar mode-name . +The default (and only supported) +mode is +.Dq stream . +.It Ic modtime Ar remote-file +Show the last modification time of the file on the remote machine. +.It Ic more Ar file +A synonym for +.Ic page . +.It Ic mput Ar local-files +Expand wild cards in the list of local files given as arguments +and do a +.Ic put +for each file in the resulting list. +See +.Ic glob +for details of filename expansion. +Resulting file names will then be processed according to +.Ic ntrans +and +.Ic nmap +settings. +.It Ic mreget Ar remote-files +As per +.Ic mget , +but performs a +.Ic reget +instead of +.Ic get . +.It Ic msend Ar local-files +A synonym for +.Ic mput . +.It Ic newer Ar remote-file Op Ar local-file +Get the file only if the modification time of the remote file is more +recent that the file on the current system. +If the file does not +exist on the current system, the remote file is considered +.Ic newer . +Otherwise, this command is identical to +.Ar get . +.It Ic nlist Op Ar remote-path Op Ar local-file +A synonym for +.Ic ls . +.It Ic nmap Op Ar inpattern outpattern +Set or unset the filename mapping mechanism. +If no arguments are specified, the filename mapping mechanism is unset. +If arguments are specified, remote filenames are mapped during +.Ic mput +commands and +.Ic put +commands issued without a specified remote target filename. +If arguments are specified, local filenames are mapped during +.Ic mget +commands and +.Ic get +commands issued without a specified local target filename. +This command is useful when connecting to a +.No non\- Ns Ux +remote computer +with different file naming conventions or practices. +The mapping follows the pattern set by +.Ar inpattern +and +.Ar outpattern . +.Op Ar Inpattern +is a template for incoming filenames (which may have already been +processed according to the +.Ic ntrans +and +.Ic case +settings). +Variable templating is accomplished by including the +sequences `$1', `$2', ..., `$9' in +.Ar inpattern . +Use `\\' to prevent this special treatment of the `$' character. +All other characters are treated literally, and are used to determine the +.Ic nmap +.Op Ar inpattern +variable values. +For example, given +.Ar inpattern +$1.$2 and the remote file name "mydata.data", $1 would have the value +"mydata", and $2 would have the value "data". +The +.Ar outpattern +determines the resulting mapped filename. +The sequences `$1', `$2', ...., `$9' are replaced by any value resulting +from the +.Ar inpattern +template. +The sequence `$0' is replace by the original filename. +Additionally, the sequence +.Ql Op Ar seq1 , Ar seq2 +is replaced by +.Op Ar seq1 +if +.Ar seq1 +is not a null string; otherwise it is replaced by +.Ar seq2 . +For example, the command +.Pp +.Bd -literal -offset indent -compact +nmap $1.$2.$3 [$1,$2].[$2,file] +.Ed +.Pp +would yield +the output filename "myfile.data" for input filenames "myfile.data" and +"myfile.data.old", "myfile.file" for the input filename "myfile", and +"myfile.myfile" for the input filename ".myfile". +Spaces may be included in +.Ar outpattern , +as in the example: `nmap $1 sed "s/ *$//" \*[Gt] $1' . +Use the `\e' character to prevent special treatment +of the `$','[',']', and `,' characters. +.It Ic ntrans Op Ar inchars Op Ar outchars +Set or unset the filename character translation mechanism. +If no arguments are specified, the filename character +translation mechanism is unset. +If arguments are specified, characters in +remote filenames are translated during +.Ic mput +commands and +.Ic put +commands issued without a specified remote target filename. +If arguments are specified, characters in +local filenames are translated during +.Ic mget +commands and +.Ic get +commands issued without a specified local target filename. +This command is useful when connecting to a +.No non\- Ns Ux +remote computer +with different file naming conventions or practices. +Characters in a filename matching a character in +.Ar inchars +are replaced with the corresponding character in +.Ar outchars . +If the character's position in +.Ar inchars +is longer than the length of +.Ar outchars , +the character is deleted from the file name. +.It Ic open Ar host Op Ar port +Establish a connection to the specified +.Ar host +.Tn FTP +server. +An optional port number may be supplied, +in which case, +.Nm +will attempt to contact an +.Tn FTP +server at that port. +If the +.Ic "set auto-login" +option is on (default), +.Nm +will also attempt to automatically log the user in to +the +.Tn FTP +server (see below). +.It Ic page Ar file +Retrieve +.Ic file +and display with the program specified by the +.Ic "set pager" +option. +.It Ic passive Op Cm auto +Toggle passive mode (if no arguments are given). +If +.Cm auto +is given, act as if +.Ev FTPMODE +is set to +.Sq auto . +If passive mode is turned on (default), +.Nm +will send a +.Dv PASV +command for all data connections instead of a +.Dv PORT +command. +The +.Dv PASV +command requests that the remote server open a port for the data connection +and return the address of that port. +The remote server listens on that port and the client connects to it. +When using the more traditional +.Dv PORT +command, the client listens on a port and sends that address to the remote +server, who connects back to it. +Passive mode is useful when using +.Nm +through a gateway router or host that controls the directionality of +traffic. +(Note that though +.Tn FTP +servers are required to support the +.Dv PASV +command by +.Li RFC 1123 , +some do not.) +.It Ic pdir Op Ar remote-path +Perform +.Ic dir +.Op Ar remote-path , +and display the result with the program specified by the +.Ic "set pager" +option. +.It Ic pls Op Ar remote-path +Perform +.Ic ls +.Op Ar remote-path , +and display the result with the program specified by the +.Ic "set pager" +option. +.It Ic pmlsd Op Ar remote-path +Perform +.Ic mlsd +.Op Ar remote-path , +and display the result with the program specified by the +.Ic "set pager" +option. +.It Ic preserve +Toggle preservation of modification times on retrieved files. +.It Ic progress +Toggle display of transfer progress bar. +The progress bar will be disabled for a transfer that has +.Ar local-file +as +.Sq Fl +or a command that starts with +.Sq \&| . +Refer to +.Sx FILE NAMING CONVENTIONS +for more information. +Enabling +.Ic progress +disables +.Ic hash . +.It Ic prompt +Toggle interactive prompting. +Interactive prompting +occurs during multiple file transfers to allow the +user to selectively retrieve or store files. +If prompting is turned off (default is on), any +.Ic mget +or +.Ic mput +will transfer all files, and any +.Ic mdelete +will delete all files. +.Pp +When prompting is on, the following commands are available at a prompt: +.Bl -tag -width 2n -offset indent +.It Cm a +Answer +.Sq yes +to the current file, and automatically answer +.Sq yes +to any remaining files for the current command. +.It Cm n +Answer +.Sq no , +and do not transfer the file. +.It Cm p +Answer +.Sq yes +to the current file, and turn off prompt mode +(as is +.Dq prompt off +had been given). +.It Cm q +Terminate the current operation. +.It Cm y +Answer +.Sq yes , +and transfer the file. +.It Cm \&? +Display a help message. +.El +.Pp +Any other response will answer +.Sq yes +to the current file. +.It Ic proxy Ar ftp-command +Execute an ftp command on a secondary control connection. +This command allows simultaneous connection to two remote +.Tn FTP +servers for transferring files between the two servers. +The first +.Ic proxy +command should be an +.Ic open , +to establish the secondary control connection. +Enter the command "proxy ?" to see other +.Tn FTP +commands executable on the secondary connection. +The following commands behave differently when prefaced by +.Ic proxy : +.Ic open +will not define new macros during the auto-login process, +.Ic close +will not erase existing macro definitions, +.Ic get +and +.Ic mget +transfer files from the host on the primary control connection +to the host on the secondary control connection, and +.Ic put , +.Ic mput , +and +.Ic append +transfer files from the host on the secondary control connection +to the host on the primary control connection. +Third party file transfers depend upon support of the +.Tn FTP +protocol +.Dv PASV +command by the server on the secondary control connection. +.It Ic put Ar local-file Op Ar remote-file +Store a local file on the remote machine. +If +.Ar remote-file +is left unspecified, the local file name is used +after processing according to any +.Ic ntrans +or +.Ic nmap +settings +in naming the remote file. +File transfer uses the +current settings for +.Ic type , +.Ic format , +.Ic mode , +and +.Ic structure . +.It Ic pwd +Print the name of the current working directory on the remote +machine. +.It Ic quit +A synonym for +.Ic bye . +.It Ic quote Ar arg1 arg2 ... +The arguments specified are sent, verbatim, to the remote +.Tn FTP +server. +.It Xo +.Ic rate Ar direction +.Op Ar maximum Op Ar increment +.Xc +Throttle the maximum transfer rate to +.Ar maximum +bytes/second. +If +.Ar maximum +is 0, disable the throttle. +.Pp +.Ar direction +may be one of: +.Bl -tag -width "all" -offset indent -compact +.It Cm all +Both directions. +.It Cm get +Incoming transfers. +.It Cm put +Outgoing transfers. +.El +.Pp +.Ar maximum +can be modified on the fly by +.Ar increment +bytes (default: 1024) each time a given signal is received: +.B +.Bl -tag -width "SIGUSR1" -offset indent +.It Dv SIGUSR1 +Increment +.Ar maximum +by +.Ar increment +bytes. +.It Dv SIGUSR2 +Decrement +.Ar maximum +by +.Ar increment +bytes. +The result must be a positive number. +.El +.Pp +If +.Ar maximum +is not supplied, the current throttle rates are displayed. +.Pp +Note: +.Ic rate +is not yet implemented for ascii mode transfers. +.It Ic rcvbuf Ar size +Set the size of the socket receive buffer to +.Ar size . +.It Ic recv Ar remote-file Op Ar local-file +A synonym for +.Ic get . +.It Ic reget Ar remote-file Op Ar local-file +.Ic reget +acts like +.Ic get , +except that if +.Ar local-file +exists and is +smaller than +.Ar remote-file , +.Ar local-file +is presumed to be +a partially transferred copy of +.Ar remote-file +and the transfer +is continued from the apparent point of failure. +This command +is useful when transferring very large files over networks that +are prone to dropping connections. +.It Ic remopts Ar command Op Ar command-options +Set options on the remote +.Tn FTP +server for +.Ar command +to +.Ar command-options +(whose absence is handled on a command-specific basis). +Remote +.Tn FTP +commands known to support options include: +.Sq MLST +(used for +.Dv MLSD +and +.Dv MLST ) . +.It Ic rename Op Ar from Op Ar to +Rename the file +.Ar from +on the remote machine, to the file +.Ar to . +.It Ic reset +Clear reply queue. +This command re-synchronizes command/reply sequencing with the remote +.Tn FTP +server. +Resynchronization may be necessary following a violation of the +.Tn FTP +protocol by the remote server. +.It Ic restart Ar marker +Restart the immediately following +.Ic get +or +.Ic put +at the +indicated +.Ar marker . +On +.Ux +systems, marker is usually a byte +offset into the file. +.It Ic rhelp Op Ar command-name +Request help from the remote +.Tn FTP +server. +If a +.Ar command-name +is specified it is supplied to the server as well. +.It Ic rmdir Ar directory-name +Delete a directory on the remote machine. +.It Ic rstatus Op Ar remote-file +With no arguments, show status of remote machine. +If +.Ar remote-file +is specified, show status of +.Ar remote-file +on remote machine. +.It Ic runique +Toggle storing of files on the local system with unique filenames. +If a file already exists with a name equal to the target +local filename for a +.Ic get +or +.Ic mget +command, a ".1" is appended to the name. +If the resulting name matches another existing file, +a ".2" is appended to the original name. +If this process continues up to ".99", an error +message is printed, and the transfer does not take place. +The generated unique filename will be reported. +Note that +.Ic runique +will not affect local files generated from a shell command +(see below). +The default value is off. +.It Ic send Ar local-file Op Ar remote-file +A synonym for +.Ic put . +.It Ic sendport +Toggle the use of +.Dv PORT +commands. +By default, +.Nm +will attempt to use a +.Dv PORT +command when establishing +a connection for each data transfer. +The use of +.Dv PORT +commands can prevent delays +when performing multiple file transfers. +If the +.Dv PORT +command fails, +.Nm +will use the default data port. +When the use of +.Dv PORT +commands is disabled, no attempt will be made to use +.Dv PORT +commands for each data transfer. +This is useful +for certain +.Tn FTP +implementations which do ignore +.Dv PORT +commands but, incorrectly, indicate they've been accepted. +.It Ic set Op Ar option Ar value +Set +.Ar option +to +.Ar value . +If +.Ar option +and +.Ar value +are not given, display all of the options and their values. +The currently supported options are: +.Bl -tag -width "http_proxy" -offset indent +.It Cm anonpass +Defaults to +.Ev $FTPANONPASS +.It Cm ftp_proxy +Defaults to +.Ev $ftp_proxy . +.It Cm http_proxy +Defaults to +.Ev $http_proxy . +.It Cm no_proxy +Defaults to +.Ev $no_proxy . +.It Cm pager +Defaults to +.Ev $PAGER . +.It Cm prompt +Defaults to +.Ev $FTPPROMPT . +.It Cm rprompt +Defaults to +.Ev $FTPRPROMPT . +.El +.It Ic site Ar arg1 arg2 ... +The arguments specified are sent, verbatim, to the remote +.Tn FTP +server as a +.Dv SITE +command. +.It Ic size Ar remote-file +Return size of +.Ar remote-file +on remote machine. +.It Ic sndbuf Ar size +Set the size of the socket send buffer to +.Ar size . +.It Ic status +Show the current status of +.Nm ftp . +.It Ic struct Ar struct-name +Set the file transfer +.Ar structure +to +.Ar struct-name . +The default (and only supported) +structure is +.Dq file . +.It Ic sunique +Toggle storing of files on remote machine under unique file names. +The remote +.Tn FTP +server must support +.Tn FTP +protocol +.Dv STOU +command for +successful completion. +The remote server will report unique name. +Default value is off. +.It Ic system +Show the type of operating system running on the remote machine. +.It Ic tenex +Set the file transfer type to that needed to +talk to +.Tn TENEX +machines. +.It Ic throttle +A synonym for +.Ic rate . +.It Ic trace +Toggle packet tracing. +.It Ic type Op Ar type-name +Set the file transfer +.Ic type +to +.Ar type-name . +If no type is specified, the current type +is printed. +The default type is network +.Tn ASCII . +.It Ic umask Op Ar newmask +Set the default umask on the remote server to +.Ar newmask . +If +.Ar newmask +is omitted, the current umask is printed. +.It Ic unset Ar option +Unset +.Ar option . +Refer to +.Ic set +for more information. +.It Ic usage Ar command +Print the usage message for +.Ar command . +.It Xo +.Ic user Ar user-name +.Op Ar password Op Ar account +.Xc +Identify yourself to the remote +.Tn FTP +server. +If the +.Ar password +is not specified and the server requires it, +.Nm +will prompt the user for it (after disabling local echo). +If an +.Ar account +field is not specified, and the +.Tn FTP +server +requires it, the user will be prompted for it. +If an +.Ar account +field is specified, an account command will +be relayed to the remote server after the login sequence +is completed if the remote server did not require it +for logging in. +Unless +.Nm +is invoked with +.Dq auto-login +disabled, this process is done automatically on initial connection to the +.Tn FTP +server. +.It Ic verbose +Toggle verbose mode. +In verbose mode, all responses from +the +.Tn FTP +server are displayed to the user. +In addition, +if verbose is on, when a file transfer completes, statistics +regarding the efficiency of the transfer are reported. +By default, +verbose is on. +.It Ic xferbuf Ar size +Set the size of the socket send and receive buffers to +.Ar size . +.It Ic \&? Op Ar command +A synonym for +.Ic help . +.El +.Pp +Command arguments which have embedded spaces may be quoted with +quote `"' marks. +.Pp +Commands which toggle settings can take an explicit +.Ic on +or +.Ic off +argument to force the setting appropriately. +.Pp +Commands which take a byte count as an argument +(e.g., +.Ic hash , +.Ic rate , +and +.Ic xferbuf ) +support an optional suffix on the argument which changes the +interpretation of the argument. +Supported suffixes are: +.Bl -tag -width 3n -offset indent -compact +.It Li b +Causes no modification. +(Optional) +.It Li k +Kilo; multiply the argument by 1024 +.It Li m +Mega; multiply the argument by 1048576 +.It Li g +Giga; multiply the argument by 1073741824 +.El +.Pp +If +.Nm +receives a +.Dv SIGINFO +(see the +.Dq status +argument of +.Xr stty 1 ) +or +.Dv SIGQUIT +signal whilst a transfer is in progress, the current transfer rate +statistics will be written to the standard error output, in the +same format as the standard completion message. +.Sh AUTO-FETCHING FILES +In addition to standard commands, this version of +.Nm +supports an auto-fetch feature. +To enable auto-fetch, simply pass the list of hostnames/files +on the command line. +.Pp +The following formats are valid syntax for an auto-fetch element: +.Bl -tag -width "FOO " +.\" [user@]host:[path][/] +.It Xo +.Sm off +.Op Ar user Li \&@ +.Ar host Li \&: +.Op Ar path +.Op Li / +.Sm on +.Xc +.Dq Classic +.Tn FTP +format. +.Pp +If +.Ar path +contains a glob character and globbing is enabled, +(see +.Ic glob ) , +then the equivalent of +.Ql mget path +is performed. +.Pp +If the directory component of +.Ar path +contains no globbing characters, +it is stored locally with the name basename (see +.Xr basename 1 ) +of +.Ic path , +in the current directory. +Otherwise, the full remote name is used as the local name, +relative to the local root directory. +.\" ftp://[user[:password]@]host[:port]/path[/][;type=X] +.It Xo +.Sm off +.Li ftp:// +.Oo Ar user +.Op Li \&: Ar password +.Li \&@ Oc +.Ar host Oo Li \&: Ar port Oc +.Li / Ar path +.Op Li / +.Op Li ;type= Ar X +.Sm on +.Xc +An +.Tn FTP +URL, retrieved using the +.Tn FTP +protocol if +.Ic "set ftp_proxy" +isn't defined. +Otherwise, transfer the URL using +.Tn HTTP +via the proxy defined in +.Ic "set ftp_proxy" . +If +.Ic "set ftp_proxy" +isn't defined and +.Ar user +is given, login as +.Ar user . +In this case, use +.Ar password +if supplied, otherwise prompt the user for one. +.Pp +If a suffix of +.Sq ;type=A +or +.Sq ;type=I +is supplied, then the transfer type will take place as +ascii or binary (respectively). +The default transfer type is binary. +.Pp +In order to be compliant with +.Li RFC 1738 , +.Nm +interprets the +.Ar path +part of an +.Dq ftp:// +auto-fetch URL as follows: +.Bl -bullet +.It +The +.Sq Li / +immediately after the +.Ar host Ns Oo Li \&: Ns Ar port Oc +is interpreted as a separator before the +.Ar path , +and not as part of the +.Ar path +itself. +.It +The +.Ar path +is interpreted as a +.So Li / Sc Ns -separated +list of name components. +For all but the last such component, +.Nm +performs the equivalent of a +.Ic cd +command. +For the last path component, +.Nm +performs the equivalent of a +.Ic get +command. +.It +Empty name components, +which result from +.Sq Li // +within the +.Ar path , +or from an extra +.Sq Li / +at the beginning of the +.Ar path , +will cause the equivalent of a +.Ic cd +command without a directory name. +This is unlikely to be useful. +.It +Any +.Sq Li \&% Ns Ar XX +codes +(per +.Li RFC 1738 ) +within the path components are decoded, with +.Ar XX +representing a character code in hexadecimal. +This decoding takes place after the +.Ar path +has been split into components, +but before each component is used in the equivalent of a +.Ic cd +or +.Ic get +command. +Some often-used codes are +.Sq Li \&%2F +(which represents +.Sq Li / ) +and +.Sq Li \&%7E +(which represents +.Sq Li ~ ) . +.El +.Pp +The above interpretation has the following consequences: +.Bl -bullet +.It +The path is interpreted relative to the +default login directory of the specified user or of the +.Sq anonymous +user. +If the +.Pa / +directory is required, use a leading path of +.Dq %2F . +If a user's home directory is required (and the remote server supports +the syntax), use a leading path of +.Dq %7Euser/ . +For example, to retrieve +.Pa /etc/motd +from +.Sq localhost +as the user +.Sq myname +with the password +.Sq mypass , +use +.Dq ftp://myname:mypass@localhost/%2fetc/motd +.It +The exact +.Ic cd +and +.Ic get +commands can be controlled by careful choice of +where to use +.Sq / +and where to use +.Sq %2F +(or +.Sq %2f ) . +For example, the following URLs correspond to the +equivalents of the indicated commands: +.Bl -tag -width "ftp://host/%2Fdir1%2Fdir2%2Ffile" +.It ftp://host/dir1/dir2/file +.Dq "cd dir1" , +.Dq "cd dir2" , +.Dq "get file" . +.It ftp://host/%2Fdir1/dir2/file +.Dq "cd /dir1" , +.Dq "cd dir2" , +.Dq "get file" . +.It ftp://host/dir1%2Fdir2/file +.Dq "cd dir1/dir2" , +.Dq "get file" . +.It ftp://host/%2Fdir1%2Fdir2/file +.Dq "cd /dir1/dir2" , +.Dq "get file" . +.It ftp://host/dir1%2Fdir2%2Ffile +.Dq "get dir1/dir2/file" . +.It ftp://host/%2Fdir1%2Fdir2%2Ffile +.Dq "get /dir1/dir2/file" . +.El +.It +You must have appropriate access permission for each of the +intermediate directories that is used in the equivalent of a +.Ic cd +command. +.El +.\" http://[user[:password]@]host[:port]/path +.It Xo +.Sm off +.Li http:// +.Oo Ar user +.Op Li \&: Ar password +.Li \&@ Oc +.Ar host Oo Li \&: Ar port Oc +.Li / Ar path +.Sm on +.Xc +An +.Tn HTTP +URL, retrieved using the +.Tn HTTP +protocol. +If +.Ic "set http_proxy" +is defined, it is used as a URL to an +.Tn HTTP +proxy server. +If +.Tn HTTP +authorization is required to retrieve +.Ar path , +and +.Sq user +(and optionally +.Sq password ) +is in the URL, use them for the first attempt to authenticate. +.\" file:///path +.It Xo +.Sm off +.Li file:/// Ar path +.Sm on +.Xc +A local URL, copied from +.Pa / Ns Ar path +on the local host. +.El +.Pp +Unless noted otherwise above, and +.Fl o Ar output +is not given, the file is stored in the current directory as the +.Xr basename 1 +of +.Ar path . +Note that if a +.Tn HTTP +redirect is received, the fetch is retried using the new target URL +supplied by the server, with a corresponding new +.Ar path . +Using an explicit +.Fl o Ar output +is recommended, to avoid writing to unexpected file names. +.Pp +If a classic format or an +.Tn FTP +URL format has a trailing +.Sq / +or an empty +.Ar path +component, then +.Nm +will connect to the site and +.Ic cd +to the directory given as the path, and leave the user in interactive +mode ready for further input. +This will not work if +.Ic "set ftp_proxy" +is being used. +.Pp +Direct +.Tn HTTP +transfers use HTTP 1.1. +Proxied +.Tn FTP +and +.Tn HTTP +transfers use HTTP 1.0. +.Pp +If +.Fl R +is given, all auto-fetches that don't go via the +.Tn FTP +or +.Tn HTTP +proxies will be restarted. +For +.Tn FTP , +this is implemented by using +.Nm reget +instead of +.Nm get . +For +.Tn HTTP , +this is implemented by using the +.Sq "Range: bytes=" +.Tn "HTTP/1.1" +directive. +.Pp +If WWW or proxy WWW authentication is required, you will be prompted +to enter a username and password to authenticate with. +.Pp +When specifying IPv6 numeric addresses in a URL, you need to +surround the address in square brackets. +E.g.: +.Dq ftp://[::1]:21/ . +This is because colons are used in IPv6 numeric address as well as +being the separator for the port number. +.Sh ABORTING A FILE TRANSFER +To abort a file transfer, use the terminal interrupt key +(usually Ctrl-C). +Sending transfers will be immediately halted. +Receiving transfers will be halted by sending an +.Tn FTP +protocol +.Dv ABOR +command to the remote server, and discarding any further data received. +The speed at which this is accomplished depends upon the remote +server's support for +.Dv ABOR +processing. +If the remote server does not support the +.Dv ABOR +command, the prompt will not appear until the remote server has completed +sending the requested file. +.Pp +If the terminal interrupt key sequence is used whilst +.Nm +is awaiting a reply from the remote server for the ABOR processing, +then the connection will be closed. +This is different from the traditional behaviour (which ignores the +terminal interrupt during this phase), but is considered more useful. +.Sh FILE NAMING CONVENTIONS +Files specified as arguments to +.Nm +commands are processed according to the following rules. +.Bl -enum +.It +If the file name +.Sq Fl +is specified, the +.Ar stdin +(for reading) or +.Ar stdout +(for writing) is used. +.It +If the first character of the file name is +.Sq \&| , +the +remainder of the argument is interpreted as a shell command. +.Nm +then forks a shell, using +.Xr popen 3 +with the argument supplied, and reads (writes) from the stdout +(stdin). +If the shell command includes spaces, the argument +must be quoted; e.g. +.Dq Qq Li \&| ls\ \-lt . +A particularly +useful example of this mechanism is: +.Dq Li dir \&"\&" \&|more . +.It +Failing the above checks, if ``globbing'' is enabled, +local file names are expanded +according to the rules used in the +.Xr csh 1 ; +c.f. the +.Ic glob +command. +If the +.Nm +command expects a single local file (e.g. +.Ic put ) , +only the first filename generated by the "globbing" operation is used. +.It +For +.Ic mget +commands and +.Ic get +commands with unspecified local file names, the local filename is +the remote filename, which may be altered by a +.Ic case , +.Ic ntrans , +or +.Ic nmap +setting. +The resulting filename may then be altered if +.Ic runique +is on. +.It +For +.Ic mput +commands and +.Ic put +commands with unspecified remote file names, the remote filename is +the local filename, which may be altered by a +.Ic ntrans +or +.Ic nmap +setting. +The resulting filename may then be altered by the remote server if +.Ic sunique +is on. +.El +.Sh FILE TRANSFER PARAMETERS +The +.Tn FTP +specification specifies many parameters which may affect a file transfer. +The +.Ic type +may be one of +.Dq ascii , +.Dq image +(binary), +.Dq ebcdic , +and +.Dq local byte size +(for +.Tn PDP Ns -10's +and +.Tn PDP Ns -20's +mostly). +.Nm +supports the ascii and image types of file transfer, +plus local byte size 8 for +.Ic tenex +mode transfers. +.Pp +.Nm +supports only the default values for the remaining +file transfer parameters: +.Ic mode , +.Ic form , +and +.Ic struct . +.Sh THE .netrc FILE +The +.Pa .netrc +file contains login and initialization information +used by the auto-login process. +It resides in the user's home directory, +unless overridden with the +.Fl N Ar netrc +option, or specified in the +.Ev NETRC +environment variable. +The following tokens are recognized; they may be separated by spaces, +tabs, or new-lines: +.Bl -tag -width password +.It Ic machine Ar name +Identify a remote machine +.Ar name . +The auto-login process searches the +.Pa .netrc +file for a +.Ic machine +token that matches the remote machine specified on the +.Nm +command line or as an +.Ic open +command argument. +Once a match is made, the subsequent +.Pa .netrc +tokens are processed, +stopping when the end of file is reached or another +.Ic machine +or a +.Ic default +token is encountered. +.It Ic default +This is the same as +.Ic machine +.Ar name +except that +.Ic default +matches any name. +There can be only one +.Ic default +token, and it must be after all +.Ic machine +tokens. +This is normally used as: +.Pp +.Dl default login anonymous password user@site +.Pp +thereby giving the user an automatic anonymous +.Tn FTP +login to +machines not specified in +.Pa .netrc . +This can be overridden +by using the +.Fl n +flag to disable auto-login. +.It Ic login Ar name +Identify a user on the remote machine. +If this token is present, the auto-login process will initiate +a login using the specified +.Ar name . +.It Ic password Ar string +Supply a password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires a password as part +of the login process. +Note that if this token is present in the +.Pa .netrc +file for any user other +than +.Ar anonymous , +.Nm +will abort the auto-login process if the +.Pa .netrc +is readable by +anyone besides the user. +.It Ic account Ar string +Supply an additional account password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires an additional +account password, or the auto-login process will initiate an +.Dv ACCT +command if it does not. +.It Ic macdef Ar name +Define a macro. +This token functions like the +.Nm +.Ic macdef +command functions. +A macro is defined with the specified name; its contents begin with the +next +.Pa .netrc +line and continue until a blank line (consecutive new-line +characters) is encountered. +If a macro named +.Ic init +is defined, it is automatically executed as the last step in the +auto-login process. +For example, +.Bd -literal -offset indent +default +macdef init +epsv4 off +.Ed +.Pp +followed by a blank line. +.El +.Sh COMMAND LINE EDITING +.Nm +supports interactive command line editing, via the +.Xr editline 3 +library. +It is enabled with the +.Ic edit +command, and is enabled by default if input is from a tty. +Previous lines can be recalled and edited with the arrow keys, +and other GNU Emacs-style editing keys may be used as well. +.Pp +The +.Xr editline 3 +library is configured with a +.Pa .editrc +file - refer to +.Xr editrc 5 +for more information. +.Pp +An extra key binding is available to +.Nm +to provide context sensitive command and filename completion +(including remote file completion). +To use this, bind a key to the +.Xr editline 3 +command +.Ic ftp-complete . +By default, this is bound to the TAB key. +.Sh COMMAND LINE PROMPT +By default, +.Nm +displays a command line prompt of +.Dq "ftp\*[Gt] " +to the user. +This can be changed with the +.Ic "set prompt" +command. +.Pp +A prompt can be displayed on the right side of the screen (after the +command input) with the +.Ic "set rprompt" +command. +.Pp +The following formatting sequences are replaced by the given +information: +.Bl -tag -width "%% " -offset indent +.It Li \&%/ +The current remote working directory. +.\" %c[[0]n], %.[[0]n] +.It Xo +.Sm off +.Li \&%c +.Op Oo Li 0 Oc Ar n Ns , +.Li \&%. +.Op Oo Li 0 Oc Ar n +.Sm on +.Xc +The trailing component of the current remote working directory, or +.Em n +trailing components if a digit +.Em n +is given. +If +.Em n +begins with +.Sq 0 , +the number of skipped components precede the trailing component(s) in +the format +.\" ``/trailing'' +.Do +.Sm off +.Li / Li \*[Lt] Va number Li \*[Gt] +.Va trailing +.Sm on +.Dc +(for +.Sq \&%c ) +or +.\" ``...trailing'' +.Dq Li \&... Ns Va trailing +(for +.Sq \&%. ) . +.It Li \&%M +The remote host name. +.It Li \&%m +The remote host name, up to the first +.Sq \&. . +.It Li \&%n +The remote user name. +.It Li \&%% +A single +.Sq % . +.El +.Sh ENVIRONMENT +.Nm +uses the following environment variables. +.Bl -tag -width "FTPSERVERPORT" +.It Ev FTPANONPASS +Password to send in an anonymous +.Tn FTP +transfer. +Defaults to +.Dq Li `whoami`@ . +.It Ev FTPMODE +Overrides the default operation mode. +Support values are: +.Bl -tag -width "passive" +.It Cm active +active mode +.Tn FTP +only +.It Cm auto +automatic determination of passive or active (this is the default) +.It Cm gate +gate-ftp mode +.It Cm passive +passive mode +.Tn FTP +only +.El +.It Ev FTPPROMPT +Command-line prompt to use. +Defaults to +.Dq "ftp\*[Gt] " . +Refer to +.Sx COMMAND LINE PROMPT +for more information. +.It Ev FTPRPROMPT +Command-line right side prompt to use. +Defaults to +.Dq "" . +Refer to +.Sx COMMAND LINE PROMPT +for more information. +.It Ev FTPSERVER +Host to use as gate-ftp server when +.Ic gate +is enabled. +.It Ev FTPSERVERPORT +Port to use when connecting to gate-ftp server when +.Ic gate +is enabled. +Default is port returned by a +.Fn getservbyname +lookup of +.Dq ftpgate/tcp . +.It Ev FTPUSERAGENT +The value to send for the +.Tn HTTP +User-Agent +header. +.It Ev HOME +For default location of a +.Pa .netrc +file, if one exists. +.It Ev NETRC +An alternate location of the +.Pa .netrc +file. +.It Ev PAGER +Used by various commands to display files. +Defaults to +.Xr more 1 +if empty or not set. +.It Ev SHELL +For default shell. +.It Ev ftp_proxy +URL of +.Tn FTP +proxy to use when making +.Tn FTP +URL requests +(if not defined, use the standard +.Tn FTP +protocol). +.Pp +See +.Ev http_proxy +for further notes about proxy use. +.It Ev http_proxy +URL of +.Tn HTTP +proxy to use when making +.Tn HTTP +URL requests. +If proxy authentication is required and there is a username and +password in this URL, they will automatically be used in the first +attempt to authenticate to the proxy. +.Pp +If +.Dq unsafe +URL characters are required in the username or password +(for example +.Sq @ +or +.Sq / ) , +encode them with +.Li RFC 1738 +.Sq Li \&% Ns Ar XX +encoding. +.Pp +Note that the use of a username and password in +.Ev ftp_proxy +and +.Ev http_proxy +may be incompatible with other programs that use it +(such as +.Xr lynx 1 ) . +.Pp +.Em NOTE : +this is not used for interactive sessions, only for command-line +fetches. +.It Ev no_proxy +A space or comma separated list of hosts (or domains) for which +proxying is not to be used. +Each entry may have an optional trailing ":port", which restricts +the matching to connections to that port. +.El +.Sh EXTENDED PASSIVE MODE AND FIREWALLS +Some firewall configurations do not allow +.Nm +to use extended passive mode. +If you find that even a simple +.Ic ls +appears to hang after printing a message such as this: +.Pp +.Dl 229 Entering Extended Passive Mode (|||58551|) +.Pp +then you will need to disable extended passive mode with +.Ic epsv4 off . +See the above section +.Sx The .netrc File +for an example of how to make this automatic. +.Sh SEE ALSO +.Xr getservbyname 3 , +.Xr editrc 5 , +.Xr services 5 , +.Xr ftpd 8 +.Sh STANDARDS +.Nm +attempts to be compliant with +.Li RFC 959 , +.Li RFC 1123 , +.Li RFC 1738 , +.Li RFC 2068 , +.Li RFC 2389 , +.Li RFC 2428 , +.Li RFC 2732 , +and +.Cm draft-ietf-ftpext-mlst-11 . +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . +.Pp +Various features such as command line editing, context sensitive +command and file completion, dynamic progress bar, automatic +fetching of files and URLs, modification time preservation, +transfer rate throttling, configurable command line prompt, +and other enhancements over the standard +.Bx +.Nm +were implemented in +.Nx 1.3 +and later releases +by +.An Luke Mewburn +.Aq lukem@NetBSD.org . +.Pp +IPv6 support was added by the WIDE/KAME project +(but may not be present in all non-NetBSD versions of this program, depending +if the operating system supports IPv6 in a similar manner to KAME). +.Sh BUGS +Correct execution of many commands depends upon proper behavior +by the remote server. +.Pp +An error in the treatment of carriage returns +in the +.Bx 4.2 +ascii-mode transfer code +has been corrected. +This correction may result in incorrect transfers of binary files +to and from +.Bx 4.2 +servers using the ascii type. +Avoid this problem by using the binary image type. +.Pp +.Nm +assumes that all IPv4 mapped addresses +.Po +IPv6 addresses with a form like +.Li ::ffff:10.1.1.1 +.Pc +indicate IPv4 destinations which can be handled by +.Dv AF_INET +sockets. +However, in certain IPv6 network configurations, this assumption is not true. +In such an environment, IPv4 mapped addresses must be passed to +.Dv AF_INET6 +sockets directly. +For example, if your site uses a SIIT translator for IPv6-to-IPv4 translation, +.Nm +is unable to support your configuration. diff --git a/src/bin/network/ftp/ftp.c b/src/bin/network/ftp/ftp.c new file mode 100644 index 0000000000..70b0d916e9 --- /dev/null +++ b/src/bin/network/ftp/ftp.c @@ -0,0 +1,2163 @@ +/* $NetBSD: ftp.c,v 1.132 2005/05/14 15:26:43 lukem Exp $ */ + +/*- + * Copyright (c) 1996-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) 1997 and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +volatile sig_atomic_t abrtflag; +volatile sig_atomic_t timeoutflag; + +sigjmp_buf ptabort; +int ptabflg; +int ptflag = 0; +char pasv[BUFSIZ]; /* passive port for proxy data connection */ + +static int empty(FILE *, FILE *, int); + +struct sockinet { + union sockunion { + struct sockaddr_in su_sin; +#ifdef INET6 + struct sockaddr_in6 su_sin6; +#endif + } si_su; +#if !HAVE_SOCKADDR_SA_LEN + int si_len; +#endif +}; + +#if !HAVE_SOCKADDR_SA_LEN +# define su_len si_len +#else +# define su_len si_su.su_sin.sin_len +#endif +#define su_family si_su.su_sin.sin_family +#define su_port si_su.su_sin.sin_port + +struct sockinet myctladdr, hisctladdr, data_addr; + +char * +hookup(char *host, char *port) +{ + int s = -1, error, portnum; + struct addrinfo hints, *res, *res0; + char hbuf[MAXHOSTNAMELEN]; + static char hostnamebuf[MAXHOSTNAMELEN]; + char *cause = "unknown"; + socklen_t len; + int on = 1; + + memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); + memset((char *)&myctladdr, 0, sizeof (myctladdr)); + memset(&hints, 0, sizeof(hints)); + portnum = parseport(port, FTP_PORT); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + warnx("%s", gai_strerror(error)); + code = -1; + return (0); + } + + if (res0->ai_canonname) + (void)strlcpy(hostnamebuf, res0->ai_canonname, + sizeof(hostnamebuf)); + else + (void)strlcpy(hostnamebuf, host, sizeof(hostnamebuf)); + hostname = hostnamebuf; + + for (res = res0; res; res = res->ai_next) { + /* + * make sure that ai_addr is NOT an IPv4 mapped address. + * IPv4 mapped address complicates too many things in FTP + * protocol handling, as FTP protocol is defined differently + * between IPv4 and IPv6. + * + * This may not be the best way to handle this situation, + * since the semantics of IPv4 mapped address is defined in + * the kernel. There are configurations where we should use + * IPv4 mapped address as native IPv6 address, not as + * "an IPv6 address that embeds IPv4 address" (namely, SIIT). + * + * More complete solution would be to have an additional + * getsockopt to grab "real" peername/sockname. "real" + * peername/sockname will be AF_INET if IPv4 mapped address + * is used to embed IPv4 address, and will be AF_INET6 if + * we use it as native. What a mess! + */ + ai_unmapped(res); +#if 0 /*old behavior*/ + if (res != res0) /* not on the first address */ +#else + if (res0->ai_next) /* if we have multiple possibilities */ +#endif + { + if (getnameinfo(res->ai_addr, res->ai_addrlen, + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) + strlcpy(hbuf, "?", sizeof(hbuf)); + fprintf(ttyout, "Trying %s...\n", hbuf); + } + ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(portnum); + s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol); + if (s < 0) { + cause = "socket"; + continue; + } + error = xconnect(s, res->ai_addr, res->ai_addrlen); + if (error) { + /* this "if" clause is to prevent print warning twice */ + if (res->ai_next) { + if (getnameinfo(res->ai_addr, res->ai_addrlen, + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) + strlcpy(hbuf, "?", sizeof(hbuf)); + warn("connect to address %s", hbuf); + } + cause = "connect"; + close(s); + s = -1; + continue; + } + + /* finally we got one */ + break; + } + if (s < 0) { + warn("%s", cause); + code = -1; + freeaddrinfo(res0); + return 0; + } + memcpy(&hisctladdr.si_su, res->ai_addr, res->ai_addrlen); + hisctladdr.su_len = res->ai_addrlen; + freeaddrinfo(res0); + res0 = res = NULL; + + len = hisctladdr.su_len; + if (getsockname(s, (struct sockaddr *)&myctladdr.si_su, &len) == -1) { + warn("getsockname"); + code = -1; + goto bad; + } + myctladdr.su_len = len; + +#ifdef IPTOS_LOWDELAY + if (hisctladdr.su_family == AF_INET) { + int tos = IPTOS_LOWDELAY; + if (setsockopt(s, IPPROTO_IP, IP_TOS, + (void *)&tos, sizeof(tos)) == -1) { + if (debug) + warn("setsockopt %s (ignored)", + "IPTOS_LOWDELAY"); + } + } +#endif + cin = fdopen(s, "r"); + cout = fdopen(s, "w"); + if (cin == NULL || cout == NULL) { + warnx("fdopen failed."); + if (cin) + (void)fclose(cin); + if (cout) + (void)fclose(cout); + code = -1; + goto bad; + } + if (verbose) + fprintf(ttyout, "Connected to %s.\n", hostname); + if (getreply(0) > 2) { /* read startup message from server */ + if (cin) + (void)fclose(cin); + if (cout) + (void)fclose(cout); + code = -1; + goto bad; + } + + if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, + (void *)&on, sizeof(on)) == -1) { + if (debug) + warn("setsockopt %s (ignored)", "SO_OOBINLINE"); + } + + return (hostname); + bad: + (void)close(s); + return (NULL); +} + +void +cmdabort(int notused) +{ + int oerrno = errno; + + sigint_raised = 1; + alarmtimer(0); + if (fromatty) + write(fileno(ttyout), "\n", 1); + abrtflag++; + if (ptflag) + siglongjmp(ptabort, 1); + errno = oerrno; +} + +void +cmdtimeout(int notused) +{ + int oerrno = errno; + + alarmtimer(0); + if (fromatty) + write(fileno(ttyout), "\n", 1); + timeoutflag++; + if (ptflag) + siglongjmp(ptabort, 1); + errno = oerrno; +} + +/*VARARGS*/ +int +command(const char *fmt, ...) +{ + va_list ap; + int r; + sigfunc oldsigint; + + if (debug) { + fputs("---> ", ttyout); + va_start(ap, fmt); + if (strncmp("PASS ", fmt, 5) == 0) + fputs("PASS XXXX", ttyout); + else if (strncmp("ACCT ", fmt, 5) == 0) + fputs("ACCT XXXX", ttyout); + else + vfprintf(ttyout, fmt, ap); + va_end(ap); + putc('\n', ttyout); + } + if (cout == NULL) { + warnx("No control connection for command."); + code = -1; + return (0); + } + + abrtflag = 0; + + oldsigint = xsignal(SIGINT, cmdabort); + + va_start(ap, fmt); + vfprintf(cout, fmt, ap); + va_end(ap); + fputs("\r\n", cout); + (void)fflush(cout); + cpend = 1; + r = getreply(!strcmp(fmt, "QUIT")); + if (abrtflag && oldsigint != SIG_IGN) + (*oldsigint)(SIGINT); + (void)xsignal(SIGINT, oldsigint); + return (r); +} + +int +getreply(int expecteof) +{ + char current_line[BUFSIZ]; /* last line of previous reply */ + int c, n, line; + int dig; + int originalcode = 0, continuation = 0; + sigfunc oldsigint, oldsigalrm; + int pflag = 0; + char *cp, *pt = pasv; + + abrtflag = 0; + timeoutflag = 0; + + oldsigint = xsignal(SIGINT, cmdabort); + oldsigalrm = xsignal(SIGALRM, cmdtimeout); + + for (line = 0 ;; line++) { + dig = n = code = 0; + cp = current_line; + while (alarmtimer(60),((c = getc(cin)) != '\n')) { + if (c == IAC) { /* handle telnet commands */ + switch (c = getc(cin)) { + case WILL: + case WONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, DONT, c); + (void)fflush(cout); + break; + case DO: + case DONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, WONT, c); + (void)fflush(cout); + break; + default: + break; + } + continue; + } + dig++; + if (c == EOF) { + /* + * these will get trashed by pswitch() + * in lostpeer() + */ + int reply_timeoutflag = timeoutflag; + int reply_abrtflag = abrtflag; + + alarmtimer(0); + if (expecteof && feof(cin)) { + (void)xsignal(SIGINT, oldsigint); + (void)xsignal(SIGALRM, oldsigalrm); + code = 221; + return (0); + } + cpend = 0; + lostpeer(0); + if (verbose) { + if (reply_timeoutflag) + fputs( + "421 Service not available, remote server timed out. Connection closed\n", + ttyout); + else if (reply_abrtflag) + fputs( + "421 Service not available, user interrupt. Connection closed.\n", + ttyout); + else + fputs( + "421 Service not available, remote server has closed connection.\n", + ttyout); + (void)fflush(ttyout); + } + code = 421; + (void)xsignal(SIGINT, oldsigint); + (void)xsignal(SIGALRM, oldsigalrm); + return (4); + } + if (c != '\r' && (verbose > 0 || + ((verbose > -1 && n == '5' && dig > 4) && + (((!n && c < '5') || (n && n < '5')) + || !retry_connect)))) { + if (proxflag && + (dig == 1 || (dig == 5 && verbose == 0))) + fprintf(ttyout, "%s:", hostname); + (void)putc(c, ttyout); + } + if (dig < 4 && isdigit(c)) + code = code * 10 + (c - '0'); + if (!pflag && (code == 227 || code == 228)) + pflag = 1; + else if (!pflag && code == 229) + pflag = 100; + if (dig > 4 && pflag == 1 && isdigit(c)) + pflag = 2; + if (pflag == 2) { + if (c != '\r' && c != ')') { + if (pt < &pasv[sizeof(pasv) - 1]) + *pt++ = c; + } else { + *pt = '\0'; + pflag = 3; + } + } + if (pflag == 100 && c == '(') + pflag = 2; + if (dig == 4 && c == '-') { + if (continuation) + code = 0; + continuation++; + } + if (n == 0) + n = c; + if (cp < ¤t_line[sizeof(current_line) - 1]) + *cp++ = c; + } + if (verbose > 0 || ((verbose > -1 && n == '5') && + (n < '5' || !retry_connect))) { + (void)putc(c, ttyout); + (void)fflush (ttyout); + } + if (cp[-1] == '\r') + cp[-1] = '\0'; + *cp = '\0'; + if (line == 0) + (void)strlcpy(reply_string, current_line, + sizeof(reply_string)); + if (line > 0 && code == 0 && reply_callback != NULL) + (*reply_callback)(current_line); + if (continuation && code != originalcode) { + if (originalcode == 0) + originalcode = code; + continue; + } + if (n != '1') + cpend = 0; + alarmtimer(0); + (void)xsignal(SIGINT, oldsigint); + (void)xsignal(SIGALRM, oldsigalrm); + if (code == 421 || originalcode == 421) + lostpeer(0); + if (abrtflag && oldsigint != cmdabort && oldsigint != SIG_IGN) + (*oldsigint)(SIGINT); + if (timeoutflag && oldsigalrm != cmdtimeout && + oldsigalrm != SIG_IGN) + (*oldsigalrm)(SIGINT); + return (n - '0'); + } +} + +static int +empty(FILE *cin, FILE *din, int sec) +{ + int nr, nfd; + struct pollfd pfd[2]; + + nfd = 0; + if (cin) { + pfd[nfd].fd = fileno(cin); + pfd[nfd++].events = POLLIN; + } + + if (din) { + pfd[nfd].fd = fileno(din); + pfd[nfd++].events = POLLIN; + } + + if ((nr = xpoll(pfd, nfd, sec * 1000)) <= 0) + return nr; + + nr = 0; + nfd = 0; + if (cin) + nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0; + if (din) + nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0; + return nr; +} + +sigjmp_buf xferabort; + +void +abortxfer(int notused) +{ + char msgbuf[100]; + size_t len; + + sigint_raised = 1; + alarmtimer(0); + mflag = 0; + abrtflag = 0; + switch (direction[0]) { + case 'r': + strlcpy(msgbuf, "\nreceive", sizeof(msgbuf)); + break; + case 's': + strlcpy(msgbuf, "\nsend", sizeof(msgbuf)); + break; + default: + errx(1, "abortxfer called with unknown direction `%s'", + direction); + } + len = strlcat(msgbuf, " aborted. Waiting for remote to finish abort.\n", + sizeof(msgbuf)); + write(fileno(ttyout), msgbuf, len); + siglongjmp(xferabort, 1); +} + +void +sendrequest(const char *cmd, const char *local, const char *remote, + int printnames) +{ + struct stat st; + int c, d; + FILE *fin, *dout; + int (*closefunc)(FILE *); + sigfunc oldintr, oldintp; + volatile off_t hashbytes; + char *lmode, *bufp; + static size_t bufsize; + static char *buf; + int oprogress; + +#ifdef __GNUC__ /* to shut up gcc warnings */ + (void)&fin; + (void)&dout; + (void)&closefunc; + (void)&oldintr; + (void)&oldintp; + (void)&lmode; +#endif + + hashbytes = mark; + direction = "sent"; + dout = NULL; + bytes = 0; + filesize = -1; + oprogress = progress; + if (verbose && printnames) { + if (local && *local != '-') + fprintf(ttyout, "local: %s ", local); + if (remote) + fprintf(ttyout, "remote: %s\n", remote); + } + if (proxy) { + proxtrans(cmd, local, remote); + return; + } + if (curtype != type) + changetype(type, 0); + closefunc = NULL; + oldintr = NULL; + oldintp = NULL; + lmode = "w"; + if (sigsetjmp(xferabort, 1)) { + while (cpend) + (void)getreply(0); + code = -1; + goto cleanupsend; + } + (void)xsignal(SIGQUIT, psummary); + oldintr = xsignal(SIGINT, abortxfer); + if (strcmp(local, "-") == 0) { + fin = stdin; + progress = 0; + } else if (*local == '|') { + oldintp = xsignal(SIGPIPE, SIG_IGN); + fin = popen(local + 1, "r"); + if (fin == NULL) { + warn("%s", local + 1); + code = -1; + goto cleanupsend; + } + progress = 0; + closefunc = pclose; + } else { + fin = fopen(local, "r"); + if (fin == NULL) { + warn("local: %s", local); + code = -1; + goto cleanupsend; + } + closefunc = fclose; + if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) { + fprintf(ttyout, "%s: not a plain file.\n", local); + code = -1; + goto cleanupsend; + } + filesize = st.st_size; + } + if (initconn()) { + code = -1; + goto cleanupsend; + } + if (sigsetjmp(xferabort, 1)) + goto abort; + + if (restart_point && + (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { + int rc; + + rc = -1; + switch (curtype) { + case TYPE_A: + rc = fseeko(fin, restart_point, SEEK_SET); + break; + case TYPE_I: + case TYPE_L: + rc = lseek(fileno(fin), restart_point, SEEK_SET); + break; + } + if (rc < 0) { + warn("local: %s", local); + goto cleanupsend; + } + if (command("REST " LLF, (LLT)restart_point) != CONTINUE) + goto cleanupsend; + lmode = "r+"; + } + if (remote) { + if (command("%s %s", cmd, remote) != PRELIM) + goto cleanupsend; + } else { + if (command("%s", cmd) != PRELIM) + goto cleanupsend; + } + dirchange = 1; + dout = dataconn(lmode); + if (dout == NULL) + goto abort; + + if (sndbuf_size > bufsize) { + if (buf) + (void)free(buf); + bufsize = sndbuf_size; + buf = xmalloc(bufsize); + } + + progressmeter(-1); + oldintp = xsignal(SIGPIPE, SIG_IGN); + + switch (curtype) { + + case TYPE_I: + case TYPE_L: + if (rate_put) { /* rate limited */ + while (1) { + struct timeval then, now, td; + off_t bufrem; + + (void)gettimeofday(&then, NULL); + errno = c = d = 0; + bufrem = rate_put; + while (bufrem > 0) { + if ((c = read(fileno(fin), buf, + MIN(bufsize, bufrem))) <= 0) + goto senddone; + bytes += c; + bufrem -= c; + for (bufp = buf; c > 0; + c -= d, bufp += d) + if ((d = write(fileno(dout), + bufp, c)) <= 0) + break; + if (d < 0) + goto senddone; + if (hash && + (!progress || filesize < 0) ) { + while (bytes >= hashbytes) { + (void)putc('#', ttyout); + hashbytes += mark; + } + (void)fflush(ttyout); + } + } + while (1) { + (void)gettimeofday(&now, NULL); + timersub(&now, &then, &td); + if (td.tv_sec > 0) + break; + usleep(1000000 - td.tv_usec); + } + } + } else { /* simpler/faster; no rate limit */ + while (1) { + errno = c = d = 0; + if ((c = read(fileno(fin), buf, bufsize)) <= 0) + goto senddone; + bytes += c; + for (bufp = buf; c > 0; c -= d, bufp += d) + if ((d = write(fileno(dout), bufp, c)) + <= 0) + break; + if (d < 0) + goto senddone; + if (hash && (!progress || filesize < 0) ) { + while (bytes >= hashbytes) { + (void)putc('#', ttyout); + hashbytes += mark; + } + (void)fflush(ttyout); + } + } + } + senddone: + if (hash && (!progress || filesize < 0) && bytes > 0) { + if (bytes < mark) + (void)putc('#', ttyout); + (void)putc('\n', ttyout); + } + if (c < 0) + warn("local: %s", local); + if (d < 0) { + if (errno != EPIPE) + warn("netout"); + bytes = -1; + } + break; + + case TYPE_A: + while ((c = getc(fin)) != EOF) { + if (c == '\n') { + while (hash && (!progress || filesize < 0) && + (bytes >= hashbytes)) { + (void)putc('#', ttyout); + (void)fflush(ttyout); + hashbytes += mark; + } + if (ferror(dout)) + break; + (void)putc('\r', dout); + bytes++; + } + (void)putc(c, dout); + bytes++; +#if 0 /* this violates RFC */ + if (c == '\r') { + (void)putc('\0', dout); + bytes++; + } +#endif + } + if (hash && (!progress || filesize < 0)) { + if (bytes < hashbytes) + (void)putc('#', ttyout); + (void)putc('\n', ttyout); + } + if (ferror(fin)) + warn("local: %s", local); + if (ferror(dout)) { + if (errno != EPIPE) + warn("netout"); + bytes = -1; + } + break; + } + + progressmeter(1); + if (closefunc != NULL) { + (*closefunc)(fin); + fin = NULL; + } + (void)fclose(dout); + dout = NULL; + (void)getreply(0); + if (bytes > 0) + ptransfer(0); + goto cleanupsend; + + abort: + (void)xsignal(SIGINT, oldintr); + oldintr = NULL; + if (!cpend) { + code = -1; + goto cleanupsend; + } + if (data >= 0) { + (void)close(data); + data = -1; + } + if (dout) { + (void)fclose(dout); + dout = NULL; + } + (void)getreply(0); + code = -1; + if (bytes > 0) + ptransfer(0); + + cleanupsend: + if (oldintr) + (void)xsignal(SIGINT, oldintr); + if (oldintp) + (void)xsignal(SIGPIPE, oldintp); + if (data >= 0) { + (void)close(data); + data = -1; + } + if (closefunc != NULL && fin != NULL) + (*closefunc)(fin); + if (dout) + (void)fclose(dout); + progress = oprogress; + restart_point = 0; + bytes = 0; +} + +void +recvrequest(const char *cmd, const char *local, const char *remote, + const char *lmode, int printnames, int ignorespecial) +{ + FILE *fout, *din; + int (*closefunc)(FILE *); + sigfunc oldintr, oldintp; + int c, d; + volatile int is_retr, tcrflag, bare_lfs; + static size_t bufsize; + static char *buf; + volatile off_t hashbytes; + struct stat st; + time_t mtime; + struct timeval tval[2]; + int oprogress; + int opreserve; + +#ifdef __GNUC__ /* to shut up gcc warnings */ + (void)&local; + (void)&fout; + (void)&din; + (void)&closefunc; + (void)&oldintr; + (void)&oldintp; +#endif + + fout = NULL; + din = NULL; + hashbytes = mark; + direction = "received"; + bytes = 0; + bare_lfs = 0; + filesize = -1; + oprogress = progress; + opreserve = preserve; + is_retr = (strcmp(cmd, "RETR") == 0); + if (is_retr && verbose && printnames) { + if (local && (ignorespecial || *local != '-')) + fprintf(ttyout, "local: %s ", local); + if (remote) + fprintf(ttyout, "remote: %s\n", remote); + } + if (proxy && is_retr) { + proxtrans(cmd, local, remote); + return; + } + closefunc = NULL; + oldintr = NULL; + oldintp = NULL; + tcrflag = !crflag && is_retr; + if (sigsetjmp(xferabort, 1)) { + while (cpend) + (void)getreply(0); + code = -1; + goto cleanuprecv; + } + (void)xsignal(SIGQUIT, psummary); + oldintr = xsignal(SIGINT, abortxfer); + if (ignorespecial || (strcmp(local, "-") && *local != '|')) { + if (access(local, W_OK) < 0) { + char *dir = strrchr(local, '/'); + + if (errno != ENOENT && errno != EACCES) { + warn("local: %s", local); + code = -1; + goto cleanuprecv; + } + if (dir != NULL) + *dir = 0; + d = access(dir == local ? "/" : + dir ? local : ".", W_OK); + if (dir != NULL) + *dir = '/'; + if (d < 0) { + warn("local: %s", local); + code = -1; + goto cleanuprecv; + } + if (!runique && errno == EACCES && + chmod(local, (S_IRUSR|S_IWUSR)) < 0) { + warn("local: %s", local); + code = -1; + goto cleanuprecv; + } + if (runique && errno == EACCES && + (local = gunique(local)) == NULL) { + code = -1; + goto cleanuprecv; + } + } + else if (runique && (local = gunique(local)) == NULL) { + code = -1; + goto cleanuprecv; + } + } + if (!is_retr) { + if (curtype != TYPE_A) + changetype(TYPE_A, 0); + } else { + if (curtype != type) + changetype(type, 0); + filesize = remotesize(remote, 0); + if (code == 421 || code == -1) + goto cleanuprecv; + } + if (initconn()) { + code = -1; + goto cleanuprecv; + } + if (sigsetjmp(xferabort, 1)) + goto abort; + if (is_retr && restart_point && + command("REST " LLF, (LLT) restart_point) != CONTINUE) + goto cleanuprecv; + if (! EMPTYSTRING(remote)) { + if (command("%s %s", cmd, remote) != PRELIM) + goto cleanuprecv; + } else { + if (command("%s", cmd) != PRELIM) + goto cleanuprecv; + } + din = dataconn("r"); + if (din == NULL) + goto abort; + if (!ignorespecial && strcmp(local, "-") == 0) { + fout = stdout; + progress = 0; + preserve = 0; + } else if (!ignorespecial && *local == '|') { + oldintp = xsignal(SIGPIPE, SIG_IGN); + fout = popen(local + 1, "w"); + if (fout == NULL) { + warn("%s", local+1); + goto abort; + } + progress = 0; + preserve = 0; + closefunc = pclose; + } else { + fout = fopen(local, lmode); + if (fout == NULL) { + warn("local: %s", local); + goto abort; + } + closefunc = fclose; + } + + if (fstat(fileno(fout), &st) != -1 && !S_ISREG(st.st_mode)) { + progress = 0; + preserve = 0; + } + if (rcvbuf_size > bufsize) { + if (buf) + (void)free(buf); + bufsize = rcvbuf_size; + buf = xmalloc(bufsize); + } + + progressmeter(-1); + + switch (curtype) { + + case TYPE_I: + case TYPE_L: + if (is_retr && restart_point && + lseek(fileno(fout), restart_point, SEEK_SET) < 0) { + warn("local: %s", local); + goto cleanuprecv; + } + if (rate_get) { /* rate limiting */ + while (1) { + struct timeval then, now, td; + off_t bufrem; + + (void)gettimeofday(&then, NULL); + errno = c = d = 0; + for (bufrem = rate_get; bufrem > 0; ) { + if ((c = read(fileno(din), buf, + MIN(bufsize, bufrem))) <= 0) + goto recvdone; + bytes += c; + bufrem -=c; + if ((d = write(fileno(fout), buf, c)) + != c) + goto recvdone; + if (hash && + (!progress || filesize < 0)) { + while (bytes >= hashbytes) { + (void)putc('#', ttyout); + hashbytes += mark; + } + (void)fflush(ttyout); + } + } + /* sleep until time is up */ + while (1) { + (void)gettimeofday(&now, NULL); + timersub(&now, &then, &td); + if (td.tv_sec > 0) + break; + usleep(1000000 - td.tv_usec); + } + } + } else { /* faster code (no limiting) */ + while (1) { + errno = c = d = 0; + if ((c = read(fileno(din), buf, bufsize)) <= 0) + goto recvdone; + bytes += c; + if ((d = write(fileno(fout), buf, c)) != c) + goto recvdone; + if (hash && (!progress || filesize < 0)) { + while (bytes >= hashbytes) { + (void)putc('#', ttyout); + hashbytes += mark; + } + (void)fflush(ttyout); + } + } + } + recvdone: + if (hash && (!progress || filesize < 0) && bytes > 0) { + if (bytes < mark) + (void)putc('#', ttyout); + (void)putc('\n', ttyout); + } + if (c < 0) { + if (errno != EPIPE) + warn("netin"); + bytes = -1; + } + if (d < c) { + if (d < 0) + warn("local: %s", local); + else + warnx("%s: short write", local); + } + break; + + case TYPE_A: + if (is_retr && restart_point) { + int ch; + off_t i; + + if (fseeko(fout, (off_t)0, SEEK_SET) < 0) + goto done; + for (i = 0; i++ < restart_point;) { + if ((ch = getc(fout)) == EOF) + goto done; + if (ch == '\n') + i++; + } + if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) { + done: + warn("local: %s", local); + goto cleanuprecv; + } + } + while ((c = getc(din)) != EOF) { + if (c == '\n') + bare_lfs++; + while (c == '\r') { + while (hash && (!progress || filesize < 0) && + (bytes >= hashbytes)) { + (void)putc('#', ttyout); + (void)fflush(ttyout); + hashbytes += mark; + } + bytes++; + if ((c = getc(din)) != '\n' || tcrflag) { + if (ferror(fout)) + goto break2; + (void)putc('\r', fout); + if (c == '\0') { + bytes++; + goto contin2; + } + if (c == EOF) + goto contin2; + } + } + (void)putc(c, fout); + bytes++; + contin2: ; + } + break2: + if (hash && (!progress || filesize < 0)) { + if (bytes < hashbytes) + (void)putc('#', ttyout); + (void)putc('\n', ttyout); + } + if (ferror(din)) { + if (errno != EPIPE) + warn("netin"); + bytes = -1; + } + if (ferror(fout)) + warn("local: %s", local); + break; + } + + progressmeter(1); + if (closefunc != NULL) { + (*closefunc)(fout); + fout = NULL; + } + (void)fclose(din); + din = NULL; + (void)getreply(0); + if (bare_lfs) { + fprintf(ttyout, + "WARNING! %d bare linefeeds received in ASCII mode.\n", + bare_lfs); + fputs("File may not have transferred correctly.\n", ttyout); + } + if (bytes >= 0 && is_retr) { + if (bytes > 0) + ptransfer(0); + if (preserve && (closefunc == fclose)) { + mtime = remotemodtime(remote, 0); + if (mtime != -1) { + (void)gettimeofday(&tval[0], NULL); + tval[1].tv_sec = mtime; + tval[1].tv_usec = 0; + if (utimes(local, tval) == -1) { + fprintf(ttyout, + "Can't change modification time on %s to %s", + local, asctime(localtime(&mtime))); + } + } + } + } + goto cleanuprecv; + + abort: + /* + * abort using RFC 959 recommended IP,SYNC sequence + */ + if (! sigsetjmp(xferabort, 1)) { + /* this is the first call */ + (void)xsignal(SIGINT, abort_squared); + if (!cpend) { + code = -1; + goto cleanuprecv; + } + abort_remote(din); + } + code = -1; + if (bytes > 0) + ptransfer(0); + + cleanuprecv: + if (oldintr) + (void)xsignal(SIGINT, oldintr); + if (oldintp) + (void)xsignal(SIGPIPE, oldintp); + if (data >= 0) { + (void)close(data); + data = -1; + } + if (closefunc != NULL && fout != NULL) + (*closefunc)(fout); + if (din) + (void)fclose(din); + progress = oprogress; + preserve = opreserve; + bytes = 0; +} + +/* + * Need to start a listen on the data channel before we send the command, + * otherwise the server's connect may fail. + */ +int +initconn(void) +{ + char *p, *a; + int result, tmpno = 0; + int on = 1; + int error; + u_int addr[16], port[2]; + u_int af, hal, pal; + socklen_t len; + char *pasvcmd = NULL; + +#ifdef INET6 + if (myctladdr.su_family == AF_INET6 && debug && + (IN6_IS_ADDR_LINKLOCAL(&myctladdr.si_su.su_sin6.sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&myctladdr.si_su.su_sin6.sin6_addr))) { + warnx("use of scoped address can be troublesome"); + } +#endif + reinit: + if (passivemode) { + data_addr = myctladdr; + data = socket(data_addr.su_family, SOCK_STREAM, 0); + if (data < 0) { + warn("socket"); + return (1); + } + if ((options & SO_DEBUG) && + setsockopt(data, SOL_SOCKET, SO_DEBUG, + (void *)&on, sizeof(on)) == -1) { + if (debug) + warn("setsockopt %s (ignored)", "SO_DEBUG"); + } + result = COMPLETE + 1; + switch (data_addr.su_family) { + case AF_INET: + if (epsv4 && !epsv4bad) { + pasvcmd = "EPSV"; + result = command("EPSV"); + if (!connected) + return (1); + /* + * this code is to be friendly with broken + * BSDI ftpd + */ + if (code / 10 == 22 && code != 229) { + fputs( +"wrong server: return code must be 229\n", + ttyout); + result = COMPLETE + 1; + } + if (result != COMPLETE) { + epsv4bad = 1; + if (debug) + fputs( + "disabling epsv4 for this connection\n", + ttyout); + } + } + if (result != COMPLETE) { + pasvcmd = "PASV"; + result = command("PASV"); + if (!connected) + return (1); + } + break; +#ifdef INET6 + case AF_INET6: + pasvcmd = "EPSV"; + result = command("EPSV"); + if (!connected) + return (1); + /* this code is to be friendly with broken BSDI ftpd */ + if (code / 10 == 22 && code != 229) { + fputs( +"wrong server: return code must be 229\n", + ttyout); + result = COMPLETE + 1; + } + if (result != COMPLETE) { + pasvcmd = "LPSV"; + result = command("LPSV"); + } + if (!connected) + return (1); + break; +#endif + default: + result = COMPLETE + 1; + break; + } + if (result != COMPLETE) { + if (activefallback) { + (void)close(data); + data = -1; + passivemode = 0; +#if 0 + activefallback = 0; +#endif + goto reinit; + } + fputs("Passive mode refused.\n", ttyout); + goto bad; + } + +#define pack2(var, off) \ + (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0)) +#define pack4(var, off) \ + (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \ + ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0)) +#define UC(b) (((int)b)&0xff) + + /* + * What we've got at this point is a string of comma separated + * one-byte unsigned integer values, separated by commas. + */ + if (strcmp(pasvcmd, "PASV") == 0) { + if (data_addr.su_family != AF_INET) { + fputs( + "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); + error = 1; + goto bad; + } + if (code / 10 == 22 && code != 227) { + fputs("wrong server: return code must be 227\n", + ttyout); + error = 1; + goto bad; + } + error = sscanf(pasv, "%u,%u,%u,%u,%u,%u", + &addr[0], &addr[1], &addr[2], &addr[3], + &port[0], &port[1]); + if (error != 6) { + fputs( +"Passive mode address scan failure. Shouldn't happen!\n", ttyout); + error = 1; + goto bad; + } + error = 0; + memset(&data_addr, 0, sizeof(data_addr)); + data_addr.su_family = AF_INET; + data_addr.su_len = sizeof(struct sockaddr_in); + data_addr.si_su.su_sin.sin_addr.s_addr = + htonl(pack4(addr, 0)); + data_addr.su_port = htons(pack2(port, 0)); + } else if (strcmp(pasvcmd, "LPSV") == 0) { + if (code / 10 == 22 && code != 228) { + fputs("wrong server: return code must be 228\n", + ttyout); + error = 1; + goto bad; + } + switch (data_addr.su_family) { + case AF_INET: + error = sscanf(pasv, +"%u,%u,%u,%u,%u,%u,%u,%u,%u", + &af, &hal, + &addr[0], &addr[1], &addr[2], &addr[3], + &pal, &port[0], &port[1]); + if (error != 9) { + fputs( +"Passive mode address scan failure. Shouldn't happen!\n", ttyout); + error = 1; + goto bad; + } + if (af != 4 || hal != 4 || pal != 2) { + fputs( +"Passive mode AF mismatch. Shouldn't happen!\n", ttyout); + error = 1; + goto bad; + } + + error = 0; + memset(&data_addr, 0, sizeof(data_addr)); + data_addr.su_family = AF_INET; + data_addr.su_len = sizeof(struct sockaddr_in); + data_addr.si_su.su_sin.sin_addr.s_addr = + htonl(pack4(addr, 0)); + data_addr.su_port = htons(pack2(port, 0)); + break; +#ifdef INET6 + case AF_INET6: + error = sscanf(pasv, +"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", + &af, &hal, + &addr[0], &addr[1], &addr[2], &addr[3], + &addr[4], &addr[5], &addr[6], &addr[7], + &addr[8], &addr[9], &addr[10], + &addr[11], &addr[12], &addr[13], + &addr[14], &addr[15], + &pal, &port[0], &port[1]); + if (error != 21) { + fputs( +"Passive mode address scan failure. Shouldn't happen!\n", ttyout); + error = 1; + goto bad; + } + if (af != 6 || hal != 16 || pal != 2) { + fputs( +"Passive mode AF mismatch. Shouldn't happen!\n", ttyout); + error = 1; + goto bad; + } + + error = 0; + memset(&data_addr, 0, sizeof(data_addr)); + data_addr.su_family = AF_INET6; + data_addr.su_len = sizeof(struct sockaddr_in6); + { + int i; + for (i = 0; i < sizeof(struct in6_addr); i++) { + data_addr.si_su.su_sin6.sin6_addr.s6_addr[i] = + UC(addr[i]); + } + } + data_addr.su_port = htons(pack2(port, 0)); + break; +#endif + default: + error = 1; + } + } else if (strcmp(pasvcmd, "EPSV") == 0) { + char delim[4]; + + port[0] = 0; + if (code / 10 == 22 && code != 229) { + fputs("wrong server: return code must be 229\n", + ttyout); + error = 1; + goto bad; + } + if (sscanf(pasv, "%c%c%c%d%c", &delim[0], + &delim[1], &delim[2], &port[1], + &delim[3]) != 5) { + fputs("parse error!\n", ttyout); + error = 1; + goto bad; + } + if (delim[0] != delim[1] || delim[0] != delim[2] + || delim[0] != delim[3]) { + fputs("parse error!\n", ttyout); + error = 1; + goto bad; + } + data_addr = hisctladdr; + data_addr.su_port = htons(port[1]); + } else + goto bad; + + while (xconnect(data, (struct sockaddr *)&data_addr.si_su, + data_addr.su_len) < 0) { + if (activefallback) { + (void)close(data); + data = -1; + passivemode = 0; +#if 0 + activefallback = 0; +#endif + goto reinit; + } + warn("connect for data channel"); + goto bad; + } +#ifdef IPTOS_THROUGHPUT + if (data_addr.su_family == AF_INET) { + on = IPTOS_THROUGHPUT; + if (setsockopt(data, IPPROTO_IP, IP_TOS, + (void *)&on, sizeof(on)) == -1) { + if (debug) + warn("setsockopt %s (ignored)", + "IPTOS_THROUGHPUT"); + } + } +#endif + return (0); + } + + noport: + data_addr = myctladdr; + if (sendport) + data_addr.su_port = 0; /* let system pick one */ + if (data != -1) + (void)close(data); + data = socket(data_addr.su_family, SOCK_STREAM, 0); + if (data < 0) { + warn("socket"); + if (tmpno) + sendport = 1; + return (1); + } + if (!sendport) + if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, + (void *)&on, sizeof(on)) == -1) { + warn("setsockopt %s", "SO_REUSEADDR"); + goto bad; + } + if (bind(data, (struct sockaddr *)&data_addr.si_su, + data_addr.su_len) < 0) { + warn("bind"); + goto bad; + } + if ((options & SO_DEBUG) && + setsockopt(data, SOL_SOCKET, SO_DEBUG, + (void *)&on, sizeof(on)) == -1) { + if (debug) + warn("setsockopt %s (ignored)", "SO_DEBUG"); + } + len = sizeof(data_addr.si_su); + memset((char *)&data_addr, 0, sizeof (data_addr)); + if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) == -1) { + warn("getsockname"); + goto bad; + } + data_addr.su_len = len; + if (xlisten(data, 1) < 0) + warn("listen"); + + if (sendport) { + char hname[NI_MAXHOST], sname[NI_MAXSERV]; + int af; + struct sockinet tmp; + + switch (data_addr.su_family) { + case AF_INET: + if (!epsv4 || epsv4bad) { + result = COMPLETE + 1; + break; + } + /* FALLTHROUGH */ +#ifdef INET6 + case AF_INET6: +#endif + af = (data_addr.su_family == AF_INET) ? 1 : 2; + tmp = data_addr; +#ifdef INET6 + if (tmp.su_family == AF_INET6) + tmp.si_su.su_sin6.sin6_scope_id = 0; +#endif + if (getnameinfo((struct sockaddr *)&tmp.si_su, + tmp.su_len, hname, sizeof(hname), sname, + sizeof(sname), NI_NUMERICHOST | NI_NUMERICSERV)) { + result = ERROR; + } else { + result = command("EPRT |%d|%s|%s|", af, hname, + sname); + if (!connected) + return (1); + if (result != COMPLETE) { + epsv4bad = 1; + if (debug) + fputs( + "disabling epsv4 for this connection\n", + ttyout); + } + } + break; + default: + result = COMPLETE + 1; + break; + } + if (result == COMPLETE) + goto skip_port; + + switch (data_addr.su_family) { + case AF_INET: + a = (char *)&data_addr.si_su.su_sin.sin_addr; + p = (char *)&data_addr.su_port; + result = command("PORT %d,%d,%d,%d,%d,%d", + UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), + UC(p[0]), UC(p[1])); + break; +#ifdef INET6 + case AF_INET6: + a = (char *)&data_addr.si_su.su_sin6.sin6_addr; + p = (char *)&data_addr.su_port; + result = command( + "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + 6, 16, + UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]), + UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]), + UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]), + UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]), + 2, UC(p[0]), UC(p[1])); + break; +#endif + default: + result = COMPLETE + 1; /* xxx */ + } + if (!connected) + return (1); + skip_port: + + if (result == ERROR && sendport == -1) { + sendport = 0; + tmpno = 1; + goto noport; + } + return (result != COMPLETE); + } + if (tmpno) + sendport = 1; +#ifdef IPTOS_THROUGHPUT + if (data_addr.su_family == AF_INET) { + on = IPTOS_THROUGHPUT; + if (setsockopt(data, IPPROTO_IP, IP_TOS, + (void *)&on, sizeof(on)) == -1) + if (debug) + warn("setsockopt %s (ignored)", + "IPTOS_THROUGHPUT"); + } +#endif + return (0); + bad: + (void)close(data); + data = -1; + if (tmpno) + sendport = 1; + return (1); +} + +FILE * +dataconn(const char *lmode) +{ + struct sockinet from; + int s, flags, rv, timeout; + struct timeval endtime, now, td; + struct pollfd pfd[1]; + socklen_t fromlen; + + if (passivemode) /* passive data connection */ + return (fdopen(data, lmode)); + + /* active mode data connection */ + + if ((flags = fcntl(data, F_GETFL, 0)) == -1) + goto dataconn_failed; /* get current socket flags */ + if (fcntl(data, F_SETFL, flags | O_NONBLOCK) == -1) + goto dataconn_failed; /* set non-blocking connect */ + + /* NOTE: we now must restore socket flags on successful exit */ + + /* limit time waiting on listening socket */ + pfd[0].fd = data; + pfd[0].events = POLLIN; + (void)gettimeofday(&endtime, NULL); /* determine end time */ + endtime.tv_sec += (quit_time > 0) ? quit_time: 60; + /* without -q, default to 60s */ + do { + (void)gettimeofday(&now, NULL); + timersub(&endtime, &now, &td); + timeout = td.tv_sec * 1000 + td.tv_usec/1000; + if (timeout < 0) + timeout = 0; + rv = xpoll(pfd, 1, timeout); + } while (rv == -1 && errno == EINTR); /* loop until poll ! EINTR */ + if (rv == -1) { + warn("poll waiting before accept"); + goto dataconn_failed; + } + if (rv == 0) { + warn("poll timeout waiting before accept"); + goto dataconn_failed; + } + + /* (non-blocking) accept the connection */ + fromlen = myctladdr.su_len; + do { + s = accept(data, (struct sockaddr *) &from.si_su, &fromlen); + } while (s == -1 && errno == EINTR); /* loop until accept ! EINTR */ + if (s == -1) { + warn("accept"); + goto dataconn_failed; + } + + (void)close(data); + data = s; + if (fcntl(data, F_SETFL, flags) == -1) /* restore socket flags */ + goto dataconn_failed; + +#ifdef IPTOS_THROUGHPUT + if (from.su_family == AF_INET) { + int tos = IPTOS_THROUGHPUT; + if (setsockopt(s, IPPROTO_IP, IP_TOS, + (void *)&tos, sizeof(tos)) == -1) { + if (debug) + warn("setsockopt %s (ignored)", + "IPTOS_THROUGHPUT"); + } + } +#endif + return (fdopen(data, lmode)); + + dataconn_failed: + (void)close(data); + data = -1; + return (NULL); +} + +void +psabort(int notused) +{ + int oerrno = errno; + + sigint_raised = 1; + alarmtimer(0); + abrtflag++; + errno = oerrno; +} + +void +pswitch(int flag) +{ + sigfunc oldintr; + static struct comvars { + int connect; + char name[MAXHOSTNAMELEN]; + struct sockinet mctl; + struct sockinet hctl; + FILE *in; + FILE *out; + int tpe; + int curtpe; + int cpnd; + int sunqe; + int runqe; + int mcse; + int ntflg; + char nti[17]; + char nto[17]; + int mapflg; + char mi[MAXPATHLEN]; + char mo[MAXPATHLEN]; + } proxstruct, tmpstruct; + struct comvars *ip, *op; + + abrtflag = 0; + oldintr = xsignal(SIGINT, psabort); + if (flag) { + if (proxy) + return; + ip = &tmpstruct; + op = &proxstruct; + proxy++; + } else { + if (!proxy) + return; + ip = &proxstruct; + op = &tmpstruct; + proxy = 0; + } + ip->connect = connected; + connected = op->connect; + if (hostname) + (void)strlcpy(ip->name, hostname, sizeof(ip->name)); + else + ip->name[0] = '\0'; + hostname = op->name; + ip->hctl = hisctladdr; + hisctladdr = op->hctl; + ip->mctl = myctladdr; + myctladdr = op->mctl; + ip->in = cin; + cin = op->in; + ip->out = cout; + cout = op->out; + ip->tpe = type; + type = op->tpe; + ip->curtpe = curtype; + curtype = op->curtpe; + ip->cpnd = cpend; + cpend = op->cpnd; + ip->sunqe = sunique; + sunique = op->sunqe; + ip->runqe = runique; + runique = op->runqe; + ip->mcse = mcase; + mcase = op->mcse; + ip->ntflg = ntflag; + ntflag = op->ntflg; + (void)strlcpy(ip->nti, ntin, sizeof(ip->nti)); + (void)strlcpy(ntin, op->nti, sizeof(ntin)); + (void)strlcpy(ip->nto, ntout, sizeof(ip->nto)); + (void)strlcpy(ntout, op->nto, sizeof(ntout)); + ip->mapflg = mapflag; + mapflag = op->mapflg; + (void)strlcpy(ip->mi, mapin, sizeof(ip->mi)); + (void)strlcpy(mapin, op->mi, sizeof(mapin)); + (void)strlcpy(ip->mo, mapout, sizeof(ip->mo)); + (void)strlcpy(mapout, op->mo, sizeof(mapout)); + (void)xsignal(SIGINT, oldintr); + if (abrtflag) { + abrtflag = 0; + (*oldintr)(SIGINT); + } +} + +void +abortpt(int notused) +{ + + sigint_raised = 1; + alarmtimer(0); + if (fromatty) + write(fileno(ttyout), "\n", 1); + ptabflg++; + mflag = 0; + abrtflag = 0; + siglongjmp(ptabort, 1); +} + +void +proxtrans(const char *cmd, const char *local, const char *remote) +{ + sigfunc oldintr; + int prox_type, nfnd; + volatile int secndflag; + char *cmd2; + +#ifdef __GNUC__ /* to shut up gcc warnings */ + (void)&oldintr; + (void)&cmd2; +#endif + + oldintr = NULL; + secndflag = 0; + if (strcmp(cmd, "RETR")) + cmd2 = "RETR"; + else + cmd2 = runique ? "STOU" : "STOR"; + if ((prox_type = type) == 0) { + if (unix_server && unix_proxy) + prox_type = TYPE_I; + else + prox_type = TYPE_A; + } + if (curtype != prox_type) + changetype(prox_type, 1); + if (command("PASV") != COMPLETE) { + fputs("proxy server does not support third party transfers.\n", + ttyout); + return; + } + pswitch(0); + if (!connected) { + fputs("No primary connection.\n", ttyout); + pswitch(1); + code = -1; + return; + } + if (curtype != prox_type) + changetype(prox_type, 1); + if (command("PORT %s", pasv) != COMPLETE) { + pswitch(1); + return; + } + if (sigsetjmp(ptabort, 1)) + goto abort; + oldintr = xsignal(SIGINT, abortpt); + if ((restart_point && + (command("REST " LLF, (LLT) restart_point) != CONTINUE)) + || (command("%s %s", cmd, remote) != PRELIM)) { + (void)xsignal(SIGINT, oldintr); + pswitch(1); + return; + } + sleep(2); + pswitch(1); + secndflag++; + if ((restart_point && + (command("REST " LLF, (LLT) restart_point) != CONTINUE)) + || (command("%s %s", cmd2, local) != PRELIM)) + goto abort; + ptflag++; + (void)getreply(0); + pswitch(0); + (void)getreply(0); + (void)xsignal(SIGINT, oldintr); + pswitch(1); + ptflag = 0; + fprintf(ttyout, "local: %s remote: %s\n", local, remote); + return; + abort: + if (sigsetjmp(xferabort, 1)) { + (void)xsignal(SIGINT, oldintr); + return; + } + (void)xsignal(SIGINT, abort_squared); + ptflag = 0; + if (strcmp(cmd, "RETR") && !proxy) + pswitch(1); + else if (!strcmp(cmd, "RETR") && proxy) + pswitch(0); + if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ + if (command("%s %s", cmd2, local) != PRELIM) { + pswitch(0); + if (cpend) + abort_remote(NULL); + } + pswitch(1); + if (ptabflg) + code = -1; + (void)xsignal(SIGINT, oldintr); + return; + } + if (cpend) + abort_remote(NULL); + pswitch(!proxy); + if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ + if (command("%s %s", cmd2, local) != PRELIM) { + pswitch(0); + if (cpend) + abort_remote(NULL); + pswitch(1); + if (ptabflg) + code = -1; + (void)xsignal(SIGINT, oldintr); + return; + } + } + if (cpend) + abort_remote(NULL); + pswitch(!proxy); + if (cpend) { + if ((nfnd = empty(cin, NULL, 10)) <= 0) { + if (nfnd < 0) + warn("abort"); + if (ptabflg) + code = -1; + lostpeer(0); + } + (void)getreply(0); + (void)getreply(0); + } + if (proxy) + pswitch(0); + pswitch(1); + if (ptabflg) + code = -1; + (void)xsignal(SIGINT, oldintr); +} + +void +reset(int argc, char *argv[]) +{ + int nfnd = 1; + + if (argc == 0 && argv != NULL) { + fprintf(ttyout, "usage: %s\n", argv[0]); + code = -1; + return; + } + while (nfnd > 0) { + if ((nfnd = empty(cin, NULL, 0)) < 0) { + warn("reset"); + code = -1; + lostpeer(0); + } else if (nfnd) + (void)getreply(0); + } +} + +char * +gunique(const char *local) +{ + static char new[MAXPATHLEN]; + char *cp = strrchr(local, '/'); + int d, count=0, len; + char ext = '1'; + + if (cp) + *cp = '\0'; + d = access(cp == local ? "/" : cp ? local : ".", W_OK); + if (cp) + *cp = '/'; + if (d < 0) { + warn("local: %s", local); + return (NULL); + } + len = strlcpy(new, local, sizeof(new)); + cp = &new[len]; + *cp++ = '.'; + while (!d) { + if (++count == 100) { + fputs("runique: can't find unique file name.\n", + ttyout); + return (NULL); + } + *cp++ = ext; + *cp = '\0'; + if (ext == '9') + ext = '0'; + else + ext++; + if ((d = access(new, F_OK)) < 0) + break; + if (ext != '0') + cp--; + else if (*(cp - 2) == '.') + *(cp - 1) = '1'; + else { + *(cp - 2) = *(cp - 2) + 1; + cp--; + } + } + return (new); +} + +/* + * abort_squared -- + * aborts abort_remote(). lostpeer() is called because if the user is + * too impatient to wait or there's another problem then ftp really + * needs to get back to a known state. + */ +void +abort_squared(int dummy) +{ + char msgbuf[100]; + size_t len; + + sigint_raised = 1; + alarmtimer(0); + len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n", + sizeof(msgbuf)); + write(fileno(ttyout), msgbuf, len); + lostpeer(0); + siglongjmp(xferabort, 1); +} + +void +abort_remote(FILE *din) +{ + char buf[BUFSIZ]; + int nfnd; + + if (cout == NULL) { + warnx("Lost control connection for abort."); + if (ptabflg) + code = -1; + lostpeer(0); + return; + } + /* + * send IAC in urgent mode instead of DM because 4.3BSD places oob mark + * after urgent byte rather than before as is protocol now + */ + buf[0] = IAC; + buf[1] = IP; + buf[2] = IAC; + if (send(fileno(cout), buf, 3, MSG_OOB) != 3) + warn("abort"); + fprintf(cout, "%cABOR\r\n", DM); + (void)fflush(cout); + if ((nfnd = empty(cin, din, 10)) <= 0) { + if (nfnd < 0) + warn("abort"); + if (ptabflg) + code = -1; + lostpeer(0); + } + if (din && (nfnd & 2)) { + while (read(fileno(din), buf, BUFSIZ) > 0) + continue; + } + if (getreply(0) == ERROR && code == 552) { + /* 552 needed for nic style abort */ + (void)getreply(0); + } + (void)getreply(0); +} + +void +ai_unmapped(struct addrinfo *ai) +{ +#ifdef INET6 + struct sockaddr_in6 *sin6; + struct sockaddr_in sin; + socklen_t len; + + if (ai->ai_family != AF_INET6) + return; + if (ai->ai_addrlen != sizeof(struct sockaddr_in6) || + sizeof(sin) > ai->ai_addrlen) + return; + sin6 = (struct sockaddr_in6 *)ai->ai_addr; + if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + return; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + len = sizeof(struct sockaddr_in); + memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12], + sizeof(sin.sin_addr)); + sin.sin_port = sin6->sin6_port; + + ai->ai_family = AF_INET; +#if HAVE_SOCKADDR_SA_LEN + sin.sin_len = len; +#endif + memcpy(ai->ai_addr, &sin, len); + ai->ai_addrlen = len; +#endif +} diff --git a/src/bin/network/ftp/ftp_var.h b/src/bin/network/ftp/ftp_var.h new file mode 100644 index 0000000000..47a42dc668 --- /dev/null +++ b/src/bin/network/ftp/ftp_var.h @@ -0,0 +1,342 @@ +/* $NetBSD: ftp_var.h,v 1.71 2005/04/11 01:49:31 lukem Exp $ */ + +/*- + * Copyright (c) 1996-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ftp_var.h 8.4 (Berkeley) 10/9/94 + */ + +/* + * Copyright (C) 1997 and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * FTP global variables. + */ + +#ifdef SMALL +#undef NO_EDITCOMPLETE +#define NO_EDITCOMPLETE +#undef NO_PROGRESS +#define NO_PROGRESS +#endif + +//#include + +#define DIRENT_MISSING_D_NAMLEN +#define INFTIM INT_MAX + +#include + +#include +#include + +#include + +#include +#include + +#ifndef NO_EDITCOMPLETE +#include +#endif /* !NO_EDITCOMPLETE */ + +#include "extern.h" +#include "progressbar.h" + +/* + * Format of command table. + */ +struct cmd { + char *c_name; /* name of command */ + const char *c_help; /* help string */ + char c_bell; /* give bell when command completes */ + char c_conn; /* must be connected to use command */ + char c_proxy; /* proxy server may execute */ +#ifndef NO_EDITCOMPLETE + const char *c_complete; /* context sensitive completion list */ +#endif /* !NO_EDITCOMPLETE */ + void (*c_handler)(int, char **); /* function to call */ +}; + +/* + * Format of macro table + */ +struct macel { + char mac_name[9]; /* macro name */ + char *mac_start; /* start of macro in macbuf */ + char *mac_end; /* end of macro in macbuf */ +}; + +/* + * Format of option table + */ +struct option { + char *name; + char *value; +}; + +/* + * Indices to features[]; an array containing status of remote server + * features; -1 not known (FEAT failed), 0 absent, 1 present. + */ +enum { + FEAT_FEAT = 0, /* FEAT, OPTS */ + FEAT_MDTM, /* MDTM */ + FEAT_MLST, /* MLSD, MLST */ + FEAT_REST_STREAM, /* RESTart STREAM */ + FEAT_SIZE, /* SIZE */ + FEAT_TVFS, /* TVFS (not used) */ + FEAT_max +}; + + +/* + * Global defines + */ +#define FTPBUFLEN MAXPATHLEN + 200 +#define MAX_IN_PORT_T 0xffffU + +#define HASHBYTES 1024 /* default mark for `hash' command */ +#define DEFAULTINCR 1024 /* default increment for `rate' command */ + +#define FTP_PORT 21 /* default if ! getservbyname("ftp/tcp") */ +#define HTTP_PORT 80 /* default if ! getservbyname("http/tcp") */ +#ifndef GATE_PORT +#define GATE_PORT 21 /* default if ! getservbyname("ftpgate/tcp") */ +#endif +#ifndef GATE_SERVER +#define GATE_SERVER "" /* default server */ +#endif + +#define DEFAULTPAGER "more" /* default pager if $PAGER isn't set */ +#define DEFAULTPROMPT "ftp> " /* default prompt if `set prompt' is empty */ +#define DEFAULTRPROMPT "" /* default rprompt if `set rprompt' is empty */ + +#define TMPFILE "ftpXXXXXXXXXX" + + +#ifndef GLOBAL +#define GLOBAL extern +#endif + +/* + * Options and other state info. + */ +GLOBAL int trace; /* trace packets exchanged */ +GLOBAL int hash; /* print # for each buffer transferred */ +GLOBAL int mark; /* number of bytes between hashes */ +GLOBAL int sendport; /* use PORT/LPRT cmd for each data connection */ +GLOBAL int connected; /* 1 = connected to server, -1 = logged in */ +GLOBAL int interactive; /* interactively prompt on m* cmds */ +GLOBAL int confirmrest; /* confirm rest of current m* cmd */ +GLOBAL int debug; /* debugging level */ +GLOBAL int bell; /* ring bell on cmd completion */ +GLOBAL int doglob; /* glob local file names */ +GLOBAL int autologin; /* establish user account on connection */ +GLOBAL int proxy; /* proxy server connection active */ +GLOBAL int proxflag; /* proxy connection exists */ +GLOBAL int gatemode; /* use gate-ftp */ +GLOBAL char *gateserver; /* server to use for gate-ftp */ +GLOBAL int sunique; /* store files on server with unique name */ +GLOBAL int runique; /* store local files with unique name */ +GLOBAL int mcase; /* map upper to lower case for mget names */ +GLOBAL int ntflag; /* use ntin ntout tables for name translation */ +GLOBAL int mapflag; /* use mapin mapout templates on file names */ +GLOBAL int preserve; /* preserve modification time on files */ +GLOBAL int code; /* return/reply code for ftp command */ +GLOBAL int crflag; /* if 1, strip car. rets. on ascii gets */ +GLOBAL int passivemode; /* passive mode enabled */ +GLOBAL int activefallback; /* fall back to active mode if passive fails */ +GLOBAL char *altarg; /* argv[1] with no shell-like preprocessing */ +GLOBAL char ntin[17]; /* input translation table */ +GLOBAL char ntout[17]; /* output translation table */ +GLOBAL char mapin[MAXPATHLEN]; /* input map template */ +GLOBAL char mapout[MAXPATHLEN]; /* output map template */ +GLOBAL char typename[32]; /* name of file transfer type */ +GLOBAL int type; /* requested file transfer type */ +GLOBAL int curtype; /* current file transfer type */ +GLOBAL char structname[32]; /* name of file transfer structure */ +GLOBAL int stru; /* file transfer structure */ +GLOBAL char formname[32]; /* name of file transfer format */ +GLOBAL int form; /* file transfer format */ +GLOBAL char modename[32]; /* name of file transfer mode */ +GLOBAL int mode; /* file transfer mode */ +GLOBAL char bytename[32]; /* local byte size in ascii */ +GLOBAL int bytesize; /* local byte size in binary */ +GLOBAL int anonftp; /* automatic anonymous login */ +GLOBAL int dirchange; /* remote directory changed by cd command */ +GLOBAL int flushcache; /* set HTTP cache flush headers with request */ +GLOBAL int rate_get; /* maximum get xfer rate */ +GLOBAL int rate_get_incr; /* increment for get xfer rate */ +GLOBAL int rate_put; /* maximum put xfer rate */ +GLOBAL int rate_put_incr; /* increment for put xfer rate */ +GLOBAL int retry_connect; /* seconds between retrying connection */ +GLOBAL char *tmpdir; /* temporary directory */ +GLOBAL int epsv4; /* use EPSV/EPRT on IPv4 connections */ +GLOBAL int epsv4bad; /* EPSV doesn't work on the current server */ +GLOBAL int editing; /* command line editing enabled */ +GLOBAL int features[FEAT_max]; /* remote FEATures supported */ + +#ifndef NO_EDITCOMPLETE +GLOBAL EditLine *el; /* editline(3) status structure */ +GLOBAL History *hist; /* editline(3) history structure */ +GLOBAL char *cursor_pos; /* cursor position we're looking for */ +GLOBAL size_t cursor_argc; /* location of cursor in margv */ +GLOBAL size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */ +#endif /* !NO_EDITCOMPLETE */ + +GLOBAL char *direction; /* direction transfer is occurring */ + +GLOBAL char *hostname; /* name of host connected to */ +GLOBAL int unix_server; /* server is unix, can use binary for ascii */ +GLOBAL int unix_proxy; /* proxy is unix, can use binary for ascii */ +GLOBAL char localcwd[MAXPATHLEN]; /* local dir */ +GLOBAL char remotecwd[MAXPATHLEN]; /* remote dir */ +GLOBAL char *username; /* name of user logged in as. (dynamic) */ + +GLOBAL sa_family_t family; /* address family to use for connections */ +GLOBAL char *ftpport; /* port number to use for FTP connections */ +GLOBAL char *httpport; /* port number to use for HTTP connections */ +GLOBAL char *gateport; /* port number to use for gateftp connections */ + +GLOBAL char *outfile; /* filename to output URLs to */ +GLOBAL int restartautofetch; /* restart auto-fetch */ + +GLOBAL char line[FTPBUFLEN]; /* input line buffer */ +GLOBAL char *stringbase; /* current scan point in line buffer */ +GLOBAL char argbuf[FTPBUFLEN]; /* argument storage buffer */ +GLOBAL char *argbase; /* current storage point in arg buffer */ +GLOBAL StringList *marg_sl; /* stringlist containing margv */ +GLOBAL int margc; /* count of arguments on input line */ +#define margv (marg_sl->sl_str) /* args parsed from input line */ +GLOBAL int cpend; /* flag: if != 0, then pending server reply */ +GLOBAL int mflag; /* flag: if != 0, then active multi command */ + +GLOBAL int options; /* used during socket creation */ + +GLOBAL int sndbuf_size; /* socket send buffer size */ +GLOBAL int rcvbuf_size; /* socket receive buffer size */ + +GLOBAL int macnum; /* number of defined macros */ +GLOBAL struct macel macros[16]; +GLOBAL char macbuf[4096]; + +GLOBAL char *localhome; /* local home directory */ +GLOBAL char *localname; /* local user name */ +GLOBAL char netrc[MAXPATHLEN]; /* path to .netrc file */ +GLOBAL char reply_string[BUFSIZ]; /* first line of previous reply */ +GLOBAL void (*reply_callback)(const char *); + /* + * function to call for each line in + * the server's reply except for the + * first (`xxx-') and last (`xxx ') + */ + +GLOBAL volatile sig_atomic_t sigint_raised; + +GLOBAL FILE *cin; +GLOBAL FILE *cout; +GLOBAL int data; + +extern struct cmd cmdtab[]; +extern struct option optiontab[]; + + +#define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0')) +#define FREEPTR(x) if ((x) != NULL) { free(x); (x) = NULL; } + +#ifdef BSD4_4 +# define HAVE_SOCKADDR_SA_LEN 1 +#endif + +#ifdef NO_LONG_LONG +# define STRTOLL(x,y,z) strtol(x,y,z) +#else +# define STRTOLL(x,y,z) strtoll(x,y,z) +#endif diff --git a/src/bin/network/ftp/main.c b/src/bin/network/ftp/main.c new file mode 100644 index 0000000000..477cc9ca71 --- /dev/null +++ b/src/bin/network/ftp/main.c @@ -0,0 +1,1039 @@ +/* $NetBSD: main.c,v 1.94 2005/05/13 05:03:49 lukem Exp $ */ + +/*- + * Copyright (c) 1996-2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) 1997 and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * FTP User Program -- Command Interface. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GLOBAL /* force GLOBAL decls in ftp_var.h to be declared */ +#include "ftp_var.h" + +#define FTP_PROXY "ftp_proxy" /* env var with FTP proxy location */ +#define HTTP_PROXY "http_proxy" /* env var with HTTP proxy location */ +#define NO_PROXY "no_proxy" /* env var with list of non-proxied + * hosts, comma or space separated */ + +static void setupoption(char *, char *, char *); +int main(int, char *[]); + +int +main(int argc, char *argv[]) +{ + int ch, rval; + struct passwd *pw; + char *cp, *ep, *anonuser, *anonpass, *upload_path; + int dumbterm, s, len, isupload; + socklen_t slen; + + setlocale(LC_ALL, ""); + setprogname(argv[0]); + + sigint_raised = 0; + + ftpport = "ftp"; + httpport = "http"; + gateport = NULL; + cp = getenv("FTPSERVERPORT"); + if (cp != NULL) + gateport = cp; + else + gateport = "ftpgate"; + doglob = 1; + interactive = 1; + autologin = 1; + passivemode = 1; + activefallback = 1; + preserve = 1; + verbose = 0; + progress = 0; + gatemode = 0; + data = -1; + outfile = NULL; + restartautofetch = 0; +#ifndef NO_EDITCOMPLETE + editing = 0; + el = NULL; + hist = NULL; +#endif + bytes = 0; + mark = HASHBYTES; + rate_get = 0; + rate_get_incr = DEFAULTINCR; + rate_put = 0; + rate_put_incr = DEFAULTINCR; +#ifdef INET6 + epsv4 = 1; +#else + epsv4 = 0; +#endif + epsv4bad = 0; + upload_path = NULL; + isupload = 0; + reply_callback = NULL; + family = AF_UNSPEC; + + netrc[0] = '\0'; + cp = getenv("NETRC"); + if (cp != NULL && strlcpy(netrc, cp, sizeof(netrc)) >= sizeof(netrc)) + errx(1, "$NETRC `%s': %s", cp, strerror(ENAMETOOLONG)); + + /* + * Get the default socket buffer sizes if we don't already have them. + * It doesn't matter which socket we do this to, because on the first + * call no socket buffer sizes will have been modified, so we are + * guaranteed to get the system defaults. + */ + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == -1) + err(1, "can't create socket"); + slen = sizeof(rcvbuf_size); + if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, + (void *)&rcvbuf_size, &slen) == -1) + err(1, "unable to get default rcvbuf size"); + slen = sizeof(sndbuf_size); + if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, + (void *)&sndbuf_size, &slen) == -1) + err(1, "unable to get default sndbuf size"); + (void)close(s); + /* sanity check returned buffer sizes */ + if (rcvbuf_size <= 0) + rcvbuf_size = 8 * 1024; + if (sndbuf_size <= 0) + sndbuf_size = 8 * 1024; + + if (sndbuf_size > 8 * 1024 * 1024) + sndbuf_size = 8 * 1024 * 1024; + if (rcvbuf_size > 8 * 1024 * 1024) + rcvbuf_size = 8 * 1024 * 1024; + + marg_sl = xsl_init(); + if ((tmpdir = getenv("TMPDIR")) == NULL) + tmpdir = _PATH_TMP; + + /* Set default operation mode based on FTPMODE environment variable */ + if ((cp = getenv("FTPMODE")) != NULL) { + if (strcasecmp(cp, "passive") == 0) { + passivemode = 1; + activefallback = 0; + } else if (strcasecmp(cp, "active") == 0) { + passivemode = 0; + activefallback = 0; + } else if (strcasecmp(cp, "gate") == 0) { + gatemode = 1; + } else if (strcasecmp(cp, "auto") == 0) { + passivemode = 1; + activefallback = 1; + } else + warnx("unknown $FTPMODE '%s'; using defaults", cp); + } + + if (strcmp(getprogname(), "pftp") == 0) { + passivemode = 1; + activefallback = 0; + } else if (strcmp(getprogname(), "gate-ftp") == 0) + gatemode = 1; + + gateserver = getenv("FTPSERVER"); + if (gateserver == NULL || *gateserver == '\0') + gateserver = GATE_SERVER; + if (gatemode) { + if (*gateserver == '\0') { + warnx( +"Neither $FTPSERVER nor GATE_SERVER is defined; disabling gate-ftp"); + gatemode = 0; + } + } + + cp = getenv("TERM"); + if (cp == NULL || strcmp(cp, "dumb") == 0) + dumbterm = 1; + else + dumbterm = 0; + fromatty = isatty(fileno(stdin)); + ttyout = stdout; + if (isatty(fileno(ttyout))) { + verbose = 1; /* verbose if to a tty */ + if (! dumbterm) { +#ifndef NO_EDITCOMPLETE + if (fromatty) /* editing mode on if tty is usable */ + editing = 1; +#endif +#ifndef NO_PROGRESS + if (foregroundproc()) + progress = 1; /* progress bar on if fg */ +#endif + } + } + + while ((ch = getopt(argc, argv, "46AadefginN:o:pP:q:r:RtT:u:vV")) != -1) { + switch (ch) { + case '4': + family = AF_INET; + break; + + case '6': +#ifdef INET6 + family = AF_INET6; +#else + warnx("INET6 support is not available; ignoring -6"); +#endif + break; + + case 'A': + activefallback = 0; + passivemode = 0; + break; + + case 'a': + anonftp = 1; + break; + + case 'd': + options |= SO_DEBUG; + debug++; + break; + + case 'e': +#ifndef NO_EDITCOMPLETE + editing = 0; +#endif + break; + + case 'f': + flushcache = 1; + break; + + case 'g': + doglob = 0; + break; + + case 'i': + interactive = 0; + break; + + case 'n': + autologin = 0; + break; + + case 'N': + if (strlcpy(netrc, optarg, sizeof(netrc)) + >= sizeof(netrc)) + errx(1, "%s: %s", optarg, + strerror(ENAMETOOLONG)); + break; + + case 'o': + outfile = optarg; + if (strcmp(outfile, "-") == 0) + ttyout = stderr; + break; + + case 'p': + passivemode = 1; + activefallback = 0; + break; + + case 'P': + ftpport = optarg; + break; + + case 'q': + quit_time = strtol(optarg, &ep, 10); + if (quit_time < 1 || *ep != '\0') + errx(1, "bad quit value: %s", optarg); + break; + + case 'r': + retry_connect = strtol(optarg, &ep, 10); + if (retry_connect < 1 || *ep != '\0') + errx(1, "bad retry value: %s", optarg); + break; + + case 'R': + restartautofetch = 1; + break; + + case 't': + trace = 1; + break; + + case 'T': + { + int targc; + char *targv[6], *oac; + + /* look for `dir,max[,incr]' */ + targc = 0; + targv[targc++] = "-T"; + oac = xstrdup(optarg); + + while ((cp = strsep(&oac, ",")) != NULL) { + if (*cp == '\0') { + warnx("bad throttle value: %s", optarg); + usage(); + /* NOTREACHED */ + } + targv[targc++] = cp; + if (targc >= 5) + break; + } + if (parserate(targc, targv, 1) == -1) + usage(); + free(oac); + break; + } + + case 'u': + { + isupload = 1; + interactive = 0; + upload_path = xstrdup(optarg); + + break; + } + + case 'v': + progress = verbose = 1; + break; + + case 'V': + progress = verbose = 0; + break; + + default: + usage(); + } + } + /* set line buffering on ttyout */ + setvbuf(ttyout, NULL, _IOLBF, 0); + argc -= optind; + argv += optind; + + cpend = 0; /* no pending replies */ + proxy = 0; /* proxy not active */ + crflag = 1; /* strip c.r. on ascii gets */ + sendport = -1; /* not using ports */ + + /* + * Cache the user name and home directory. + */ + localhome = NULL; + localname = NULL; + anonuser = "anonymous"; + cp = getenv("HOME"); + if (! EMPTYSTRING(cp)) + localhome = xstrdup(cp); + pw = NULL; + cp = getlogin(); + if (cp != NULL) + pw = getpwnam(cp); + if (pw == NULL) + pw = getpwuid(getuid()); + if (pw != NULL) { + if (localhome == NULL && !EMPTYSTRING(pw->pw_dir)) + localhome = xstrdup(pw->pw_dir); + localname = xstrdup(pw->pw_name); + anonuser = localname; + } + if (netrc[0] == '\0' && localhome != NULL) { + if (strlcpy(netrc, localhome, sizeof(netrc)) >= sizeof(netrc) || + strlcat(netrc, "/.netrc", sizeof(netrc)) >= sizeof(netrc)) { + warnx("%s/.netrc: %s", localhome, + strerror(ENAMETOOLONG)); + netrc[0] = '\0'; + } + } + if (localhome == NULL) + localhome = xstrdup("/"); + + /* + * Every anonymous FTP server I've encountered will accept the + * string "username@", and will append the hostname itself. We + * do this by default since many servers are picky about not + * having a FQDN in the anonymous password. + * - thorpej@NetBSD.org + */ + len = strlen(anonuser) + 2; + anonpass = xmalloc(len); + (void)strlcpy(anonpass, anonuser, len); + (void)strlcat(anonpass, "@", len); + + /* + * set all the defaults for options defined in + * struct option optiontab[] declared in cmdtab.c + */ + setupoption("anonpass", getenv("FTPANONPASS"), anonpass); + setupoption("ftp_proxy", getenv(FTP_PROXY), ""); + setupoption("http_proxy", getenv(HTTP_PROXY), ""); + setupoption("no_proxy", getenv(NO_PROXY), ""); + setupoption("pager", getenv("PAGER"), DEFAULTPAGER); + setupoption("prompt", getenv("FTPPROMPT"), DEFAULTPROMPT); + setupoption("rprompt", getenv("FTPRPROMPT"), DEFAULTRPROMPT); + + free(anonpass); + + setttywidth(0); +#ifdef SIGINFO + (void)xsignal(SIGINFO, psummary); +#endif + (void)xsignal(SIGQUIT, psummary); + (void)xsignal(SIGUSR1, crankrate); + (void)xsignal(SIGUSR2, crankrate); + (void)xsignal(SIGWINCH, setttywidth); + +#ifdef __GNUC__ /* to shut up gcc warnings */ + (void)&argc; + (void)&argv; +#endif + + if (argc > 0) { + if (isupload) { + rval = auto_put(argc, argv, upload_path); + sigint_or_rval_exit: + if (sigint_raised) { + (void)xsignal(SIGINT, SIG_DFL); + raise(SIGINT); + } + exit(rval); + } else if (strchr(argv[0], ':') != NULL + && ! isipv6addr(argv[0])) { + rval = auto_fetch(argc, argv); + if (rval >= 0) /* -1 == connected and cd-ed */ + goto sigint_or_rval_exit; + } else { + char *xargv[4], *user, *host; + + if ((rval = sigsetjmp(toplevel, 1))) + goto sigint_or_rval_exit; + (void)xsignal(SIGINT, intr); + (void)xsignal(SIGPIPE, lostpeer); + user = NULL; + host = argv[0]; + cp = strchr(host, '@'); + if (cp) { + *cp = '\0'; + user = host; + host = cp + 1; + } + /* XXX discards const */ + xargv[0] = (char *)getprogname(); + xargv[1] = host; + xargv[2] = argv[1]; + xargv[3] = NULL; + do { + int oautologin; + + oautologin = autologin; + if (user != NULL) { + anonftp = 0; + autologin = 0; + } + setpeer(argc+1, xargv); + autologin = oautologin; + if (connected == 1 && user != NULL) + (void)ftp_login(host, user, NULL); + if (!retry_connect) + break; + if (!connected) { + macnum = 0; + fprintf(ttyout, + "Retrying in %d seconds...\n", + retry_connect); + sleep(retry_connect); + } + } while (!connected); + retry_connect = 0; /* connected, stop hiding msgs */ + } + } + if (isupload) + usage(); + +#ifndef NO_EDITCOMPLETE + controlediting(); +#endif /* !NO_EDITCOMPLETE */ + + (void)sigsetjmp(toplevel, 1); + (void)xsignal(SIGINT, intr); + (void)xsignal(SIGPIPE, lostpeer); + for (;;) + cmdscanner(); +} + +/* + * Generate a prompt + */ +char * +prompt(void) +{ + static char **prompt; + static char buf[MAXPATHLEN]; + + if (prompt == NULL) { + struct option *o; + + o = getoption("prompt"); + if (o == NULL) + errx(1, "no such option `prompt'"); + prompt = &(o->value); + } + formatbuf(buf, sizeof(buf), *prompt ? *prompt : DEFAULTPROMPT); + return (buf); +} + +/* + * Generate an rprompt + */ +char * +rprompt(void) +{ + static char **rprompt; + static char buf[MAXPATHLEN]; + + if (rprompt == NULL) { + struct option *o; + + o = getoption("rprompt"); + if (o == NULL) + errx(1, "no such option `rprompt'"); + rprompt = &(o->value); + } + formatbuf(buf, sizeof(buf), *rprompt ? *rprompt : DEFAULTRPROMPT); + return (buf); +} + +/* + * Command parser. + */ +void +cmdscanner(void) +{ + struct cmd *c; + char *p; + int num; + + for (;;) { +#ifndef NO_EDITCOMPLETE + if (!editing) { +#endif /* !NO_EDITCOMPLETE */ + if (fromatty) { + fputs(prompt(), ttyout); + p = rprompt(); + if (*p) + fprintf(ttyout, "%s ", p); + (void)fflush(ttyout); + } + if (fgets(line, sizeof(line), stdin) == NULL) { + if (fromatty) + putc('\n', ttyout); + quit(0, NULL); + } + num = strlen(line); + if (num == 0) + break; + if (line[--num] == '\n') { + if (num == 0) + break; + line[num] = '\0'; + } else if (num == sizeof(line) - 2) { + fputs("Sorry, input line is too long.\n", + ttyout); + while ((num = getchar()) != '\n' && num != EOF) + /* void */; + break; + } /* else it was a line without a newline */ +#ifndef NO_EDITCOMPLETE + } else { + const char *buf; + HistEvent ev; + cursor_pos = NULL; + + buf = el_gets(el, &num); + if (buf == NULL || num == 0) { + if (fromatty) + putc('\n', ttyout); + quit(0, NULL); + } + if (num >= sizeof(line)) { + fputs("Sorry, input line is too long.\n", + ttyout); + break; + } + memcpy(line, buf, num); + if (line[--num] == '\n') { + line[num] = '\0'; + if (num == 0) + break; + } + history(hist, &ev, H_ENTER, buf); + } +#endif /* !NO_EDITCOMPLETE */ + + makeargv(); + if (margc == 0) + continue; + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + fputs("?Ambiguous command.\n", ttyout); + continue; + } + if (c == NULL) { +#if !defined(NO_EDITCOMPLETE) + /* + * attempt to el_parse() unknown commands. + * any command containing a ':' would be parsed + * as "[prog:]cmd ...", and will result in a + * false positive if prog != "ftp", so treat + * such commands as invalid. + */ + if (strchr(margv[0], ':') != NULL || + el_parse(el, margc, (const char **)margv) != 0) +#endif /* !NO_EDITCOMPLETE */ + fputs("?Invalid command.\n", ttyout); + continue; + } + if (c->c_conn && !connected) { + fputs("Not connected.\n", ttyout); + continue; + } + confirmrest = 0; + margv[0] = c->c_name; + (*c->c_handler)(margc, margv); + if (bell && c->c_bell) + (void)putc('\007', ttyout); + if (c->c_handler != help) + break; + } + (void)xsignal(SIGINT, intr); + (void)xsignal(SIGPIPE, lostpeer); +} + +struct cmd * +getcmd(const char *name) +{ + const char *p, *q; + struct cmd *c, *found; + int nmatches, longest; + + if (name == NULL) + return (0); + + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; (p = c->c_name) != NULL; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmd *)-1); + return (found); +} + +/* + * Slice a string up into argc/argv. + */ + +int slrflag; + +void +makeargv(void) +{ + char *argp; + + stringbase = line; /* scan from first of buffer */ + argbase = argbuf; /* store from first of buffer */ + slrflag = 0; + marg_sl->sl_cur = 0; /* reset to start of marg_sl */ + for (margc = 0; ; margc++) { + argp = slurpstring(); + xsl_add(marg_sl, argp); + if (argp == NULL) + break; + } +#ifndef NO_EDITCOMPLETE + if (cursor_pos == line) { + cursor_argc = 0; + cursor_argo = 0; + } else if (cursor_pos != NULL) { + cursor_argc = margc; + cursor_argo = strlen(margv[margc-1]); + } +#endif /* !NO_EDITCOMPLETE */ +} + +#ifdef NO_EDITCOMPLETE +#define INC_CHKCURSOR(x) (x)++ +#else /* !NO_EDITCOMPLETE */ +#define INC_CHKCURSOR(x) { (x)++ ; \ + if (x == cursor_pos) { \ + cursor_argc = margc; \ + cursor_argo = ap-argbase; \ + cursor_pos = NULL; \ + } } + +#endif /* !NO_EDITCOMPLETE */ + +/* + * Parse string into argbuf; + * implemented with FSM to + * handle quoting and strings + */ +char * +slurpstring(void) +{ + int got_one = 0; + char *sb = stringbase; + char *ap = argbase; + char *tmp = argbase; /* will return this if token found */ + + if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ + switch (slrflag) { /* and $ as token for macro invoke */ + case 0: + slrflag++; + INC_CHKCURSOR(stringbase); + return ((*sb == '!') ? "!" : "$"); + /* NOTREACHED */ + case 1: + slrflag++; + altarg = stringbase; + break; + default: + break; + } + } + +S0: + switch (*sb) { + + case '\0': + goto OUT; + + case ' ': + case '\t': + INC_CHKCURSOR(sb); + goto S0; + + default: + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = sb; + break; + default: + break; + } + goto S1; + } + +S1: + switch (*sb) { + + case ' ': + case '\t': + case '\0': + goto OUT; /* end of token */ + + case '\\': + INC_CHKCURSOR(sb); + goto S2; /* slurp next character */ + + case '"': + INC_CHKCURSOR(sb); + goto S3; /* slurp quoted string */ + + default: + *ap = *sb; /* add character to token */ + ap++; + INC_CHKCURSOR(sb); + got_one = 1; + goto S1; + } + +S2: + switch (*sb) { + + case '\0': + goto OUT; + + default: + *ap = *sb; + ap++; + INC_CHKCURSOR(sb); + got_one = 1; + goto S1; + } + +S3: + switch (*sb) { + + case '\0': + goto OUT; + + case '"': + INC_CHKCURSOR(sb); + goto S1; + + default: + *ap = *sb; + ap++; + INC_CHKCURSOR(sb); + got_one = 1; + goto S3; + } + +OUT: + if (got_one) + *ap++ = '\0'; + argbase = ap; /* update storage pointer */ + stringbase = sb; /* update scan pointer */ + if (got_one) { + return (tmp); + } + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = NULL; + break; + default: + break; + } + return (NULL); +} + +/* + * Help/usage command. + * Call each command handler with argc == 0 and argv[0] == name. + */ +void +help(int argc, char *argv[]) +{ + struct cmd *c; + char *nargv[1], *p, *cmd; + int isusage; + + cmd = argv[0]; + isusage = (strcmp(cmd, "usage") == 0); + if (argc == 0 || (isusage && argc == 1)) { + fprintf(ttyout, "usage: %s [command [...]]\n", cmd); + return; + } + if (argc == 1) { + StringList *buf; + + buf = xsl_init(); + fprintf(ttyout, + "%sommands may be abbreviated. Commands are:\n\n", + proxy ? "Proxy c" : "C"); + for (c = cmdtab; (p = c->c_name) != NULL; c++) + if (!proxy || c->c_proxy) + xsl_add(buf, p); + list_vertical(buf); + sl_free(buf, 0); + return; + } + +#define HELPINDENT ((int) sizeof("disconnect")) + + while (--argc > 0) { + char *arg; + + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + fprintf(ttyout, "?Ambiguous %s command `%s'\n", + cmd, arg); + else if (c == NULL) + fprintf(ttyout, "?Invalid %s command `%s'\n", + cmd, arg); + else { + if (isusage) { + nargv[0] = c->c_name; + (*c->c_handler)(0, nargv); + } else + fprintf(ttyout, "%-*s\t%s\n", HELPINDENT, + c->c_name, c->c_help); + } + } +} + +struct option * +getoption(const char *name) +{ + const char *p; + struct option *c; + + if (name == NULL) + return (NULL); + for (c = optiontab; (p = c->name) != NULL; c++) { + if (strcasecmp(p, name) == 0) + return (c); + } + return (NULL); +} + +char * +getoptionvalue(const char *name) +{ + struct option *c; + + if (name == NULL) + errx(1, "getoptionvalue() invoked with NULL name"); + c = getoption(name); + if (c != NULL) + return (c->value); + errx(1, "getoptionvalue() invoked with unknown option `%s'", name); + /* NOTREACHED */ +} + +static void +setupoption(char *name, char *value, char *defaultvalue) +{ + char *nargv[3]; + int overbose; + + nargv[0] = "setupoption()"; + nargv[1] = name; + nargv[2] = (value ? value : defaultvalue); + overbose = verbose; + verbose = 0; + setoption(3, nargv); + verbose = overbose; +} + +void +usage(void) +{ + const char *progname = getprogname(); + + (void)fprintf(stderr, +"usage: %s [-46AadefginpRtvV] [-N netrc] [-o outfile] [-P port] [-q quittime]\n" +" [-r retry] [-T dir,max[,inc][[user@]host [port]]] [host:path[/]]\n" +" [file:///file] [ftp://[user[:pass]@]host[:port]/path[/]]\n" +" [http://[user[:pass]@]host[:port]/path] [...]\n" +" %s -u URL file [...]\n", progname, progname); + exit(1); +} diff --git a/src/bin/network/ftp/progressbar.c b/src/bin/network/ftp/progressbar.c new file mode 100644 index 0000000000..8e2487cb2e --- /dev/null +++ b/src/bin/network/ftp/progressbar.c @@ -0,0 +1,461 @@ +/* $NetBSD: progressbar.c,v 1.7 2005/04/11 01:49:31 lukem Exp $ */ + +/*- + * Copyright (c) 1997-2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +/* + * FTP User Program -- Misc support routines + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "progressbar.h" + +#define SECSPERHOUR (60 * 60) +#define SECSPERDAY ((long)60 * 60 * 24) + +#if !defined(NO_PROGRESS) +/* + * return non-zero if we're the current foreground process + */ +int +foregroundproc(void) +{ + static pid_t pgrp = -1; + + if (pgrp == -1) + pgrp = getpgrp(); + + return (tcgetpgrp(fileno(ttyout)) == pgrp); +} +#endif /* !defined(NO_PROGRESS) */ + + +static void updateprogressmeter(int); + +/* + * SIGALRM handler to update the progress meter + */ +static void +updateprogressmeter(int dummy) +{ + int oerrno = errno; + + progressmeter(0); + errno = oerrno; +} + +/* + * List of order of magnitude prefixes. + * The last is `P', as 2^64 = 16384 Petabytes + */ +static const char prefixes[] = " KMGTP"; + +/* + * Display a transfer progress bar if progress is non-zero. + * SIGALRM is hijacked for use by this function. + * - Before the transfer, set filesize to size of file (or -1 if unknown), + * and call with flag = -1. This starts the once per second timer, + * and a call to updateprogressmeter() upon SIGALRM. + * - During the transfer, updateprogressmeter will call progressmeter + * with flag = 0 + * - After the transfer, call with flag = 1 + */ +static struct timeval start; +static struct timeval lastupdate; + +#define BUFLEFT (sizeof(buf) - len) + +void +progressmeter(int flag) +{ + static off_t lastsize; + off_t cursize; + struct timeval now, wait; +#ifndef NO_PROGRESS + struct timeval td; + off_t abbrevsize, bytespersec; + double elapsed; + int ratio, barlength, i, remaining; + + /* + * Work variables for progress bar. + * + * XXX: if the format of the progress bar changes + * (especially the number of characters in the + * `static' portion of it), be sure to update + * these appropriately. + */ +#endif + int len; + char buf[256]; /* workspace for progress bar */ +#ifndef NO_PROGRESS +#define BAROVERHEAD 43 /* non `*' portion of progress bar */ + /* + * stars should contain at least + * sizeof(buf) - BAROVERHEAD entries + */ + static const char stars[] = +"*****************************************************************************" +"*****************************************************************************" +"*****************************************************************************"; + +#endif + + if (flag == -1) { + (void)gettimeofday(&start, NULL); + lastupdate = start; + lastsize = restart_point; + } + + (void)gettimeofday(&now, NULL); + cursize = bytes + restart_point; + timersub(&now, &lastupdate, &wait); + if (cursize > lastsize) { + lastupdate = now; + lastsize = cursize; + wait.tv_sec = 0; + } else { +#ifndef STANDALONE_PROGRESS + if (quit_time > 0 && wait.tv_sec > quit_time) { + len = snprintf(buf, sizeof(buf), "\r\n%s: " + "transfer aborted because stalled for %lu sec.\r\n", + getprogname(), (unsigned long)wait.tv_sec); + (void)write(fileno(ttyout), buf, len); + (void)xsignal(SIGALRM, SIG_DFL); + alarmtimer(0); + siglongjmp(toplevel, 1); + } +#endif /* !STANDALONE_PROGRESS */ + } + /* + * Always set the handler even if we are not the foreground process. + */ +#ifdef STANDALONE_PROGRESS + if (progress) { +#else + if (quit_time > 0 || progress) { +#endif /* !STANDALONE_PROGRESS */ + if (flag == -1) { + (void)xsignal_restart(SIGALRM, updateprogressmeter, 1); + alarmtimer(1); /* set alarm timer for 1 Hz */ + } else if (flag == 1) { + (void)xsignal(SIGALRM, SIG_DFL); + alarmtimer(0); + } + } +#ifndef NO_PROGRESS + if (!progress) + return; + len = 0; + + /* + * print progress bar only if we are foreground process. + */ + if (! foregroundproc()) + return; + + len += snprintf(buf + len, BUFLEFT, "\r"); + if (prefix) + len += snprintf(buf + len, BUFLEFT, "%s", prefix); + if (filesize > 0) { + ratio = (int)((double)cursize * 100.0 / (double)filesize); + ratio = MAX(ratio, 0); + ratio = MIN(ratio, 100); + len += snprintf(buf + len, BUFLEFT, "%3d%% ", ratio); + + /* + * calculate the length of the `*' bar, ensuring that + * the number of stars won't exceed the buffer size + */ + barlength = MIN(sizeof(buf) - 1, ttywidth) - BAROVERHEAD; + if (prefix) + barlength -= strlen(prefix); + if (barlength > 0) { + i = barlength * ratio / 100; + len += snprintf(buf + len, BUFLEFT, + "|%.*s%*s|", i, stars, barlength - i, ""); + } + } + + abbrevsize = cursize; + for (i = 0; abbrevsize >= 100000 && i < sizeof(prefixes); i++) + abbrevsize >>= 10; + len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %c%c ", + (LLT)abbrevsize, + prefixes[i], + i == 0 ? ' ' : 'B'); + + timersub(&now, &start, &td); + elapsed = td.tv_sec + (td.tv_usec / 1000000.0); + + bytespersec = 0; + if (bytes > 0) { + bytespersec = bytes; + if (elapsed > 0.0) + bytespersec /= elapsed; + } + for (i = 1; bytespersec >= 1024000 && i < sizeof(prefixes); i++) + bytespersec >>= 10; + len += snprintf(buf + len, BUFLEFT, + " " LLFP("3") ".%02d %cB/s ", + (LLT)(bytespersec / 1024), + (int)((bytespersec % 1024) * 100 / 1024), + prefixes[i]); + + if (filesize > 0) { + if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) { + len += snprintf(buf + len, BUFLEFT, " --:-- ETA"); + } else if (wait.tv_sec >= STALLTIME) { + len += snprintf(buf + len, BUFLEFT, " - stalled -"); + } else { + remaining = (int) + ((filesize - restart_point) / (bytes / elapsed) - + elapsed); + if (remaining >= 100 * SECSPERHOUR) + len += snprintf(buf + len, BUFLEFT, + " --:-- ETA"); + else { + i = remaining / SECSPERHOUR; + if (i) + len += snprintf(buf + len, BUFLEFT, + "%2d:", i); + else + len += snprintf(buf + len, BUFLEFT, + " "); + i = remaining % SECSPERHOUR; + len += snprintf(buf + len, BUFLEFT, + "%02d:%02d ETA", i / 60, i % 60); + } + } + } + if (flag == 1) + len += snprintf(buf + len, BUFLEFT, "\n"); + (void)write(fileno(ttyout), buf, len); + +#endif /* !NO_PROGRESS */ +} + +#ifndef STANDALONE_PROGRESS +/* + * Display transfer statistics. + * Requires start to be initialised by progressmeter(-1), + * direction to be defined by xfer routines, and filesize and bytes + * to be updated by xfer routines + * If siginfo is nonzero, an ETA is displayed, and the output goes to stderr + * instead of ttyout. + */ +void +ptransfer(int siginfo) +{ + struct timeval now, td, wait; + double elapsed; + off_t bytespersec; + int remaining, hh, i, len; + + char buf[256]; /* Work variable for transfer status. */ + + if (!verbose && !progress && !siginfo) + return; + + (void)gettimeofday(&now, NULL); + timersub(&now, &start, &td); + elapsed = td.tv_sec + (td.tv_usec / 1000000.0); + bytespersec = 0; + if (bytes > 0) { + bytespersec = bytes; + if (elapsed > 0.0) + bytespersec /= elapsed; + } + len = 0; + len += snprintf(buf + len, BUFLEFT, LLF " byte%s %s in ", + (LLT)bytes, bytes == 1 ? "" : "s", direction); + remaining = (int)elapsed; + if (remaining > SECSPERDAY) { + int days; + + days = remaining / SECSPERDAY; + remaining %= SECSPERDAY; + len += snprintf(buf + len, BUFLEFT, + "%d day%s ", days, days == 1 ? "" : "s"); + } + hh = remaining / SECSPERHOUR; + remaining %= SECSPERHOUR; + if (hh) + len += snprintf(buf + len, BUFLEFT, "%2d:", hh); + len += snprintf(buf + len, BUFLEFT, + "%02d:%02d ", remaining / 60, remaining % 60); + + for (i = 1; bytespersec >= 1024000 && i < sizeof(prefixes); i++) + bytespersec >>= 10; + len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %cB/s)", + (LLT)(bytespersec / 1024), + (int)((bytespersec % 1024) * 100 / 1024), + prefixes[i]); + + if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0 + && bytes + restart_point <= filesize) { + remaining = (int)((filesize - restart_point) / + (bytes / elapsed) - elapsed); + hh = remaining / SECSPERHOUR; + remaining %= SECSPERHOUR; + len += snprintf(buf + len, BUFLEFT, " ETA: "); + if (hh) + len += snprintf(buf + len, BUFLEFT, "%2d:", hh); + len += snprintf(buf + len, BUFLEFT, "%02d:%02d", + remaining / 60, remaining % 60); + timersub(&now, &lastupdate, &wait); + if (wait.tv_sec >= STALLTIME) + len += snprintf(buf + len, BUFLEFT, " (stalled)"); + } + len += snprintf(buf + len, BUFLEFT, "\n"); + (void)write(siginfo ? STDERR_FILENO : fileno(ttyout), buf, len); +} + +/* + * SIG{INFO,QUIT} handler to print transfer stats if a transfer is in progress + */ +void +psummary(int notused) +{ + int oerrno = errno; + + if (bytes > 0) { + if (fromatty) + write(fileno(ttyout), "\n", 1); + ptransfer(1); + } + errno = oerrno; +} +#endif /* !STANDALONE_PROGRESS */ + + +/* + * Set the SIGALRM interval timer for wait seconds, 0 to disable. + */ +void +alarmtimer(int wait) +{ + struct itimerval itv; + + itv.it_value.tv_sec = wait; + itv.it_value.tv_usec = 0; + itv.it_interval = itv.it_value; + setitimer(ITIMER_REAL, &itv, NULL); +} + + +/* + * Install a POSIX signal handler, allowing the invoker to set whether + * the signal should be restartable or not + */ +sigfunc +xsignal_restart(int sig, sigfunc func, int restartable) +{ + struct sigaction act, oact; + act.sa_handler = func; + + sigemptyset(&act.sa_mask); +#if defined(SA_RESTART) /* 4.4BSD, Posix(?), SVR4 */ + act.sa_flags = restartable ? SA_RESTART : 0; +#elif defined(SA_INTERRUPT) /* SunOS 4.x */ + act.sa_flags = restartable ? 0 : SA_INTERRUPT; +#else +#error "system must have SA_RESTART or SA_INTERRUPT" +#endif + if (sigaction(sig, &act, &oact) < 0) + return (SIG_ERR); + return (oact.sa_handler); +} + +/* + * Install a signal handler with the `restartable' flag set dependent upon + * which signal is being set. (This is a wrapper to xsignal_restart()) + */ +sigfunc +xsignal(int sig, sigfunc func) +{ + int restartable; + + /* + * Some signals print output or change the state of the process. + * There should be restartable, so that reads and writes are + * not affected. Some signals should cause program flow to change; + * these signals should not be restartable, so that the system call + * will return with EINTR, and the program will go do something + * different. If the signal handler calls longjmp() or siglongjmp(), + * it doesn't matter if it's restartable. + */ + + switch(sig) { +#ifdef SIGINFO + case SIGINFO: +#endif + case SIGQUIT: + case SIGUSR1: + case SIGUSR2: + case SIGWINCH: + restartable = 1; + break; + + case SIGALRM: + case SIGINT: + case SIGPIPE: + restartable = 0; + break; + + default: + /* + * This is unpleasant, but I don't know what would be better. + * Right now, this "can't happen" + */ + errx(1, "xsignal_restart called with signal %d", sig); + } + + return(xsignal_restart(sig, func, restartable)); +} diff --git a/src/bin/network/ftp/progressbar.h b/src/bin/network/ftp/progressbar.h new file mode 100644 index 0000000000..9e004f415b --- /dev/null +++ b/src/bin/network/ftp/progressbar.h @@ -0,0 +1,99 @@ +/* $NetBSD: progressbar.h,v 1.5 2005/02/10 16:00:38 jmc Exp $ */ + +/*- + * Copyright (c) 1996-2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STANDALONE_PROGRESS +#include +#endif /* !STANDALONE_PROGRESS */ + +#ifndef GLOBAL +#define GLOBAL extern +#endif + + +#define STALLTIME 5 /* # of seconds of no xfer before "stalling" */ + +typedef void (*sigfunc)(int); + + +GLOBAL FILE *ttyout; /* stdout, or stderr if retrieving to stdout */ + +GLOBAL int progress; /* display transfer progress bar */ +GLOBAL int ttywidth; /* width of tty */ + +GLOBAL off_t bytes; /* current # of bytes read */ +GLOBAL off_t filesize; /* size of file being transferred */ +GLOBAL off_t restart_point; /* offset to restart transfer */ +GLOBAL char *prefix; /* Text written left of progress bar */ + + +#ifndef STANDALONE_PROGRESS +GLOBAL int fromatty; /* input is from a terminal */ +GLOBAL int verbose; /* print messages coming back from server */ +GLOBAL int quit_time; /* maximum time to wait if stalled */ + +GLOBAL char *direction; /* direction transfer is occurring */ + +GLOBAL sigjmp_buf toplevel; /* non-local goto stuff for cmd scanner */ +#endif /* !STANDALONE_PROGRESS */ + +int foregroundproc(void); +void alarmtimer(int); +void progressmeter(int); +sigfunc xsignal(int, sigfunc); +sigfunc xsignal_restart(int, sigfunc, int); + +#ifndef STANDALONE_PROGRESS +void psummary(int); +void ptransfer(int); +#endif /* !STANDALONE_PROGRESS */ + +#ifdef NO_LONG_LONG +# define LLF "%ld" +# define LLFP(x) "%" x "ld" +# define LLT long +# define ULLF "%lu" +# define ULLFP(x) "%" x "lu" +# define ULLT unsigned long +#else +# define LLF "%lld" +# define LLFP(x) "%" x "lld" +# define LLT long long +# define ULLF "%llu" +# define ULLFP(x) "%" x "llu" +# define ULLT unsigned long long +#endif diff --git a/src/bin/network/ftp/ruserpass.c b/src/bin/network/ftp/ruserpass.c new file mode 100644 index 0000000000..ef0954bbdd --- /dev/null +++ b/src/bin/network/ftp/ruserpass.c @@ -0,0 +1,286 @@ +/* $NetBSD: ruserpass.c,v 1.29 2003/08/07 11:13:57 agc Exp $ */ + +/* + * Copyright (c) 1985, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +static int token(void); +static FILE *cfile; + +#define DEFAULT 1 +#define LOGIN 2 +#define PASSWD 3 +#define ACCOUNT 4 +#define MACDEF 5 +#define ID 10 +#define MACH 11 + +static char tokval[100]; + +static struct toktab { + char *tokstr; + int tval; +} toktab[] = { + { "default", DEFAULT }, + { "login", LOGIN }, + { "password", PASSWD }, + { "passwd", PASSWD }, + { "account", ACCOUNT }, + { "machine", MACH }, + { "macdef", MACDEF }, + { NULL, 0 } +}; + +int +ruserpass(const char *host, const char **aname, const char **apass, + const char **aacct) +{ + char *tmp; + char myname[MAXHOSTNAMELEN + 1], *mydomain; + int t, i, c, usedefault = 0; + struct stat stb; + + if (netrc[0] == '\0') + return (0); + cfile = fopen(netrc, "r"); + if (cfile == NULL) { + if (errno != ENOENT) + warn("%s", netrc); + return (0); + } + if (gethostname(myname, sizeof(myname)) < 0) + myname[0] = '\0'; + myname[sizeof(myname) - 1] = '\0'; + if ((mydomain = strchr(myname, '.')) == NULL) + mydomain = ""; + next: + while ((t = token())) switch(t) { + + case DEFAULT: + usedefault = 1; + /* FALL THROUGH */ + + case MACH: + if (!usedefault) { + if (token() != ID) + continue; + /* + * Allow match either for user's input host name + * or official hostname. Also allow match of + * incompletely-specified host in local domain. + */ + if (strcasecmp(host, tokval) == 0) + goto match; + if (strcasecmp(hostname, tokval) == 0) + goto match; + if ((tmp = strchr(hostname, '.')) != NULL && + strcasecmp(tmp, mydomain) == 0 && + strncasecmp(hostname, tokval, tmp-hostname) == 0 && + tokval[tmp - hostname] == '\0') + goto match; + if ((tmp = strchr(host, '.')) != NULL && + strcasecmp(tmp, mydomain) == 0 && + strncasecmp(host, tokval, tmp - host) == 0 && + tokval[tmp - host] == '\0') + goto match; + continue; + } + match: + while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { + + case LOGIN: + if (token()) { + if (*aname == NULL) + *aname = xstrdup(tokval); + else { + if (strcmp(*aname, tokval)) + goto next; + } + } + break; + case PASSWD: + if ((*aname == NULL || strcmp(*aname, "anonymous")) && + fstat(fileno(cfile), &stb) >= 0 && + (stb.st_mode & 077) != 0) { + warnx("Error: .netrc file is readable by others."); + warnx("Remove password or make file unreadable by others."); + goto bad; + } + if (token() && *apass == NULL) + *apass = xstrdup(tokval); + break; + case ACCOUNT: + if (fstat(fileno(cfile), &stb) >= 0 + && (stb.st_mode & 077) != 0) { + warnx("Error: .netrc file is readable by others."); + warnx("Remove account or make file unreadable by others."); + goto bad; + } + if (token() && *aacct == NULL) + *aacct = xstrdup(tokval); + break; + case MACDEF: + if (proxy) { + (void)fclose(cfile); + return (0); + } + while ((c = getc(cfile)) != EOF) + if (c != ' ' && c != '\t') + break; + if (c == EOF || c == '\n') { + fputs("Missing macdef name argument.\n", + ttyout); + goto bad; + } + if (macnum == 16) { + fputs( + "Limit of 16 macros have already been defined.\n", + ttyout); + goto bad; + } + tmp = macros[macnum].mac_name; + *tmp++ = c; + for (i = 0; i < 8 && (c = getc(cfile)) != EOF && + !isspace(c); ++i) { + *tmp++ = c; + } + if (c == EOF) { + fputs( + "Macro definition missing null line terminator.\n", + ttyout); + goto bad; + } + *tmp = '\0'; + if (c != '\n') { + while ((c = getc(cfile)) != EOF && c != '\n'); + } + if (c == EOF) { + fputs( + "Macro definition missing null line terminator.\n", + ttyout); + goto bad; + } + if (macnum == 0) { + macros[macnum].mac_start = macbuf; + } + else { + macros[macnum].mac_start = + macros[macnum-1].mac_end + 1; + } + tmp = macros[macnum].mac_start; + while (tmp != macbuf + 4096) { + if ((c = getc(cfile)) == EOF) { + fputs( + "Macro definition missing null line terminator.\n", + ttyout); + goto bad; + } + *tmp = c; + if (*tmp == '\n') { + if (*(tmp-1) == '\0') { + macros[macnum++].mac_end = tmp - 1; + break; + } + *tmp = '\0'; + } + tmp++; + } + if (tmp == macbuf + 4096) { + fputs("4K macro buffer exceeded.\n", + ttyout); + goto bad; + } + break; + default: + warnx("Unknown .netrc keyword %s", tokval); + break; + } + goto done; + } + done: + (void)fclose(cfile); + return (0); + bad: + (void)fclose(cfile); + return (-1); +} + +static int +token(void) +{ + char *cp; + int c; + struct toktab *t; + + if (feof(cfile) || ferror(cfile)) + return (0); + while ((c = getc(cfile)) != EOF && + (c == '\n' || c == '\t' || c == ' ' || c == ',')) + continue; + if (c == EOF) + return (0); + cp = tokval; + if (c == '"') { + while ((c = getc(cfile)) != EOF && c != '"') { + if (c == '\\') + c = getc(cfile); + *cp++ = c; + } + } else { + *cp++ = c; + while ((c = getc(cfile)) != EOF + && c != '\n' && c != '\t' && c != ' ' && c != ',') { + if (c == '\\') + c = getc(cfile); + *cp++ = c; + } + } + *cp = 0; + if (tokval[0] == 0) + return (0); + for (t = toktab; t->tokstr; t++) + if (!strcmp(t->tokstr, tokval)) + return (t->tval); + return (ID); +} diff --git a/src/bin/network/ftp/util.c b/src/bin/network/ftp/util.c new file mode 100644 index 0000000000..e990569ecc --- /dev/null +++ b/src/bin/network/ftp/util.c @@ -0,0 +1,1397 @@ +/* $NetBSD: util.c,v 1.123 2005/05/14 18:56:45 dsl Exp $ */ + +/*- + * Copyright (c) 1997-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * FTP User Program -- Misc support routines + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +#define TM_YEAR_BASE 1900 + +/* + * Connect to peer server and auto-login, if possible. + */ +void +setpeer(int argc, char *argv[]) +{ + char *host; + char *port; + + if (argc == 0) + goto usage; + if (connected) { + fprintf(ttyout, "Already connected to %s, use close first.\n", + hostname); + code = -1; + return; + } + if (argc < 2) + (void)another(&argc, &argv, "to"); + if (argc < 2 || argc > 3) { + usage: + fprintf(ttyout, "usage: %s host-name [port]\n", argv[0]); + code = -1; + return; + } + if (gatemode) + port = gateport; + else + port = ftpport; + if (argc > 2) + port = argv[2]; + + if (gatemode) { + if (gateserver == NULL || *gateserver == '\0') + errx(1, "gateserver not defined (shouldn't happen)"); + host = hookup(gateserver, port); + } else + host = hookup(argv[1], port); + + if (host) { + if (gatemode && verbose) { + fprintf(ttyout, + "Connecting via pass-through server %s\n", + gateserver); + } + + connected = 1; + /* + * Set up defaults for FTP. + */ + (void)strlcpy(typename, "ascii", sizeof(typename)); + type = TYPE_A; + curtype = TYPE_A; + (void)strlcpy(formname, "non-print", sizeof(formname)); + form = FORM_N; + (void)strlcpy(modename, "stream", sizeof(modename)); + mode = MODE_S; + (void)strlcpy(structname, "file", sizeof(structname)); + stru = STRU_F; + (void)strlcpy(bytename, "8", sizeof(bytename)); + bytesize = 8; + if (autologin) + (void)ftp_login(argv[1], NULL, NULL); + } +} + +static void +parse_feat(const char *line) +{ + + /* + * work-around broken ProFTPd servers that can't + * even obey RFC 2389. + */ + while (*line && isspace((int)*line)) + line++; + + if (strcasecmp(line, "MDTM") == 0) + features[FEAT_MDTM] = 1; + else if (strncasecmp(line, "MLST", sizeof("MLST") - 1) == 0) { + features[FEAT_MLST] = 1; + } else if (strcasecmp(line, "REST STREAM") == 0) + features[FEAT_REST_STREAM] = 1; + else if (strcasecmp(line, "SIZE") == 0) + features[FEAT_SIZE] = 1; + else if (strcasecmp(line, "TVFS") == 0) + features[FEAT_TVFS] = 1; +} + +/* + * Determine the remote system type (SYST) and features (FEAT). + * Call after a successful login (i.e, connected = -1) + */ +void +getremoteinfo(void) +{ + int overbose, i; + + overbose = verbose; + if (debug == 0) + verbose = -1; + + /* determine remote system type */ + if (command("SYST") == COMPLETE) { + if (overbose) { + char *cp, c; + + c = 0; + cp = strchr(reply_string + 4, ' '); + if (cp == NULL) + cp = strchr(reply_string + 4, '\r'); + if (cp) { + if (cp[-1] == '.') + cp--; + c = *cp; + *cp = '\0'; + } + + fprintf(ttyout, "Remote system type is %s.\n", + reply_string + 4); + if (cp) + *cp = c; + } + if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { + if (proxy) + unix_proxy = 1; + else + unix_server = 1; + /* + * Set type to 0 (not specified by user), + * meaning binary by default, but don't bother + * telling server. We can use binary + * for text files unless changed by the user. + */ + type = 0; + (void)strlcpy(typename, "binary", sizeof(typename)); + if (overbose) + fprintf(ttyout, + "Using %s mode to transfer files.\n", + typename); + } else { + if (proxy) + unix_proxy = 0; + else + unix_server = 0; + if (overbose && + !strncmp(reply_string, "215 TOPS20", 10)) + fputs( +"Remember to set tenex mode when transferring binary files from this machine.\n", + ttyout); + } + } + + /* determine features (if any) */ + for (i = 0; i < FEAT_max; i++) + features[i] = -1; + reply_callback = parse_feat; + if (command("FEAT") == COMPLETE) { + for (i = 0; i < FEAT_max; i++) { + if (features[i] == -1) + features[i] = 0; + } + features[FEAT_FEAT] = 1; + } else + features[FEAT_FEAT] = 0; + if (debug) { +#define DEBUG_FEAT(x) fprintf(ttyout, "features[" #x "] = %d\n", features[(x)]) + DEBUG_FEAT(FEAT_FEAT); + DEBUG_FEAT(FEAT_MDTM); + DEBUG_FEAT(FEAT_MLST); + DEBUG_FEAT(FEAT_REST_STREAM); + DEBUG_FEAT(FEAT_SIZE); + DEBUG_FEAT(FEAT_TVFS); +#undef DEBUG_FEAT + } + reply_callback = NULL; + + verbose = overbose; +} + +/* + * Reset the various variables that indicate connection state back to + * disconnected settings. + * The caller is responsible for issuing any commands to the remote server + * to perform a clean shutdown before this is invoked. + */ +void +cleanuppeer(void) +{ + + if (cout) + (void)fclose(cout); + cout = NULL; + connected = 0; + unix_server = 0; + unix_proxy = 0; + /* + * determine if anonftp was specifically set with -a + * (1), or implicitly set by auto_fetch() (2). in the + * latter case, disable after the current xfer + */ + if (anonftp == 2) + anonftp = 0; + data = -1; + epsv4bad = 0; + if (username) + free(username); + username = NULL; + if (!proxy) + macnum = 0; +} + +/* + * Top-level signal handler for interrupted commands. + */ +void +intr(int signo) +{ + + sigint_raised = 1; + alarmtimer(0); + if (fromatty) + write(fileno(ttyout), "\n", 1); + siglongjmp(toplevel, 1); +} + +/* + * Signal handler for lost connections; cleanup various elements of + * the connection state, and call cleanuppeer() to finish it off. + */ +void +lostpeer(int dummy) +{ + int oerrno = errno; + + alarmtimer(0); + if (connected) { + if (cout != NULL) { + (void)shutdown(fileno(cout), 1+1); + (void)fclose(cout); + cout = NULL; + } + if (data >= 0) { + (void)shutdown(data, 1+1); + (void)close(data); + data = -1; + } + connected = 0; + } + pswitch(1); + if (connected) { + if (cout != NULL) { + (void)shutdown(fileno(cout), 1+1); + (void)fclose(cout); + cout = NULL; + } + connected = 0; + } + proxflag = 0; + pswitch(0); + cleanuppeer(); + errno = oerrno; +} + + +/* + * Login to remote host, using given username & password if supplied. + * Return non-zero if successful. + */ +int +ftp_login(const char *host, const char *user, const char *pass) +{ + char tmp[80]; + const char *acct; + int n, aflag, rval, freeuser, freepass, freeacct; + + acct = NULL; + aflag = rval = freeuser = freepass = freeacct = 0; + + if (debug) + fprintf(ttyout, "ftp_login: user `%s' pass `%s' host `%s'\n", + user ? user : "", pass ? pass : "", + host ? host : ""); + + + /* + * Set up arguments for an anonymous FTP session, if necessary. + */ + if (anonftp) { + user = "anonymous"; /* as per RFC 1635 */ + pass = getoptionvalue("anonpass"); + } + + if (user == NULL) + freeuser = 1; + if (pass == NULL) + freepass = 1; + freeacct = 1; + if (ruserpass(host, &user, &pass, &acct) < 0) { + code = -1; + goto cleanup_ftp_login; + } + + while (user == NULL) { + if (localname) + fprintf(ttyout, "Name (%s:%s): ", host, localname); + else + fprintf(ttyout, "Name (%s): ", host); + *tmp = '\0'; + if (fgets(tmp, sizeof(tmp) - 1, stdin) == NULL) { + fprintf(ttyout, "\nEOF received; login aborted.\n"); + clearerr(stdin); + code = -1; + goto cleanup_ftp_login; + } + tmp[strlen(tmp) - 1] = '\0'; + freeuser = 0; + if (*tmp == '\0') + user = localname; + else + user = tmp; + } + + if (gatemode) { + char *nuser; + int len; + + len = strlen(user) + 1 + strlen(host) + 1; + nuser = xmalloc(len); + (void)strlcpy(nuser, user, len); + (void)strlcat(nuser, "@", len); + (void)strlcat(nuser, host, len); + freeuser = 1; + user = nuser; + } + + n = command("USER %s", user); + if (n == CONTINUE) { + if (pass == NULL) { + freepass = 0; + pass = getpass("Password:"); + } + n = command("PASS %s", pass); + } + if (n == CONTINUE) { + aflag++; + if (acct == NULL) { + freeacct = 0; + acct = getpass("Account:"); + } + if (acct[0] == '\0') { + warnx("Login failed."); + goto cleanup_ftp_login; + } + n = command("ACCT %s", acct); + } + if ((n != COMPLETE) || + (!aflag && acct != NULL && command("ACCT %s", acct) != COMPLETE)) { + warnx("Login failed."); + goto cleanup_ftp_login; + } + rval = 1; + username = xstrdup(user); + if (proxy) + goto cleanup_ftp_login; + + connected = -1; + getremoteinfo(); + for (n = 0; n < macnum; ++n) { + if (!strcmp("init", macros[n].mac_name)) { + (void)strlcpy(line, "$init", sizeof(line)); + makeargv(); + domacro(margc, margv); + break; + } + } + updatelocalcwd(); + updateremotecwd(); + + cleanup_ftp_login: + if (user != NULL && freeuser) + free((char *)user); + if (pass != NULL && freepass) + free((char *)pass); + if (acct != NULL && freeacct) + free((char *)acct); + return (rval); +} + +/* + * `another' gets another argument, and stores the new argc and argv. + * It reverts to the top level (via intr()) on EOF/error. + * + * Returns false if no new arguments have been added. + */ +int +another(int *pargc, char ***pargv, const char *prompt) +{ + int len = strlen(line), ret; + + if (len >= sizeof(line) - 3) { + fputs("sorry, arguments too long.\n", ttyout); + intr(0); + } + fprintf(ttyout, "(%s) ", prompt); + line[len++] = ' '; + if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) { + clearerr(stdin); + intr(0); + } + len += strlen(&line[len]); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + makeargv(); + ret = margc > *pargc; + *pargc = margc; + *pargv = margv; + return (ret); +} + +/* + * glob files given in argv[] from the remote server. + * if errbuf isn't NULL, store error messages there instead + * of writing to the screen. + */ +char * +remglob(char *argv[], int doswitch, char **errbuf) +{ + char temp[MAXPATHLEN]; + static char buf[MAXPATHLEN]; + static FILE *ftemp = NULL; + static char **args; + int oldverbose, oldhash, oldprogress, fd, len; + char *cp, *mode; + + if (!mflag || !connected) { + if (!doglob) + args = NULL; + else { + if (ftemp) { + (void)fclose(ftemp); + ftemp = NULL; + } + } + return (NULL); + } + if (!doglob) { + if (args == NULL) + args = argv; + if ((cp = *++args) == NULL) + args = NULL; + return (cp); + } + if (ftemp == NULL) { + len = strlcpy(temp, tmpdir, sizeof(temp)); + if (temp[len - 1] != '/') + (void)strlcat(temp, "/", sizeof(temp)); + (void)strlcat(temp, TMPFILE, sizeof(temp)); + if ((fd = mkstemp(temp)) < 0) { + warn("unable to create temporary file %s", temp); + return (NULL); + } + close(fd); + oldverbose = verbose; + verbose = (errbuf != NULL) ? -1 : 0; + oldhash = hash; + oldprogress = progress; + hash = 0; + progress = 0; + if (doswitch) + pswitch(!proxy); + for (mode = "w"; *++argv != NULL; mode = "a") + recvrequest("NLST", temp, *argv, mode, 0, 0); + if ((code / 100) != COMPLETE) { + if (errbuf != NULL) + *errbuf = reply_string; + } + if (doswitch) + pswitch(!proxy); + verbose = oldverbose; + hash = oldhash; + progress = oldprogress; + ftemp = fopen(temp, "r"); + (void)unlink(temp); + if (ftemp == NULL) { + if (errbuf == NULL) + fputs( + "can't find list of remote files, oops.\n", + ttyout); + else + *errbuf = + "can't find list of remote files, oops."; + return (NULL); + } + } + if (fgets(buf, sizeof(buf), ftemp) == NULL) { + (void)fclose(ftemp); + ftemp = NULL; + return (NULL); + } + if ((cp = strchr(buf, '\n')) != NULL) + *cp = '\0'; + return (buf); +} + +/* + * Glob a local file name specification with the expectation of a single + * return value. Can't control multiple values being expanded from the + * expression, we return only the first. + * Returns NULL on error, or a pointer to a buffer containing the filename + * that's the caller's responsiblity to free(3) when finished with. + */ +char * +globulize(const char *pattern) +{ + glob_t gl; + int flags; + char *p; + + if (!doglob) + return (xstrdup(pattern)); + + flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; + memset(&gl, 0, sizeof(gl)); + if (glob(pattern, flags, NULL, &gl) || gl.gl_pathc == 0) { + warnx("%s: not found", pattern); + globfree(&gl); + return (NULL); + } + p = xstrdup(gl.gl_pathv[0]); + globfree(&gl); + return (p); +} + +/* + * determine size of remote file + */ +off_t +remotesize(const char *file, int noisy) +{ + int overbose, r; + off_t size; + + overbose = verbose; + size = -1; + if (debug == 0) + verbose = -1; + if (! features[FEAT_SIZE]) { + if (noisy) + fprintf(ttyout, + "SIZE is not supported by remote server.\n"); + goto cleanup_remotesize; + } + r = command("SIZE %s", file); + if (r == COMPLETE) { + char *cp, *ep; + + cp = strchr(reply_string, ' '); + if (cp != NULL) { + cp++; + size = STRTOLL(cp, &ep, 10); + if (*ep != '\0' && !isspace((unsigned char)*ep)) + size = -1; + } + } else { + if (r == ERROR && code == 500 && features[FEAT_SIZE] == -1) + features[FEAT_SIZE] = 0; + if (noisy && debug == 0) { + fputs(reply_string, ttyout); + putc('\n', ttyout); + } + } + cleanup_remotesize: + verbose = overbose; + return (size); +} + +/* + * determine last modification time (in GMT) of remote file + */ +time_t +remotemodtime(const char *file, int noisy) +{ + int overbose, ocode, r; + time_t rtime; + + overbose = verbose; + ocode = code; + rtime = -1; + if (debug == 0) + verbose = -1; + if (! features[FEAT_MDTM]) { + if (noisy) + fprintf(ttyout, + "MDTM is not supported by remote server.\n"); + goto cleanup_parse_time; + } + r = command("MDTM %s", file); + if (r == COMPLETE) { + struct tm timebuf; + char *timestr, *frac; + int yy, mo, day, hour, min, sec; + + /* + * time-val = 14DIGIT [ "." 1*DIGIT ] + * YYYYMMDDHHMMSS[.sss] + * mdtm-response = "213" SP time-val CRLF / error-response + */ + timestr = reply_string + 4; + + /* + * parse fraction. + * XXX: ignored for now + */ + frac = strchr(timestr, '\r'); + if (frac != NULL) + *frac = '\0'; + frac = strchr(timestr, '.'); + if (frac != NULL) + *frac++ = '\0'; + if (strlen(timestr) == 15 && strncmp(timestr, "191", 3) == 0) { + /* + * XXX: Workaround for lame ftpd's that return + * `19100' instead of `2000' + */ + fprintf(ttyout, + "Y2K warning! Incorrect time-val `%s' received from server.\n", + timestr); + timestr++; + timestr[0] = '2'; + timestr[1] = '0'; + fprintf(ttyout, "Converted to `%s'\n", timestr); + } + if (strlen(timestr) != 14 || + sscanf(timestr, "%04d%02d%02d%02d%02d%02d", + &yy, &mo, &day, &hour, &min, &sec) != 6) { + bad_parse_time: + fprintf(ttyout, "Can't parse time `%s'.\n", timestr); + goto cleanup_parse_time; + } + memset(&timebuf, 0, sizeof(timebuf)); + timebuf.tm_sec = sec; + timebuf.tm_min = min; + timebuf.tm_hour = hour; + timebuf.tm_mday = day; + timebuf.tm_mon = mo - 1; + timebuf.tm_year = yy - TM_YEAR_BASE; + timebuf.tm_isdst = -1; + rtime = timegm(&timebuf); + if (rtime == -1) { + if (noisy || debug != 0) + goto bad_parse_time; + else + goto cleanup_parse_time; + } else if (debug) + fprintf(ttyout, "parsed date as: %s", ctime(&rtime)); + } else { + if (r == ERROR && code == 500 && features[FEAT_MDTM] == -1) + features[FEAT_MDTM] = 0; + if (noisy && debug == 0) { + fputs(reply_string, ttyout); + putc('\n', ttyout); + } + } + cleanup_parse_time: + verbose = overbose; + if (rtime == -1) + code = ocode; + return (rtime); +} + +/* + * Update global `localcwd', which contains the state of the local cwd + */ +void +updatelocalcwd(void) +{ + + if (getcwd(localcwd, sizeof(localcwd)) == NULL) + localcwd[0] = '\0'; + if (debug) + fprintf(ttyout, "got localcwd as `%s'\n", localcwd); +} + +/* + * Update global `remotecwd', which contains the state of the remote cwd + */ +void +updateremotecwd(void) +{ + int overbose, ocode, i; + char *cp; + + overbose = verbose; + ocode = code; + if (debug == 0) + verbose = -1; + if (command("PWD") != COMPLETE) + goto badremotecwd; + cp = strchr(reply_string, ' '); + if (cp == NULL || cp[0] == '\0' || cp[1] != '"') + goto badremotecwd; + cp += 2; + for (i = 0; *cp && i < sizeof(remotecwd) - 1; i++, cp++) { + if (cp[0] == '"') { + if (cp[1] == '"') + cp++; + else + break; + } + remotecwd[i] = *cp; + } + remotecwd[i] = '\0'; + if (debug) + fprintf(ttyout, "got remotecwd as `%s'\n", remotecwd); + goto cleanupremotecwd; + badremotecwd: + remotecwd[0]='\0'; + cleanupremotecwd: + verbose = overbose; + code = ocode; +} + +/* + * Ensure file is in or under dir. + * Returns 1 if so, 0 if not (or an error occurred). + */ +int +fileindir(const char *file, const char *dir) +{ + char realfile[PATH_MAX+1]; + size_t dirlen; + + if (realpath(file, realfile) == NULL) { + warn("Unable to determine real path of `%s'", file); + return 0; + } + if (realfile[0] != '/') /* relative result */ + return 1; + dirlen = strlen(dir); +#if 0 +printf("file %s realfile %s dir %s [%d]\n", file, realfile, dir, dirlen); +#endif + if (strncmp(realfile, dir, dirlen) == 0 && realfile[dirlen] == '/') + return 1; + return 0; +} + +/* + * List words in stringlist, vertically arranged + */ +void +list_vertical(StringList *sl) +{ + int i, j, w; + int columns, width, lines; + char *p; + + width = 0; + + for (i = 0 ; i < sl->sl_cur ; i++) { + w = strlen(sl->sl_str[i]); + if (w > width) + width = w; + } + width = (width + 8) &~ 7; + + columns = ttywidth / width; + if (columns == 0) + columns = 1; + lines = (sl->sl_cur + columns - 1) / columns; + for (i = 0; i < lines; i++) { + for (j = 0; j < columns; j++) { + p = sl->sl_str[j * lines + i]; + if (p) + fputs(p, ttyout); + if (j * lines + i + lines >= sl->sl_cur) { + putc('\n', ttyout); + break; + } + w = strlen(p); + while (w < width) { + w = (w + 8) &~ 7; + (void)putc('\t', ttyout); + } + } + } +} + +/* + * Update the global ttywidth value, using TIOCGWINSZ. + */ +void +setttywidth(int a) +{ + struct winsize winsize; + int oerrno = errno; + + if (ioctl(fileno(ttyout), TIOCGWINSZ, &winsize) != -1 && + winsize.ws_col != 0) + ttywidth = winsize.ws_col; + else + ttywidth = 80; + errno = oerrno; +} + +/* + * Change the rate limit up (SIGUSR1) or down (SIGUSR2) + */ +void +crankrate(int sig) +{ + + switch (sig) { + case SIGUSR1: + if (rate_get) + rate_get += rate_get_incr; + if (rate_put) + rate_put += rate_put_incr; + break; + case SIGUSR2: + if (rate_get && rate_get > rate_get_incr) + rate_get -= rate_get_incr; + if (rate_put && rate_put > rate_put_incr) + rate_put -= rate_put_incr; + break; + default: + err(1, "crankrate invoked with unknown signal: %d", sig); + } +} + + +/* + * Setup or cleanup EditLine structures + */ +#ifndef NO_EDITCOMPLETE +void +controlediting(void) +{ + if (editing && el == NULL && hist == NULL) { + HistEvent ev; + int editmode; + + el = el_init(getprogname(), stdin, ttyout, stderr); + /* init editline */ + hist = history_init(); /* init the builtin history */ + history(hist, &ev, H_SETSIZE, 100);/* remember 100 events */ + el_set(el, EL_HIST, history, hist); /* use history */ + + el_set(el, EL_EDITOR, "emacs"); /* default editor is emacs */ + el_set(el, EL_PROMPT, prompt); /* set the prompt functions */ + el_set(el, EL_RPROMPT, rprompt); + + /* add local file completion, bind to TAB */ + el_set(el, EL_ADDFN, "ftp-complete", + "Context sensitive argument completion", + complete); + el_set(el, EL_BIND, "^I", "ftp-complete", NULL); + el_source(el, NULL); /* read ~/.editrc */ + if ((el_get(el, EL_EDITMODE, &editmode) != -1) && editmode == 0) + editing = 0; /* the user doesn't want editing, + * so disable, and let statement + * below cleanup */ + else + el_set(el, EL_SIGNAL, 1); + } + if (!editing) { + if (hist) { + history_end(hist); + hist = NULL; + } + if (el) { + el_end(el); + el = NULL; + } + } +} +#endif /* !NO_EDITCOMPLETE */ + +/* + * Convert the string `arg' to an int, which may have an optional SI suffix + * (`b', `k', `m', `g'). Returns the number for success, -1 otherwise. + */ +int +strsuftoi(const char *arg) +{ + char *cp; + long val; + + if (!isdigit((unsigned char)arg[0])) + return (-1); + + val = strtol(arg, &cp, 10); + if (cp != NULL) { + if (cp[0] != '\0' && cp[1] != '\0') + return (-1); + switch (tolower((unsigned char)cp[0])) { + case '\0': + case 'b': + break; + case 'k': + val <<= 10; + break; + case 'm': + val <<= 20; + break; + case 'g': + val <<= 30; + break; + default: + return (-1); + } + } + if (val < 0 || val > INT_MAX) + return (-1); + + return (val); +} + +/* + * Set up socket buffer sizes before a connection is made. + */ +void +setupsockbufsize(int sock) +{ + + if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, + (void *)&sndbuf_size, sizeof(sndbuf_size)) == -1) + warn("unable to set sndbuf size %d", sndbuf_size); + + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, + (void *)&rcvbuf_size, sizeof(rcvbuf_size)) == -1) + warn("unable to set rcvbuf size %d", rcvbuf_size); +} + +/* + * Copy characters from src into dst, \ quoting characters that require it + */ +void +ftpvis(char *dst, size_t dstlen, const char *src, size_t srclen) +{ + int di, si; + + for (di = si = 0; + src[si] != '\0' && di < dstlen && si < srclen; + di++, si++) { + switch (src[si]) { + case '\\': + case ' ': + case '\t': + case '\r': + case '\n': + case '"': + dst[di++] = '\\'; + if (di >= dstlen) + break; + /* FALLTHROUGH */ + default: + dst[di] = src[si]; + } + } + dst[di] = '\0'; +} + +/* + * Copy src into buf (which is len bytes long), expanding % sequences. + */ +void +formatbuf(char *buf, size_t len, const char *src) +{ + const char *p; + char *p2, *q; + int i, op, updirs, pdirs; + +#define ADDBUF(x) do { \ + if (i >= len - 1) \ + goto endbuf; \ + buf[i++] = (x); \ + } while (0) + + p = src; + for (i = 0; *p; p++) { + if (*p != '%') { + ADDBUF(*p); + continue; + } + p++; + + switch (op = *p) { + + case '/': + case '.': + case 'c': + p2 = connected ? remotecwd : ""; + updirs = pdirs = 0; + + /* option to determine fixed # of dirs from path */ + if (op == '.' || op == 'c') { + int skip; + + q = p2; + while (*p2) /* calc # of /'s */ + if (*p2++ == '/') + updirs++; + if (p[1] == '0') { /* print or ... */ + pdirs = 1; + p++; + } + if (p[1] >= '1' && p[1] <= '9') { + /* calc # to skip */ + skip = p[1] - '0'; + p++; + } else + skip = 1; + + updirs -= skip; + while (skip-- > 0) { + while ((p2 > q) && (*p2 != '/')) + p2--; /* back up */ + if (skip && p2 > q) + p2--; + } + if (*p2 == '/' && p2 != q) + p2++; + } + + if (updirs > 0 && pdirs) { + if (i >= len - 5) + break; + if (op == '.') { + ADDBUF('.'); + ADDBUF('.'); + ADDBUF('.'); + } else { + ADDBUF('/'); + ADDBUF('<'); + if (updirs > 9) { + ADDBUF('9'); + ADDBUF('+'); + } else + ADDBUF('0' + updirs); + ADDBUF('>'); + } + } + for (; *p2; p2++) + ADDBUF(*p2); + break; + + case 'M': + case 'm': + for (p2 = connected && username ? username : "-"; + *p2 ; p2++) { + if (op == 'm' && *p2 == '.') + break; + ADDBUF(*p2); + } + break; + + case 'n': + for (p2 = connected ? username : "-"; *p2 ; p2++) + ADDBUF(*p2); + break; + + case '%': + ADDBUF('%'); + break; + + default: /* display unknown codes literally */ + ADDBUF('%'); + ADDBUF(op); + break; + + } + } + endbuf: + buf[i] = '\0'; +} + +/* + * Parse `port' into a TCP port number, defaulting to `defport' if `port' is + * an unknown service name. If defport != -1, print a warning upon bad parse. + */ +int +parseport(const char *port, int defport) +{ + int rv; + long nport; + char *p, *ep; + + p = xstrdup(port); + nport = strtol(p, &ep, 10); + if (*ep != '\0' && ep == p) { + struct servent *svp; + + svp = getservbyname(port, "tcp"); + if (svp == NULL) { + badparseport: + if (defport != -1) + warnx("Unknown port `%s', using port %d", + port, defport); + rv = defport; + } else + rv = ntohs(svp->s_port); + } else if (nport < 1 || nport > MAX_IN_PORT_T || *ep != '\0') + goto badparseport; + else + rv = nport; + free(p); + return (rv); +} + +/* + * Determine if given string is an IPv6 address or not. + * Return 1 for yes, 0 for no + */ +int +isipv6addr(const char *addr) +{ + int rv = 0; +#ifdef INET6 + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_INET6; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(addr, "0", &hints, &res) != 0) + rv = 0; + else { + rv = 1; + freeaddrinfo(res); + } + if (debug) + fprintf(ttyout, "isipv6addr: got %d for %s\n", rv, addr); +#endif + return (rv == 1) ? 1 : 0; +} + + +/* + * Internal version of connect(2); sets socket buffer sizes first and + * supports a connection timeout using a non-blocking connect(2) with + * a poll(2). + * Socket fcntl flags are temporarily updated to include O_NONBLOCK; + * these will not be reverted on connection failure. + * Returns -1 upon failure (with errno set to the problem), or 0 on success. + */ +int +xconnect(int sock, const struct sockaddr *name, socklen_t namelen) +{ + int flags, rv, timeout, error; + socklen_t slen; + struct timeval endtime, now, td; + struct pollfd pfd[1]; + + setupsockbufsize(sock); + + if ((flags = fcntl(sock, F_GETFL, 0)) == -1) + return -1; /* get current socket flags */ + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) + return -1; /* set non-blocking connect */ + + /* NOTE: we now must restore socket flags on successful exit */ + + pfd[0].fd = sock; + pfd[0].events = POLLIN|POLLOUT; + + if (quit_time > 0) { /* want a non default timeout */ + (void)gettimeofday(&endtime, NULL); + endtime.tv_sec += quit_time; /* determine end time */ + } + + rv = connect(sock, name, namelen); /* inititate the connection */ + if (rv == -1) { /* connection error */ + if (errno != EINPROGRESS) /* error isn't "please wait" */ + return -1; + + /* connect EINPROGRESS; wait */ + do { + if (quit_time > 0) { /* determine timeout */ + (void)gettimeofday(&now, NULL); + timersub(&endtime, &now, &td); + timeout = td.tv_sec * 1000 + td.tv_usec/1000; + if (timeout < 0) + timeout = 0; + } else { + timeout = INFTIM; + } + pfd[0].revents = 0; + rv = xpoll(pfd, 1, timeout); + /* loop until poll ! EINTR */ + } while (rv == -1 && errno == EINTR); + + if (rv == 0) { /* poll (connect) timed out */ + errno = ETIMEDOUT; + return -1; + } + + if (rv == -1) { /* poll error */ + return -1; + } else if (pfd[0].revents & (POLLIN|POLLOUT)) { + slen = sizeof(error); /* OK, or pending error */ + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, + &error, &slen) == -1) + return -1; /* Solaris pending error */ + if (error != 0) { + errno = error; /* BSD pending error */ + return -1; + } + } else { + errno = EBADF; /* this shouldn't happen ... */ + return -1; + } + } + + if (fcntl(sock, F_SETFL, flags) == -1) /* restore socket flags */ + return -1; + return 0; +} + +/* + * Internal version of listen(2); sets socket buffer sizes first. + */ +int +xlisten(int sock, int backlog) +{ + + setupsockbufsize(sock); + return (listen(sock, backlog)); +} + +/* + * Internal version of poll(2), to allow reimplementation by select(2) + * on platforms without the former. + */ +int +xpoll(struct pollfd *fds, int nfds, int timeout) +{ + return poll(fds, nfds, timeout); +} + +/* + * malloc() with inbuilt error checking + */ +void * +xmalloc(size_t size) +{ + void *p; + + p = malloc(size); + if (p == NULL) + err(1, "Unable to allocate %ld bytes of memory", (long)size); + return (p); +} + +/* + * sl_init() with inbuilt error checking + */ +StringList * +xsl_init(void) +{ + StringList *p; + + p = sl_init(); + if (p == NULL) + err(1, "Unable to allocate memory for stringlist"); + return (p); +} + +/* + * sl_add() with inbuilt error checking + */ +void +xsl_add(StringList *sl, char *i) +{ + + if (sl_add(sl, i) == -1) + err(1, "Unable to add `%s' to stringlist", i); +} + +/* + * strdup() with inbuilt error checking + */ +char * +xstrdup(const char *str) +{ + char *s; + + if (str == NULL) + errx(1, "xstrdup() called with NULL argument"); + s = strdup(str); + if (s == NULL) + err(1, "Unable to allocate memory for string copy"); + return (s); +} diff --git a/src/bin/network/ftp/version.h b/src/bin/network/ftp/version.h new file mode 100644 index 0000000000..7b69df1323 --- /dev/null +++ b/src/bin/network/ftp/version.h @@ -0,0 +1,44 @@ +/* $NetBSD: version.h,v 1.50 2005/05/14 15:26:43 lukem Exp $ */ +/*- + * Copyright (c) 1999-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FTP_PRODUCT +#define FTP_PRODUCT "NetBSD-ftp" +#endif + +#ifndef FTP_VERSION +#define FTP_VERSION "20050514" +#endif diff --git a/src/bin/ifconfig/Jamfile b/src/bin/network/ifconfig/Jamfile similarity index 83% rename from src/bin/ifconfig/Jamfile rename to src/bin/network/ifconfig/Jamfile index 31331fb30e..9248a374d9 100644 --- a/src/bin/ifconfig/Jamfile +++ b/src/bin/network/ifconfig/Jamfile @@ -1,6 +1,4 @@ -SubDir HAIKU_TOP src bin ifconfig ; - -SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ; +SubDir HAIKU_TOP src bin network ifconfig ; if $(TARGET_PLATFORM) != haiku { UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; @@ -8,10 +6,8 @@ if $(TARGET_PLATFORM) != haiku { # Unfortunately we get more than we want, namely all POSIX headers. } -UsePrivateHeaders net ; - BinCommand ifconfig : - ifconfig.c + ifconfig.cpp : libnetwork.so ; diff --git a/src/bin/network/ifconfig/ifconfig.cpp b/src/bin/network/ifconfig/ifconfig.cpp new file mode 100644 index 0000000000..088c0602d9 --- /dev/null +++ b/src/bin/network/ifconfig/ifconfig.cpp @@ -0,0 +1,672 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * Oliver Tappe, zooey@hirschkaefer.de + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +extern const char* __progname; +const char* kProgramName = __progname; + + +struct address_family { + int family; + const char* name; + const char* identifiers[4]; + bool (*parse_address)(const char* string, sockaddr* _address); + void (*print_address)(sockaddr* address); +}; + +// AF_INET family +static bool inet_parse_address(const char* string, sockaddr* address); +static void inet_print_address(sockaddr* address); + +static const address_family kFamilies[] = { + { + AF_INET, + "inet", + {"AF_INET", "inet", "ipv4", NULL}, + inet_parse_address, + inet_print_address + }, + { -1, NULL, {NULL}, NULL, NULL } +}; + + +static bool +inet_parse_address(const char* string, sockaddr* _address) +{ + in_addr inetAddress; + + if (inet_aton(string, &inetAddress) != 1) + return false; + + sockaddr_in& address = *(sockaddr_in *)_address; + address.sin_family = AF_INET; + address.sin_len = sizeof(struct sockaddr_in); + address.sin_port = 0; + address.sin_addr = inetAddress; + memset(&address.sin_zero[0], 0, sizeof(address.sin_zero)); + + return true; +} + + +static void +inet_print_address(sockaddr* _address) +{ + sockaddr_in& address = *(sockaddr_in *)_address; + + if (address.sin_family != AF_INET) + return; + + printf("%s", inet_ntoa(address.sin_addr)); +} + + +// #pragma mark - + + +void +usage(int status) +{ + printf("usage: %s [ [
] [
[]] [