int sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) { int len, rc; struct domain *dom; if (sa1->sa_family != sa2->sa_family) return sa1->sa_family - sa2->sa_family; dom = pffinddomain(sa1->sa_family); if (dom != NULL && dom->dom_sockaddr_cmp != NULL) return (*dom->dom_sockaddr_cmp)(sa1, sa2); len = MIN(sa1->sa_len, sa2->sa_len); if (dom == NULL || dom->dom_sa_cmplen == 0) { if ((rc = memcmp(sa1, sa2, len)) != 0) return rc; return sa1->sa_len - sa2->sa_len; } if ((rc = memcmp((const char *)sa1 + dom->dom_sa_cmpofs, (const char *)sa2 + dom->dom_sa_cmpofs, MIN(dom->dom_sa_cmplen, len - MIN(len, dom->dom_sa_cmpofs)))) != 0) return rc; return MIN(dom->dom_sa_cmplen + dom->dom_sa_cmpofs, sa1->sa_len) - MIN(dom->dom_sa_cmplen + dom->dom_sa_cmpofs, sa2->sa_len); }
struct protosw * pffindproto(int family, int protocol, int type) { struct domain *dp; struct protosw *pr; struct protosw *maybe; maybe = NULL; if (family == 0) return (NULL); dp = pffinddomain(family); if (dp == NULL) return (NULL); for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) return (pr); if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && pr->pr_protocol == 0 && maybe == NULL) maybe = pr; } return (maybe); }
const struct sockaddr * sockaddr_any_by_family(int family) { const struct domain *dom; if ((dom = pffinddomain(family)) == NULL) return NULL; return dom->dom_sa_any; }
int net_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, struct proc *p) { struct domain *dp; struct protosw *pr; int family, protocol; /* * All sysctl names at this level are nonterminal. * Usually: next two components are protocol family and protocol * number, then at least one addition component. */ if (namelen < 2) return (EISDIR); /* overloaded */ family = name[0]; if (family == 0) return (0); #if NBPFILTER > 0 if (family == PF_BPF) return (bpf_sysctl(name + 1, namelen - 1, oldp, oldlenp, newp, newlen)); #endif #if NPFLOW > 0 if (family == PF_PFLOW) return (pflow_sysctl(name + 1, namelen - 1, oldp, oldlenp, newp, newlen)); #endif #ifdef PIPEX if (family == PF_PIPEX) return (pipex_sysctl(name + 1, namelen - 1, oldp, oldlenp, newp, newlen)); #endif dp = pffinddomain(family); if (dp == NULL) return (ENOPROTOOPT); #ifdef MPLS /* XXX WARNING: big fat ugly hack */ /* stupid net.mpls is special as it does not have a protocol */ if (family == PF_MPLS) return (dp->dom_protosw[0].pr_sysctl(name + 1, namelen - 1, oldp, oldlenp, newp, newlen)); #endif if (namelen < 3) return (EISDIR); /* overloaded */ protocol = name[1]; for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) if (pr->pr_protocol == protocol && pr->pr_sysctl) return ((*pr->pr_sysctl)(name + 2, namelen - 2, oldp, oldlenp, newp, newlen)); return (ENOPROTOOPT); }
const void * sockaddr_const_addr(const struct sockaddr *sa, socklen_t *slenp) { const struct domain *dom; if ((dom = pffinddomain(sa->sa_family)) == NULL || dom->dom_sockaddr_const_addr == NULL) return NULL; return (*dom->dom_sockaddr_const_addr)(sa, slenp); }
struct sockaddr * sockaddr_externalize(struct sockaddr *dst, socklen_t socklen, const struct sockaddr *src) { struct domain *dom; dom = pffinddomain(src->sa_family); if (dom != NULL && dom->dom_sockaddr_externalize != NULL) return (*dom->dom_sockaddr_externalize)(dst, socklen, src); return sockaddr_copy(dst, socklen, src); }
struct protosw * pffindtype(int family, int type) { struct domain *dp; struct protosw *pr; dp = pffinddomain(family); if (dp == NULL) return (NULL); for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) if (pr->pr_type && pr->pr_type == type) return (pr); return (NULL); }
/* * 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(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. */ dp = pffinddomain(family); if (dp == NULL) return (EPFNOSUPPORT); dpr = NULL; /* Lock out everyone else while we are manipulating the protosw. */ mtx_lock(&dom_mtx); /* 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) { mtx_unlock(&dom_mtx); return (EMLINK); /* Should not happen! */ } else dpr = pr; } } /* Protocol does not exist. */ if (dpr == NULL) { mtx_unlock(&dom_mtx); 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_init = NULL; dpr->pr_fasttimo = NULL; dpr->pr_slowtimo = NULL; dpr->pr_drain = NULL; dpr->pr_usrreqs = &nousrreqs; /* Job is done, not more protection required. */ mtx_unlock(&dom_mtx); return (0); }
/* * 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(int family, struct protosw *npr) { VNET_ITERATOR_DECL(vnet_iter); 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. */ dp = pffinddomain(family); if (dp == NULL) return (EPFNOSUPPORT); /* Initialize backpointer to struct domain. */ npr->pr_domain = dp; fpr = NULL; /* * Protect us against races when two protocol registrations for * the same protocol happen at the same time. */ mtx_lock(&dom_mtx); /* 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)) { mtx_unlock(&dom_mtx); 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) { mtx_unlock(&dom_mtx); return (ENOMEM); } /* Copy the new struct protosw over the spacer. */ bcopy(npr, fpr, sizeof(*fpr)); /* Job is done, no more protection required. */ mtx_unlock(&dom_mtx); /* Initialize and activate the protocol. */ VNET_LIST_RLOCK(); VNET_FOREACH(vnet_iter) { CURVNET_SET_QUIET(vnet_iter); protosw_init(fpr); CURVNET_RESTORE(); } VNET_LIST_RUNLOCK(); return (0); }