Changeset View
Standalone View
share/man/man9/domain.9
.\" | .\" | |||||||||||||||||
.\" Copyright (C) 2001 Chad David <davidc@acns.ab.ca>. All rights reserved. | .\" Copyright (C) 2001 Chad David <davidc@acns.ab.ca>. All rights reserved. | |||||||||||||||||
.\" Copyright (C) 2022 Gleb Smirnoff <glebius@FreeBSD.org> | ||||||||||||||||||
.\" | .\" | |||||||||||||||||
.\" Redistribution and use in source and binary forms, with or without | .\" Redistribution and use in source and binary forms, with or without | |||||||||||||||||
.\" modification, are permitted provided that the following conditions | .\" modification, are permitted provided that the following conditions | |||||||||||||||||
.\" are met: | .\" are met: | |||||||||||||||||
.\" 1. Redistributions of source code must retain the above copyright | .\" 1. Redistributions of source code must retain the above copyright | |||||||||||||||||
.\" notice(s), this list of conditions and the following disclaimer as | .\" notice(s), this list of conditions and the following disclaimer as | |||||||||||||||||
.\" the first lines of this file unmodified other than the possible | .\" the first lines of this file unmodified other than the possible | |||||||||||||||||
.\" addition of one or more copyright notices. | .\" addition of one or more copyright notices. | |||||||||||||||||
Show All 10 Lines | ||||||||||||||||||
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||||||||||||||||
.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | .\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||||||||||||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | .\" 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 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |||||||||||||||||
.\" DAMAGE. | .\" DAMAGE. | |||||||||||||||||
.\" | .\" | |||||||||||||||||
.\" $FreeBSD$ | .\" $FreeBSD$ | |||||||||||||||||
.\" | .\" | |||||||||||||||||
.Dd January 3, 2022 | .Dd September 14, 2022 | |||||||||||||||||
.Dt DOMAIN 9 | .Dt DOMAIN 9 | |||||||||||||||||
.Os | .Os | |||||||||||||||||
.Sh NAME | .Sh NAME | |||||||||||||||||
.Nm domain_add , | .Nm domain , | |||||||||||||||||
.Nm domain_init , | .Nm protosw | |||||||||||||||||
.Nm pfctlinput , | .Nd "programming interface for kernel socket implementation" | |||||||||||||||||
debdrup: This can be word-smithed, I think. | ||||||||||||||||||
Not Done Inline ActionsIs that about kernel implementation of sockets for use by userland, or a kernel-internal API? pauamma_gundo.com: Is that about kernel implementation of sockets for use by userland, or a kernel-internal API? | ||||||||||||||||||
Done Inline ActionsThis is KPI (kernel PI) that allows to implement sockets for use by userland. The KPI itself doesn't create any kind of socket, but all existing sockets are built on it. glebius: This is KPI (kernel PI) that allows to implement sockets for use by userland. The KPI itself… | ||||||||||||||||||
.Nm pffinddomain , | ||||||||||||||||||
.Nm pffindproto , | ||||||||||||||||||
.Nm pffindtype , | ||||||||||||||||||
.Nm DOMAIN_SET | ||||||||||||||||||
.Nd "network domain management" | ||||||||||||||||||
.Sh SYNOPSIS | .Sh SYNOPSIS | |||||||||||||||||
.In sys/param.h | .In sys/param.h | |||||||||||||||||
.In sys/kernel.h | .In sys/kernel.h | |||||||||||||||||
.In sys/protosw.h | .In sys/protosw.h | |||||||||||||||||
.In sys/domain.h | .In sys/domain.h | |||||||||||||||||
.Ft void | .Ft void | |||||||||||||||||
.Fn domain_add "void *data" | .Fn domain_add "struct domain *dom" | |||||||||||||||||
.Ft void | .Ft void | |||||||||||||||||
.Fn domain_init "void *data" | .Fn domain_remove "struct domain *dom" | |||||||||||||||||
.Ft void | .Ft void | |||||||||||||||||
.Fn pfctlinput "int cmd" "struct sockaddr *sa" | .Fn DOMAIN_SET "domain" | |||||||||||||||||
.Ft struct domain * | .Ft int | |||||||||||||||||
.Fn pffinddomain "int family" | .Fn protosw_register "struct domain *dom" "struct protosw *pr" | |||||||||||||||||
.Ft struct protosw * | .Ft int | |||||||||||||||||
.Fn pffindproto "int family" "int protocol" "int type" | .Fn protosw_unregister "struct protosw *pr" | |||||||||||||||||
.Ft struct protosw * | ||||||||||||||||||
.Fn pffindtype "int family" "int type" | ||||||||||||||||||
.Ft void | ||||||||||||||||||
.Fn DOMAIN_SET "name" | ||||||||||||||||||
.Sh DESCRIPTION | .Sh DESCRIPTION | |||||||||||||||||
Network protocols installed in the system are maintained within what | The | |||||||||||||||||
are called domains | .Nm | |||||||||||||||||
(for example the | subsystem allows implementation of communication protocols that are exposed to | |||||||||||||||||
Done Inline Actions
A bit of word-smithing here too, might need to reflow the entire paragraph as a result. debdrup: A bit of word-smithing here too, might need to reflow the entire paragraph as a result. | ||||||||||||||||||
Not Done Inline Actions
Alternative rewording pauamma_gundo.com: Alternative rewording | ||||||||||||||||||
Done Inline ActionsCan you please guys agree on some final wording and I will abide. :) glebius: Can you please guys agree on some final wording and I will abide. :) | ||||||||||||||||||
.Va inetdomain | the userland via the | |||||||||||||||||
and | .Xr socket 2 | |||||||||||||||||
.Va localdomain ) . | API. | |||||||||||||||||
When an application performs a | ||||||||||||||||||
Done Inline Actions
Missing particle here. debdrup: Missing particle here. | ||||||||||||||||||
Done Inline Actions
2 missing articles, not 1. I'm undecided about "an application", "the application", or "applications".11 pauamma_gundo.com: 2 missing articles, not 1. I'm undecided about "an application", "the application", or… | ||||||||||||||||||
.Fn socket "domain" "type" "protocol" | ||||||||||||||||||
syscall, the kernel searches for a | ||||||||||||||||||
.Nm | ||||||||||||||||||
matching the | ||||||||||||||||||
.Ar domain | ||||||||||||||||||
argument, then within this domain, searches for a protocol | ||||||||||||||||||
Not Done Inline ActionsThere's a non-specific reference here, and I think the sentence can benefit from being rewritten but without understanding the reference I'm not having much luck coming up with something. debdrup: There's a non-specific reference here, and I think the sentence can benefit from being… | ||||||||||||||||||
Not Done Inline ActionsSee my guess below. pauamma_gundo.com: See my guess below. | ||||||||||||||||||
matching | ||||||||||||||||||
.Ar type . | ||||||||||||||||||
Done Inline Actions
What I think this likely means, clarified and copyedited. pauamma_gundo.com: What I think this likely means, clarified and copyedited. | ||||||||||||||||||
If the third argument, | ||||||||||||||||||
.Ar protocol , | ||||||||||||||||||
is not | ||||||||||||||||||
Done Inline Actions
There aren't 3 "protocol" argument, only one (which is 3rd in the argument list) pauamma_gundo.com: There aren't 3 "protocol" argument, only one (which is 3rd in the argument list) | ||||||||||||||||||
.Dv 0 , | ||||||||||||||||||
that value must also match. | ||||||||||||||||||
Done Inline Actions
"shall" as a future imperative modal is pretty much extinct. pauamma_gundo.com: "shall" as a future imperative modal is pretty much extinct. | ||||||||||||||||||
The structure found must implement certain methods, so that | ||||||||||||||||||
.Xr socket 2 | ||||||||||||||||||
API works for this particular kind of a socket. | ||||||||||||||||||
.Pp | ||||||||||||||||||
A minimal | ||||||||||||||||||
.Nm | ||||||||||||||||||
structure implementing a domain shall be initialized with sparse C99 | ||||||||||||||||||
initializer and has public fields as follows: | ||||||||||||||||||
.Bd -literal | .Bd -literal | |||||||||||||||||
struct domain { | struct domain { | |||||||||||||||||
int dom_family; /* AF_xxx */ | /* | |||||||||||||||||
char *dom_name; | * Mandatory fields. | |||||||||||||||||
int dom_flags; | */ | |||||||||||||||||
int (*dom_probe)(void); /* check for support (optional) */ | int dom_family; /* PF_xxx, first argument of socket(2) */ | |||||||||||||||||
int (*dom_externalize) /* externalize access rights */ | char *dom_name; /* text name of the domain */ | |||||||||||||||||
(struct mbuf *, struct mbuf **); | u_int dom_nprotosw; /* length of dom_protosw[] */ | |||||||||||||||||
void (*dom_dispose) /* dispose of internalized rights */ | /* | |||||||||||||||||
(struct mbuf *); | * Following methods are optional. | |||||||||||||||||
struct protosw *dom_protosw, *dom_protoswNPROTOSW; | */ | |||||||||||||||||
struct domain *dom_next; | int (*dom_probe)(void); /* check for support */ | |||||||||||||||||
int (*dom_rtattach) /* initialize routing table */ | struct rib_head *(*dom_rtattach)(uint32_t); /* init route table */ | |||||||||||||||||
(void **, int); | void (*dom_rtdetach)(struct rib_head *); /* clean up table */ | |||||||||||||||||
int (*dom_rtdetach) /* clean up routing table */ | void *(*dom_ifattach)(struct ifnet *); /* interface attach */ | |||||||||||||||||
(void **, int); | void (*dom_ifdetach)(struct ifnet *, void *);/* & detach callbacks */ | |||||||||||||||||
void *(*dom_ifattach)(struct ifnet *); | int (*dom_ifmtu)(struct ifnet *); /* mtu change */ | |||||||||||||||||
void (*dom_ifdetach)(struct ifnet *, void *); | /* | |||||||||||||||||
int (*dom_ifmtu)(struct ifnet *); | * Mandatory variable size array of pointers to protosw structs. | |||||||||||||||||
/* af-dependent data on ifnet */ | */ | |||||||||||||||||
struct protosw *dom_protosw[]; | ||||||||||||||||||
}; | }; | |||||||||||||||||
.Ed | .Ed | |||||||||||||||||
.Pp | .Pp | |||||||||||||||||
Each domain contains an array of protocol switch structures | Each domain contains the | |||||||||||||||||
.Va dom_protosw | ||||||||||||||||||
array of protocol switch structures | ||||||||||||||||||
.Pq Vt "struct protosw *" , | .Pq Vt "struct protosw *" , | |||||||||||||||||
one for each socket type supported. | one for each socket type supported. | |||||||||||||||||
The array may have | ||||||||||||||||||
.Dv NULL | ||||||||||||||||||
spacers for loadable protocols. | ||||||||||||||||||
Sparse C99 initializers shall be used to initialize | ||||||||||||||||||
.Nm protosw | ||||||||||||||||||
structures. | ||||||||||||||||||
The structure has mandatory field | ||||||||||||||||||
.Va pr_type | ||||||||||||||||||
and mandatory | ||||||||||||||||||
.Va pr_attach | ||||||||||||||||||
method. | ||||||||||||||||||
The rest of the methods are optional, but a meaningful protocol should | ||||||||||||||||||
Done Inline Actions
Missing particle here, paragraph might need to be reflowed. debdrup: Missing particle here, paragraph might need to be reflowed. | ||||||||||||||||||
implement some. | ||||||||||||||||||
.Bd -literal | .Bd -literal | |||||||||||||||||
struct protosw { | struct protosw { | |||||||||||||||||
short pr_type; /* socket type used for */ | short pr_type; /* second argument of socket(2) */ | |||||||||||||||||
struct domain *pr_domain; /* domain protocol a member of */ | short pr_protocol; /* third argument of socket(2) or 0 */ | |||||||||||||||||
short pr_protocol; /* protocol number */ | short pr_flags; /* see protosw.h */ | |||||||||||||||||
short pr_flags; /* see below */ | pr_soreceive_t *pr_soreceive; /* recv(2) */ | |||||||||||||||||
/* protocol-protocol hooks */ | pr_rcvd_t *pr_rcvd; /* soreceive_generic() if PR_WANTRCV */ | |||||||||||||||||
pr_input_t *pr_input; /* input to protocol (from below) */ | pr_sosend_t *pr_sosend; /* send(2) */ | |||||||||||||||||
pr_output_t *pr_output; /* output to protocol (from above) */ | pr_send_t *pr_send; /* send(2) via sosend_generic() */ | |||||||||||||||||
pr_ctlinput_t *pr_ctlinput; /* control input (from below) */ | pr_ready_t *pr_ready; /* sendfile/ktls readyness */ | |||||||||||||||||
pr_sopoll_t *pr_sopoll; /* poll(2) */ | ||||||||||||||||||
pr_attach_t *pr_attach; /* creation: socreate(), sonewconn() */ | ||||||||||||||||||
pr_detach_t *pr_detach; /* destruction: sofree() */ | ||||||||||||||||||
pr_connect_t *pr_connect; /* connect(2) */ | ||||||||||||||||||
pr_disconnect_t *pr_disconnect; /* sodisconnect() */ | ||||||||||||||||||
pr_close_t *pr_close; /* close(2) */ | ||||||||||||||||||
pr_shutdown_t *pr_shutdown; /* shutdown(2) */ | ||||||||||||||||||
pr_abort_t *pr_abort; /* abrupt tear down: soabort() */ | ||||||||||||||||||
pr_aio_queue_t *pr_aio_queue; /* aio(9) */ | ||||||||||||||||||
pr_bind_t *pr_bind; /* bind(2) */ | ||||||||||||||||||
pr_bindat_t *pr_bindat; /* bindat(2) */ | ||||||||||||||||||
pr_listen_t *pr_listen; /* listen(2) */ | ||||||||||||||||||
pr_accept_t *pr_accept; /* accept(2) */ | ||||||||||||||||||
pr_connectat_t *pr_connectat; /* connectat(2) */ | ||||||||||||||||||
pr_connect2_t *pr_connect2; /* socketpair(2) */ | ||||||||||||||||||
pr_control_t *pr_control; /* ioctl(2) */ | ||||||||||||||||||
pr_rcvoob_t *pr_rcvoob; /* soreceive_rcvoob() */ | ||||||||||||||||||
pr_ctloutput_t *pr_ctloutput; /* control output (from above) */ | pr_ctloutput_t *pr_ctloutput; /* control output (from above) */ | |||||||||||||||||
/* utility hooks */ | pr_peeraddr_t *pr_peeraddr; /* getpeername(2) */ | |||||||||||||||||
pr_fasttimo_t *pr_fasttimo; /* fast timeout (200ms) */ | pr_sockaddr_t *pr_sockaddr; /* getsockname(2) */ | |||||||||||||||||
pr_slowtimo_t *pr_slowtimo; /* slow timeout (500ms) */ | pr_sense_t *pr_sense; /* stat(2) */ | |||||||||||||||||
pr_drain_t *pr_drain; /* flush any excess space possible */ | ||||||||||||||||||
struct pr_usrreqs *pr_usrreqs; /* user-protocol hook */ | ||||||||||||||||||
}; | }; | |||||||||||||||||
.Ed | .Ed | |||||||||||||||||
.Pp | .Pp | |||||||||||||||||
The following functions handle the registration of a new domain, | The following functions handle the registration of new domains and protocols. | |||||||||||||||||
lookups of specific protocols and protocol types within those domains, | ||||||||||||||||||
and handle control messages from the system. | ||||||||||||||||||
.Pp | .Pp | |||||||||||||||||
.Fn pfctlinput | ||||||||||||||||||
is called by the system whenever an event occurs that could affect every | ||||||||||||||||||
domain. | ||||||||||||||||||
Examples of those types of events are routing table changes, interface | ||||||||||||||||||
shutdowns or certain | ||||||||||||||||||
.Tn ICMP | ||||||||||||||||||
message types. | ||||||||||||||||||
When called, | ||||||||||||||||||
.Fn pfctlinput | ||||||||||||||||||
calls the protocol specific | ||||||||||||||||||
.Fn pr_ctlinput | ||||||||||||||||||
function for each protocol in that has defined one, in every domain. | ||||||||||||||||||
.Pp | ||||||||||||||||||
.Fn domain_add | .Fn domain_add | |||||||||||||||||
adds a new protocol domain to the system. | adds a new protocol domain to the system. | |||||||||||||||||
The argument | ||||||||||||||||||
.Fa data | ||||||||||||||||||
is cast directly to | ||||||||||||||||||
.Vt "struct domain *" | ||||||||||||||||||
within the function, but is declared | ||||||||||||||||||
.Vt "void *" | ||||||||||||||||||
in order to prevent compiler warnings when new domains are registered with | ||||||||||||||||||
.Fn SYSINIT . | ||||||||||||||||||
In most cases | In most cases | |||||||||||||||||
.Fn domain_add | .Fn domain_add | |||||||||||||||||
is not called directly, instead | is not called directly, instead | |||||||||||||||||
.Fn DOMAIN_SET | .Fn DOMAIN_SET | |||||||||||||||||
is used. | is used, which is a wrapper around | |||||||||||||||||
.Pp | .Fn SYSINIT | |||||||||||||||||
Done Inline Actions.Xr SYSINIT 9 You might add it to SEE ALSO as well/instead. mhorne: `.Xr SYSINIT 9`
You might add it to SEE ALSO as well/instead. | ||||||||||||||||||
If the new domain has defined a probe routine, it is called first in | macro. | |||||||||||||||||
If the new domain has defined a | ||||||||||||||||||
.Va dom_probe | ||||||||||||||||||
routine, it is called first in | ||||||||||||||||||
.Fn domain_add | .Fn domain_add | |||||||||||||||||
to determine if the domain should be supported on the current system. | to determine if the domain should be supported on the current system. | |||||||||||||||||
If the probe routine returns a non-0 value, then the domain will not be | If the probe routine returns a non-0 value, then the domain will not be added. | |||||||||||||||||
marked as supported. | ||||||||||||||||||
Unsupported domains do not proceed with the initialization process and are not | ||||||||||||||||||
discoverable by | ||||||||||||||||||
.Fn pffinddomain , | ||||||||||||||||||
.Fn pffindtype , | ||||||||||||||||||
or | ||||||||||||||||||
.Fn pffindproto . | ||||||||||||||||||
.Pp | ||||||||||||||||||
.Fn domain_init | ||||||||||||||||||
is called after | ||||||||||||||||||
.Fn domain_add | ||||||||||||||||||
during boot and for each | ||||||||||||||||||
.Xr vnet 9 . | ||||||||||||||||||
If the new domain has defined an initialization routine, it is called during | ||||||||||||||||||
.Fn domain_init ; | ||||||||||||||||||
as well, each of the protocols within the domain that have defined an | ||||||||||||||||||
initialization routine will have theirs called. | ||||||||||||||||||
Note that domain initialization cannot fail at this time. | ||||||||||||||||||
.Pp | ||||||||||||||||||
Once a domain is added it cannot be completely unloaded. | Once a domain is added it cannot be completely unloaded. | |||||||||||||||||
This is because there is | This is because there is | |||||||||||||||||
no reference counting system in place to determine if there are any | no reference counting system in place to determine if there are any | |||||||||||||||||
active references from sockets within that domain. | active references from sockets within that domain. | |||||||||||||||||
However, the exprimental | ||||||||||||||||||
.Fn domain_remove | ||||||||||||||||||
exists, and unloadable domains may be supported in the future. | ||||||||||||||||||
.Pp | .Pp | |||||||||||||||||
.Fn pffinddomain | .Fn protosw_register | |||||||||||||||||
finds a domain by family. | dynamically adds a protocol to a domain, if the latter | |||||||||||||||||
If the domain cannot be found, | has an empty slot in its | |||||||||||||||||
.Dv NULL | .Va dom_protosw . | |||||||||||||||||
is returned. | Dynamically added protocol can later be unloaded with | |||||||||||||||||
.Pp | .Fn protosw_unregister . | |||||||||||||||||
.Fn pffindtype | ||||||||||||||||||
and | ||||||||||||||||||
.Fn pffindproto | ||||||||||||||||||
look up a protocol by its number or by its type. | ||||||||||||||||||
In most cases, if the protocol or type cannot be found, | ||||||||||||||||||
.Dv NULL | ||||||||||||||||||
is returned, but | ||||||||||||||||||
.Fn pffindproto | ||||||||||||||||||
may return the default if the requested type is | ||||||||||||||||||
.Dv SOCK_RAW , | ||||||||||||||||||
a protocol switch type of | ||||||||||||||||||
.Dv SOCK_RAW | ||||||||||||||||||
is found, and the domain has a default raw protocol. | ||||||||||||||||||
.Pp | ||||||||||||||||||
Both functions are called by | ||||||||||||||||||
.Fn socreate | ||||||||||||||||||
in order to resolve the protocol for the socket currently being created. | ||||||||||||||||||
.Pp | ||||||||||||||||||
.Fn DOMAIN_SET | ||||||||||||||||||
is a macro that simplifies the registration of a domain via | ||||||||||||||||||
.Fn SYSINIT . | ||||||||||||||||||
The code resulting from the macro expects there to be a domain structure | ||||||||||||||||||
named | ||||||||||||||||||
.Dq Fa name Ns Li domain | ||||||||||||||||||
where | ||||||||||||||||||
.Fa name | ||||||||||||||||||
is the argument to | ||||||||||||||||||
.Fn DOMAIN_SET : | ||||||||||||||||||
.Bd -literal | ||||||||||||||||||
struct domain localdomain = | ||||||||||||||||||
{ AF_LOCAL, "local", unp_init, unp_externalize, unp_dispose, | ||||||||||||||||||
localsw, &localsw[sizeof(localsw)/sizeof(localsw[0])] }; | ||||||||||||||||||
DOMAIN_SET(local); | ||||||||||||||||||
.Ed | .Ed | |||||||||||||||||
.Sh RETURN VALUES | .Sh RETURN VALUES | |||||||||||||||||
Both | The | |||||||||||||||||
.Fn pffindtype | .Fn domain_add | |||||||||||||||||
never fails, but it may not add a domain if its | ||||||||||||||||||
.Va dom_probe | ||||||||||||||||||
fails. | ||||||||||||||||||
.Pp | ||||||||||||||||||
The | ||||||||||||||||||
.Fn protosw_register | ||||||||||||||||||
function may fail if: | ||||||||||||||||||
.Bl -tag -width Er | ||||||||||||||||||
.It Bq Er EEXIST | ||||||||||||||||||
A protocol with the same value of | ||||||||||||||||||
.Va pr_type | ||||||||||||||||||
and | and | |||||||||||||||||
.Fn pffindproto | .Va pr_protocol | |||||||||||||||||
return a | already exists in the domain. | |||||||||||||||||
.Vt "struct protosw *" | .It Bq Er ENOMEM | |||||||||||||||||
for the protocol requested. | The domain doesn't have any NULL slots in its | |||||||||||||||||
If the protocol or socket type is not found, | .Va dom_protosw . | |||||||||||||||||
.Dv NULL | .El | |||||||||||||||||
is returned. | ||||||||||||||||||
In the case of | ||||||||||||||||||
.Fn pffindproto , | ||||||||||||||||||
the default protocol may be returned for | ||||||||||||||||||
.Dv SOCK_RAW | ||||||||||||||||||
types if the domain has a default raw protocol. | ||||||||||||||||||
.Sh SEE ALSO | .Sh SEE ALSO | |||||||||||||||||
.Xr socket 2 | .Xr socket 2 , | |||||||||||||||||
.Xr SYSINIT 9 | ||||||||||||||||||
.Sh HISTORY | .Sh HISTORY | |||||||||||||||||
The functions | The | |||||||||||||||||
.Fn domain_add , | .Nm | |||||||||||||||||
.Fn pfctlinput , | subsystem first appeared in | |||||||||||||||||
Done Inline ActionsI'd suggest using existing "X first appeared in N", as that's common across a wide variety of manual pages. debdrup: I'd suggest using existing "X first appeared in N", as that's common across a wide variety of… | ||||||||||||||||||
.Fn pffinddomain , | .Bx 4.3 | |||||||||||||||||
.Fn pffindproto , | as the part of the very first | |||||||||||||||||
.Fn pffindtype | .Xr socket 2 | |||||||||||||||||
and | API implementation. | |||||||||||||||||
.Fn DOMAIN_SET | .Pp | |||||||||||||||||
first appeared in | The | |||||||||||||||||
.Fx 4.4 . | .Nm | |||||||||||||||||
subsystem and this manual page were significantly rewritten in | ||||||||||||||||||
.Fx 14 . | ||||||||||||||||||
.Sh AUTHORS | .Sh AUTHORS | |||||||||||||||||
This manual page was written by | This manual page was written by | |||||||||||||||||
.An Chad David Aq Mt davidc@acns.ab.ca . | .An Chad David Aq Mt davidc@acns.ab.ca | |||||||||||||||||
and | ||||||||||||||||||
.An Gleb Smirnoff Aq Mt glebius@FreeBSD.org . |
This can be word-smithed, I think.