diff options
author | bz <bz@FreeBSD.org> | 2010-09-02 17:43:44 +0000 |
---|---|---|
committer | bz <bz@FreeBSD.org> | 2010-09-02 17:43:44 +0000 |
commit | 18b40a43ee40b60f16950803b49724d0ef523293 (patch) | |
tree | 230de1f4337a85ebf5c0a3f05c9883bdd78fba3d /sys/netinet6 | |
parent | afcc72e27209509f7b650cea4f8607fb316ea2de (diff) | |
download | FreeBSD-src-18b40a43ee40b60f16950803b49724d0ef523293.zip FreeBSD-src-18b40a43ee40b60f16950803b49724d0ef523293.tar.gz |
MFp4 CH=183052 183053 183258:
In protosw we define pr_protocol as short, while on the wire
it is an uint8_t. That way we can have "internal" protocols
like DIVERT, SEND or gaps for modules (PROTO_SPACER).
Switch ipproto_{un,}register to accept a short protocol number(*)
and do an upfront check for valid boundries. With this we
also consistently report EPROTONOSUPPORT for out of bounds
protocols, as we did for proto == 0. This allows a caller
to not error for this case, which is especially important
if we want to automatically call these from domain handling.
(*) the functions have been without any in-tree consumer
since the initial introducation, so this is considered save.
Implement ip6proto_{un,}register() similarly to their legacy IP
counter parts to allow modules to hook up dynamically.
Reviewed by: philip, will
MFC after: 1 week
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/ip6_input.c | 58 | ||||
-rw-r--r-- | sys/netinet6/ip6_var.h | 3 |
2 files changed, 61 insertions, 0 deletions
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index ec82250..7e650a2 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -227,6 +227,64 @@ ip6_init(void) netisr_register(&ip6_nh); } +/* + * The protocol to be inserted into ip6_protox[] must be already registered + * in inet6sw[], either statically or through pf_proto_register(). + */ +int +ip6proto_register(short ip6proto) +{ + struct ip6protosw *pr; + + /* Sanity checks. */ + if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) + return (EPROTONOSUPPORT); + + /* + * The protocol slot must not be occupied by another protocol + * already. An index pointing to IPPROTO_RAW is unused. + */ + pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); + if (pr == NULL) + return (EPFNOSUPPORT); + if (ip6_protox[ip6proto] != pr - inet6sw) /* IPPROTO_RAW */ + return (EEXIST); + + /* + * Find the protocol position in inet6sw[] and set the index. + */ + for (pr = (struct ip6protosw *)inet6domain.dom_protosw; + pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) { + if (pr->pr_domain->dom_family == PF_INET6 && + pr->pr_protocol && pr->pr_protocol == ip6proto) { + ip6_protox[pr->pr_protocol] = pr - inet6sw; + return (0); + } + } + return (EPROTONOSUPPORT); +} + +int +ip6proto_unregister(short ip6proto) +{ + struct ip6protosw *pr; + + /* Sanity checks. */ + if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) + return (EPROTONOSUPPORT); + + /* Check if the protocol was indeed registered. */ + pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); + if (pr == NULL) + return (EPFNOSUPPORT); + if (ip6_protox[ip6proto] == pr - inet6sw) /* IPPROTO_RAW */ + return (ENOENT); + + /* Reset the protocol slot to IPPROTO_RAW. */ + ip6_protox[ip6proto] = pr - inet6sw; + return (0); +} + #ifdef VIMAGE void ip6_destroy() diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 3e91a79..51ae1f7 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -368,6 +368,9 @@ void ip6_init __P((void)); #ifdef VIMAGE void ip6_destroy __P((void)); #endif +int ip6proto_register(short); +int ip6proto_unregister(short); + void ip6_input __P((struct mbuf *)); struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *)); void ip6_freepcbopts __P((struct ip6_pktopts *)); |