/* * Allocate a control block and a nominal amount of buffer space for the * socket. */ int raw_attach(struct socket *so, int proto) { struct rawcb *rp = sotorawcb(so); int error; /* * It is assumed that raw_attach is called after space has been * allocated for the rawcb; consumer protocols may simply allocate * type struct rawcb, or a wrapper data structure that begins with a * struct rawcb. */ KASSERT(rp != NULL, ("raw_attach: rp == NULL")); error = soreserve(so, raw_sendspace, raw_recvspace); if (error) return (error); rp->rcb_socket = so; rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family; rp->rcb_proto.sp_protocol = proto; mtx_lock(&rawcb_mtx); LIST_INSERT_HEAD(&V_rawcb_list, rp, list); mtx_unlock(&rawcb_mtx); return (0); }
/* * key_detach() * derived from net/rtsock.c:rts_detach() */ static int key_detach(struct socket *so) { struct keycb *kp = (struct keycb *)sotorawcb(so); struct mbuf *n; int s, error; s = splnet(); if (kp != 0) { if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) key_cb.key_count--; key_cb.any_count--; key_freereg(so); while (kp->kp_queue) { n = kp->kp_queue->m_nextpkt; kp->kp_queue->m_nextpkt = NULL; m_freem(kp->kp_queue); kp->kp_queue = n; } } error = raw_usrreqs.pru_detach(so); splx(s); return error; }
/* * key_attach() * derived from net/rtsock.c:rts_attach() */ static int key_attach(struct socket *so, int proto, struct thread *p) { struct keycb *kp; int s, error; if (sotorawcb(so) != 0) return EISCONN; /* XXX panic? */ kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK); /* XXX */ if (kp == 0) return ENOBUFS; bzero(kp, sizeof *kp); /* * The splnet() is necessary to block protocols from sending * error notifications (like RTM_REDIRECT or RTM_LOSING) while * this PCB is extant but incompletely initialized. * Probably we should try to do more of this work beforehand and * eliminate the spl. */ s = splnet(); so->so_pcb = (caddr_t)kp; error = raw_usrreqs.pru_attach(so, proto, p); kp = (struct keycb *)sotorawcb(so); if (error) { free(kp, M_PCB); so->so_pcb = (caddr_t) 0; splx(s); return error; } kp->kp_promisc = kp->kp_registered = 0; if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */ key_cb.key_count++; key_cb.any_count++; kp->kp_raw.rcb_laddr = &key_src; kp->kp_raw.rcb_faddr = &key_dst; soisconnected(so); so->so_options |= SO_USELOOPBACK; splx(s); return 0; }
int raw_bind(struct socket *so, struct mbuf *nam) { struct sockaddr *addr = mtod(nam, struct sockaddr *); register struct rawcb *rp; if (ifnet == 0) return (EADDRNOTAVAIL); rp = sotorawcb(so); nam = m_copym(nam, 0, M_COPYALL, M_TRYWAIT); rp->rcb_laddr = mtod(nam, struct sockaddr *); return (0); }
int raw_bind(struct socket *so, struct mbuf *nam) { struct sockaddr *addr = mtod(nam, struct sockaddr *); struct rawcb *rp; if (ifnet == 0) return (EADDRNOTAVAIL); rp = sotorawcb(so); nam = m_copym(nam, 0, M_COPYALL, M_WAITOK); if (nam == NULL) return ENOBUFS; rp->rcb_laddr = mtod(nam, struct sockaddr *); return (0); }
key_receive(struct socket *so, struct mbuf **paddr, struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp) #endif { struct rawcb *rp = sotorawcb(so); struct keycb *kp = (struct keycb *)rp; int error; #ifndef __FreeBSD__ error = (*kp->kp_receive)(so, paddr, uio, mp0, controlp, flagsp); #else error = soreceive(so, paddr, uio, mp0, controlp, flagsp); #endif if (kp->kp_queue && sbspace(&rp->rcb_socket->so_rcv) > kp->kp_queue->m_pkthdr.len) sorwakeup(so); return error; }
/* * Allocate a control block and a nominal amount * of buffer space for the socket. */ int raw_attach(struct socket *so, int proto) { struct rawcb *rp = sotorawcb(so); int error; /* * It is assumed that raw_attach is called * after space has been allocated for the * rawcb. */ if (rp == 0) return (ENOBUFS); if ((error = soreserve(so, raw_sendspace, raw_recvspace)) != 0) return (error); rp->rcb_socket = so; rp->rcb_proto.sp_family = so->so_proto->pr_domain->dom_family; rp->rcb_proto.sp_protocol = proto; LIST_INSERT_HEAD(&rawcb, rp, rcb_list); return (0); }
/* so can be NULL if target != KEY_SENDUP_ONE */ int key_sendup_mbuf(struct socket *so, struct mbuf *m, int target) { struct mbuf *n; struct keycb *kp; int sendup; struct rawcb *rp; int error = 0; int canwait; if (m == NULL) panic("key_sendup_mbuf: NULL pointer was passed."); if (so == NULL && target == KEY_SENDUP_ONE) panic("key_sendup_mbuf: NULL pointer was passed."); canwait = target & KEY_SENDUP_CANWAIT; target &= ~KEY_SENDUP_CANWAIT; pfkeystat.in_total++; pfkeystat.in_bytes += m->m_pkthdr.len; if (m->m_len < sizeof(struct sadb_msg)) { m = m_pullup(m, sizeof(struct sadb_msg)); if (m == NULL) { pfkeystat.in_nomem++; return ENOBUFS; } } if (m->m_len >= sizeof(struct sadb_msg)) { struct sadb_msg *msg; msg = mtod(m, struct sadb_msg *); pfkeystat.in_msgtype[msg->sadb_msg_type]++; } #ifdef __NetBSD__ for (rp = rawcb.lh_first; rp; rp = rp->rcb_list.le_next) #elif defined(__FreeBSD__) LIST_FOREACH(rp, &rawcb_list, list) #else for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) #endif { if (rp->rcb_proto.sp_family != PF_KEY) continue; if (rp->rcb_proto.sp_protocol && rp->rcb_proto.sp_protocol != PF_KEY_V2) { continue; } kp = (struct keycb *)rp; /* * If you are in promiscuous mode, and when you get broadcasted * reply, you'll get two PF_KEY messages. * (based on [email protected] message on 14 Oct 1998) */ if (((struct keycb *)rp)->kp_promisc) { if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { (void)key_sendup0(rp, n, 1, canwait); n = NULL; } } /* the exact target will be processed later */ if (so && sotorawcb(so) == rp) continue; sendup = 0; switch (target) { case KEY_SENDUP_ONE: /* the statement has no effect */ if (so && sotorawcb(so) == rp) sendup++; break; case KEY_SENDUP_ALL: sendup++; break; case KEY_SENDUP_REGISTERED: if (kp->kp_registered) sendup++; break; } pfkeystat.in_msgtarget[target]++; if (!sendup) continue; if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) { m_freem(m); pfkeystat.in_nomem++; return ENOBUFS; } /* * ignore error even if queue is full. PF_KEY does not * guarantee the delivery of the message. * this is important when target == KEY_SENDUP_ALL. */ key_sendup0(rp, n, 0, canwait); n = NULL; } if (so) { error = key_sendup0(sotorawcb(so), m, 0, canwait); m = NULL; } else { error = 0; m_freem(m); } return error; }
key_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control, struct proc *p) #endif /*__NetBSD__*/ { int error = 0; struct keycb *kp = (struct keycb *)sotorawcb(so); int s; #ifdef __NetBSD__ s = splsoftnet(); #else s = splnet(); #endif if (req == PRU_ATTACH) { kp = (struct keycb *)malloc(sizeof(*kp), M_PCB, M_WAITOK); so->so_pcb = (caddr_t)kp; if (so->so_pcb) bzero(so->so_pcb, sizeof(*kp)); } if (req == PRU_DETACH && kp) { int af = kp->kp_raw.rcb_proto.sp_protocol; struct mbuf *n; if (af == PF_KEY) key_cb.key_count--; key_cb.any_count--; key_freereg(so); while (kp->kp_queue) { n = kp->kp_queue->m_nextpkt; kp->kp_queue->m_nextpkt = NULL; m_freem(kp->kp_queue); kp->kp_queue = n; } } #ifndef __NetBSD__ error = raw_usrreq(so, req, m, nam, control); #else error = raw_usrreq(so, req, m, nam, control, p); #endif m = control = NULL; /* reclaimed in raw_usrreq */ kp = (struct keycb *)sotorawcb(so); if (req == PRU_ATTACH && kp) { int af = kp->kp_raw.rcb_proto.sp_protocol; if (error) { pfkeystat.sockerr++; free((caddr_t)kp, M_PCB); so->so_pcb = (caddr_t) 0; splx(s); return (error); } kp->kp_promisc = kp->kp_registered = 0; kp->kp_receive = so->so_receive; so->so_receive = key_receive; if (af == PF_KEY) /* XXX: AF_KEY */ key_cb.key_count++; key_cb.any_count++; kp->kp_raw.rcb_laddr = &key_src; kp->kp_raw.rcb_faddr = &key_dst; soisconnected(so); so->so_options |= SO_USELOOPBACK; } splx(s); return (error); }
int raw_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control) { register struct rawcb *rp = sotorawcb(so); register int error = 0; int len; if (req == PRU_CONTROL) return (EOPNOTSUPP); if (control && control->m_len) { error = EOPNOTSUPP; goto release; } if (rp == 0) { error = EINVAL; goto release; } switch (req) { /* * Allocate a raw control block and fill in the * necessary info to allow packets to be routed to * the appropriate raw interface routine. */ case PRU_ATTACH: if ((so->so_state & SS_PRIV) == 0) { error = EACCES; break; } error = raw_attach(so, (int)nam); break; /* * Destroy state just before socket deallocation. * Flush data or not depending on the options. */ case PRU_DETACH: if (rp == 0) { error = ENOTCONN; break; } raw_detach(rp); break; #ifdef notdef /* * If a socket isn't bound to a single address, * the raw input routine will hand it anything * within that protocol family (assuming there's * nothing else around it should go to). */ case PRU_CONNECT: if (rp->rcb_faddr) { error = EISCONN; break; } nam = m_copym(nam, 0, M_COPYALL, M_WAIT); rp->rcb_faddr = mtod(nam, struct sockaddr *); soisconnected(so); break; case PRU_BIND: if (rp->rcb_laddr) { error = EINVAL; /* XXX */ break; } error = raw_bind(so, nam); break; #endif case PRU_CONNECT2: error = EOPNOTSUPP; goto release; case PRU_DISCONNECT: if (rp->rcb_faddr == 0) { error = ENOTCONN; break; } raw_disconnect(rp); soisdisconnected(so); break; /* * Mark the connection as being incapable of further input. */ case PRU_SHUTDOWN: socantsendmore(so); break; /* * Ship a packet out. The appropriate raw output * routine handles any massaging necessary. */ case PRU_SEND: if (nam) { if (rp->rcb_faddr) { error = EISCONN; break; } rp->rcb_faddr = mtod(nam, struct sockaddr *); } else if (rp->rcb_faddr == 0) { error = ENOTCONN; break; } error = (*so->so_proto->pr_output)(m, so); m = NULL; if (nam) rp->rcb_faddr = 0; break; case PRU_ABORT: raw_disconnect(rp); sofree(so); soisdisconnected(so); break; case PRU_SENSE: /* * stat: don't bother with a blocksize. */ return (0); /* * Not supported. */ case PRU_RCVOOB: case PRU_RCVD: return(EOPNOTSUPP); case PRU_LISTEN: case PRU_ACCEPT: case PRU_SENDOOB: error = EOPNOTSUPP; break; case PRU_SOCKADDR: if (rp->rcb_laddr == 0) { error = EINVAL; break; } len = rp->rcb_laddr->sa_len; aligned_bcopy((caddr_t)rp->rcb_laddr, mtod(nam, caddr_t), (unsigned)len); nam->m_len = len; break; case PRU_PEERADDR: if (rp->rcb_faddr == 0) { error = ENOTCONN; break; } len = rp->rcb_faddr->sa_len; aligned_bcopy((caddr_t)rp->rcb_faddr, mtod(nam, caddr_t), (unsigned)len); nam->m_len = len; break; default: panic("raw_usrreq"); }