diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index 5e1b264ee941..c9fe3957a98e 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -69,9 +69,23 @@ struct domain *domains; /* registered protocol domains */ struct mtx dom_mtx; /* domain list lock */ MTX_SYSINIT(domain, &dom_mtx, "domain list", MTX_DEF); +/* + * Dummy protocol specific user requests function pointer array. + * All functions return EOPNOTSUPP. + */ +struct pr_usrreqs nousrreqs = { + pru_abort_notsupp, pru_accept_notsupp, pru_attach_notsupp, + pru_bind_notsupp, pru_connect_notsupp, pru_connect2_notsupp, + pru_control_notsupp, pru_detach_notsupp, pru_disconnect_notsupp, + pru_listen_notsupp, pru_peeraddr_notsupp, pru_rcvd_notsupp, + pru_rcvoob_notsupp, pru_send_notsupp, pru_sense_null, + pru_shutdown_notsupp, pru_sockaddr_notsupp, pru_sosend_notsupp, + pru_soreceive_notsupp, pru_sopoll_notsupp, pru_sosetlabel_null +}; + /* * Add a new protocol domain to the list of supported domains - * Note: you cant unload it again because a socket may be using it. + * Note: you cant unload it again because a socket may be using it. * XXX can't fail at this time. */ static void @@ -98,7 +112,7 @@ net_init_domain(struct domain *dp) /* * Add a new protocol domain to the list of supported domains - * Note: you cant unload it again because a socket may be using it. + * Note: you cant unload it again because a socket may be using it. * XXX can't fail at this time. */ void @@ -190,6 +204,126 @@ pffindproto(family, protocol, type) return (maybe); } +/* + * The caller must make sure that the new protocol is fully set up and ready to + * accept requests before it is registered. + */ +int +pf_proto_register(family, npr) + int family; + struct protosw *npr; +{ + struct domain *dp; + struct protosw *pr, *fpr; + + /* Sanity checks. */ + if (family == 0) + return (EPFNOSUPPORT); + if (npr->pr_type == 0) + return (EPROTOTYPE); + if (npr->pr_protocol == 0) + return (EPROTONOSUPPORT); + if (npr->pr_usrreqs == NULL) + return (ENXIO); + + /* Try to find the specified domain based on the family. */ + for (dp = domains; dp; dp = dp->dom_next) + if (dp->dom_family == family) + goto found; + return (EPFNOSUPPORT); + +found: + /* Initialize backpointer to struct domain. */ + npr->pr_domain = dp; + fpr = NULL; + + /* The new protocol must not yet exist. */ + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { + if ((pr->pr_type == npr->pr_type) && + (pr->pr_protocol == npr->pr_protocol)) + return (EEXIST); /* XXX: Check only protocol? */ + /* While here, remember the first free spacer. */ + if ((fpr == NULL) && (pr->pr_protocol == PROTO_SPACER)) + fpr = pr; + } + + /* If no free spacer is found we can't add the new protocol. */ + if (fpr == NULL) + return (ENOMEM); + + /* Copy the new struct protosw over the spacer. */ + bcopy(npr, fpr, sizeof(*fpr)); + + /* Initialize and activate the protocol. */ + if (fpr->pr_init) + (fpr->pr_init)(); + + return (0); +} + +/* + * The caller must make sure the protocol and its functions correctly shut down + * all sockets and release all locks and memory references. + */ +int +pf_proto_unregister(family, protocol, type) + int family; + int protocol; + int type; +{ + struct domain *dp; + struct protosw *pr, *dpr; + + /* Sanity checks. */ + if (family == 0) + return (EPFNOSUPPORT); + if (protocol == 0) + return (EPROTONOSUPPORT); + if (type == 0) + return (EPROTOTYPE); + + /* Try to find the specified domain based on the family type. */ + for (dp = domains; dp; dp = dp->dom_next) + if (dp->dom_family == family) + goto found; + return (EPFNOSUPPORT); + +found: + dpr = NULL; + + /* The protocol must exist and only once. */ + for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { + if ((pr->pr_type == type) && (pr->pr_protocol == protocol)) { + if (dpr != NULL) + return (EMLINK); /* Should not happen! */ + else + dpr = pr; + } + } + + /* Protocol does not exist. */ + if (dpr == NULL) + return (EPROTONOSUPPORT); + + /* De-orbit the protocol and make the slot available again. */ + dpr->pr_type = 0; + dpr->pr_domain = dp; + dpr->pr_protocol = PROTO_SPACER; + dpr->pr_flags = 0; + dpr->pr_input = NULL; + dpr->pr_output = NULL; + dpr->pr_ctlinput = NULL; + dpr->pr_ctloutput = NULL; + dpr->pr_ousrreq = NULL; + dpr->pr_init = NULL; + dpr->pr_fasttimo = NULL; + dpr->pr_slowtimo = NULL; + dpr->pr_drain = NULL; + dpr->pr_usrreqs = &nousrreqs; + + return (0); +} + void pfctlinput(cmd, sa) int cmd; diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 02b68d868f60..eff3c6f81e8a 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -1276,12 +1276,30 @@ sbcreatecontrol(p, size, type, level) * Some routines that return EOPNOTSUPP for entry points that are not * supported by a protocol. Fill in as needed. */ +int +pru_abort_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + int pru_accept_notsupp(struct socket *so, struct sockaddr **nam) { return EOPNOTSUPP; } +int +pru_attach_notsupp(struct socket *so, int proto, struct thread *td) +{ + return EOPNOTSUPP; +} + +int +pru_bind_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + return EOPNOTSUPP; +} + int pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td) { @@ -1296,7 +1314,19 @@ pru_connect2_notsupp(struct socket *so1, struct socket *so2) int pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp, struct thread *td) + struct ifnet *ifp, struct thread *td) +{ + return EOPNOTSUPP; +} + +int +pru_detach_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + +int +pru_disconnect_notsupp(struct socket *so) { return EOPNOTSUPP; } @@ -1307,6 +1337,12 @@ pru_listen_notsupp(struct socket *so, struct thread *td) return EOPNOTSUPP; } +int +pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam) +{ + return EOPNOTSUPP; +} + int pru_rcvd_notsupp(struct socket *so, int flags) { @@ -1319,6 +1355,13 @@ pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags) return EOPNOTSUPP; } +int +pru_send_notsupp(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *addr, struct mbuf *control, struct thread *td) +{ + return EOPNOTSUPP; +} + /* * This isn't really a ``null'' operation, but it's the default one * and doesn't do anything destructive. @@ -1330,6 +1373,40 @@ pru_sense_null(struct socket *so, struct stat *sb) return 0; } +int +pru_shutdown_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + +int +pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam) +{ + return EOPNOTSUPP; +} + +int +pru_sosend_notsupp(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, struct thread *td) +{ + return EOPNOTSUPP; +} + +int +pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr, + struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, + int *flagsp) +{ + return EOPNOTSUPP; +} + +int +pru_sopoll_notsupp(struct socket *so, int events, struct ucred *cred, + struct thread *td) +{ + return EOPNOTSUPP; +} + /* * For protocol types that don't keep cached copies of labels in their * pcbs, provide a null sosetlabel that does a NOOP. diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 02b68d868f60..eff3c6f81e8a 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -1276,12 +1276,30 @@ sbcreatecontrol(p, size, type, level) * Some routines that return EOPNOTSUPP for entry points that are not * supported by a protocol. Fill in as needed. */ +int +pru_abort_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + int pru_accept_notsupp(struct socket *so, struct sockaddr **nam) { return EOPNOTSUPP; } +int +pru_attach_notsupp(struct socket *so, int proto, struct thread *td) +{ + return EOPNOTSUPP; +} + +int +pru_bind_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + return EOPNOTSUPP; +} + int pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td) { @@ -1296,7 +1314,19 @@ pru_connect2_notsupp(struct socket *so1, struct socket *so2) int pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp, struct thread *td) + struct ifnet *ifp, struct thread *td) +{ + return EOPNOTSUPP; +} + +int +pru_detach_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + +int +pru_disconnect_notsupp(struct socket *so) { return EOPNOTSUPP; } @@ -1307,6 +1337,12 @@ pru_listen_notsupp(struct socket *so, struct thread *td) return EOPNOTSUPP; } +int +pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam) +{ + return EOPNOTSUPP; +} + int pru_rcvd_notsupp(struct socket *so, int flags) { @@ -1319,6 +1355,13 @@ pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags) return EOPNOTSUPP; } +int +pru_send_notsupp(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *addr, struct mbuf *control, struct thread *td) +{ + return EOPNOTSUPP; +} + /* * This isn't really a ``null'' operation, but it's the default one * and doesn't do anything destructive. @@ -1330,6 +1373,40 @@ pru_sense_null(struct socket *so, struct stat *sb) return 0; } +int +pru_shutdown_notsupp(struct socket *so) +{ + return EOPNOTSUPP; +} + +int +pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam) +{ + return EOPNOTSUPP; +} + +int +pru_sosend_notsupp(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, struct thread *td) +{ + return EOPNOTSUPP; +} + +int +pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr, + struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, + int *flagsp) +{ + return EOPNOTSUPP; +} + +int +pru_sopoll_notsupp(struct socket *so, int events, struct ucred *cred, + struct thread *td) +{ + return EOPNOTSUPP; +} + /* * For protocol types that don't keep cached copies of labels in their * pcbs, provide a null sosetlabel that does a NOOP. diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h index 617ab59da89d..f4bb7343c985 100644 --- a/sys/sys/protosw.h +++ b/sys/sys/protosw.h @@ -104,6 +104,12 @@ struct protosw { #define PR_SLOWHZ 2 /* 2 slow timeouts per second */ #define PR_FASTHZ 5 /* 5 fast timeouts per second */ +/* + * This number should be defined again within each protocol family to avoid + * confusion. + */ +#define PROTO_SPACER 32767 /* spacer for loadable protocols */ + /* * Values for pr_flags. * PR_ADDR requires PR_ATOMIC; @@ -231,16 +237,41 @@ struct pr_usrreqs { void (*pru_sosetlabel)(struct socket *so); }; +/* + * The dummy protocol specific user requests function pointer array is + * initialized to the functions below. All functions return EOPNOTSUPP. + */ +extern struct pr_usrreqs nousrreqs; + +int pru_abort_notsupp(struct socket *so); int pru_accept_notsupp(struct socket *so, struct sockaddr **nam); +int pru_attach_notsupp(struct socket *so, int proto, struct thread *td); +int pru_bind_notsupp(struct socket *so, struct sockaddr *nam, + struct thread *td); int pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td); int pru_connect2_notsupp(struct socket *so1, struct socket *so2); int pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td); +int pru_detach_notsupp(struct socket *so); +int pru_disconnect_notsupp(struct socket *so); int pru_listen_notsupp(struct socket *so, struct thread *td); +int pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam); int pru_rcvd_notsupp(struct socket *so, int flags); int pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags); +int pru_send_notsupp(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *addr, struct mbuf *control, struct thread *td); int pru_sense_null(struct socket *so, struct stat *sb); +int pru_shutdown_notsupp(struct socket *so); +int pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam); +int pru_sosend_notsupp(struct socket *so, struct sockaddr *addr, + struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, + struct thread *td); +int pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr, + struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, + int *flagsp); +int pru_sopoll_notsupp(struct socket *so, int events, struct ucred *cred, + struct thread *td); void pru_sosetlabel_null(struct socket *so); #endif /* _KERNEL */ @@ -319,6 +350,8 @@ void pfctlinput(int, struct sockaddr *); void pfctlinput2(int, struct sockaddr *, void *); struct protosw *pffindproto(int family, int protocol, int type); struct protosw *pffindtype(int family, int type); +int pf_proto_register(int family, struct protosw *npr); +int pf_proto_unregister(int family, int protocol, int type); #endif #endif