diff options
Diffstat (limited to 'sys/netinet/in_pcb.c')
-rw-r--r-- | sys/netinet/in_pcb.c | 140 |
1 files changed, 108 insertions, 32 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 7f957b93a28..1bb338ddff4 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,5 @@ -/* $NetBSD: in_pcb.c,v 1.23 1995/08/17 02:57:27 mycroft Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.2 1996/03/03 22:30:31 niklas Exp $ */ +/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1991, 1993 @@ -59,21 +60,28 @@ struct in_addr zeroin_addr; +#define INPCBHASH(table, faddr, fport, laddr, lport) \ + &(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + ntohs((fport)) + ntohs((lport))) & (table->inpt_hash)] + void -in_pcbinit(table) +in_pcbinit(table, hashsize) struct inpcbtable *table; + int hashsize; { CIRCLEQ_INIT(&table->inpt_queue); + table->inpt_hashtbl = hashinit(hashsize, M_PCB, &table->inpt_hash); table->inpt_lastport = 0; } int -in_pcballoc(so, table) +in_pcballoc(so, v) struct socket *so; - struct inpcbtable *table; + void *v; { + struct inpcbtable *table = v; register struct inpcb *inp; + int s; MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK); if (inp == NULL) @@ -81,16 +89,21 @@ in_pcballoc(so, table) bzero((caddr_t)inp, sizeof(*inp)); inp->inp_table = table; inp->inp_socket = so; + s = splnet(); CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue); + LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr, inp->inp_fport, + &inp->inp_laddr, inp->inp_lport), inp, inp_hash); + splx(s); so->so_pcb = inp; return (0); } int -in_pcbbind(inp, nam) - register struct inpcb *inp; +in_pcbbind(v, nam) + register void *v; struct mbuf *nam; { + register struct inpcb *inp = v; register struct socket *so = inp->inp_socket; register struct inpcbtable *table = inp->inp_table; register struct sockaddr_in *sin; @@ -158,6 +171,7 @@ in_pcbbind(inp, nam) } while (in_pcblookup(table, zeroin_addr, 0, inp->inp_laddr, lport, wild)); inp->inp_lport = lport; + in_pcbrehash(inp); return (0); } @@ -168,12 +182,13 @@ in_pcbbind(inp, nam) * then pick one. */ int -in_pcbconnect(inp, nam) - register struct inpcb *inp; +in_pcbconnect(v, nam) + register void *v; struct mbuf *nam; { + register struct inpcb *inp = v; struct in_ifaddr *ia; - struct sockaddr_in *ifaddr; + struct sockaddr_in *ifaddr = NULL; register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof (*sin)) @@ -265,12 +280,9 @@ in_pcbconnect(inp, nam) } ifaddr = satosin(&ia->ia_addr); } - if (in_pcblookup(inp->inp_table, - sin->sin_addr, - sin->sin_port, + if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port, inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, - inp->inp_lport, - 0)) + inp->inp_lport) != 0) return (EADDRINUSE); if (inp->inp_laddr.s_addr == INADDR_ANY) { if (inp->inp_lport == 0) @@ -279,25 +291,30 @@ in_pcbconnect(inp, nam) } inp->inp_faddr = sin->sin_addr; inp->inp_fport = sin->sin_port; + in_pcbrehash(inp); return (0); } -int -in_pcbdisconnect(inp) - struct inpcb *inp; +void +in_pcbdisconnect(v) + void *v; { + struct inpcb *inp = v; inp->inp_faddr.s_addr = INADDR_ANY; inp->inp_fport = 0; + in_pcbrehash(inp); if (inp->inp_socket->so_state & SS_NOFDREF) in_pcbdetach(inp); } -int -in_pcbdetach(inp) - struct inpcb *inp; +void +in_pcbdetach(v) + void *v; { + struct inpcb *inp = v; struct socket *so = inp->inp_socket; + int s; so->so_pcb = 0; sofree(so); @@ -306,11 +323,14 @@ in_pcbdetach(inp) if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt); ip_freemoptions(inp->inp_moptions); + s = splnet(); + LIST_REMOVE(inp, inp_hash); CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue); + splx(s); FREE(inp, M_PCB); } -int +void in_setsockaddr(inp, nam) register struct inpcb *inp; struct mbuf *nam; @@ -326,7 +346,7 @@ in_setsockaddr(inp, nam) sin->sin_addr = inp->inp_laddr; } -int +void in_setpeeraddr(inp, nam) struct inpcb *inp; struct mbuf *nam; @@ -425,7 +445,7 @@ in_pcbnotifyall(table, dst, errno, notify) * routing information. If the route was created dynamically * (by a redirect), time to try a default gateway again. */ -int +void in_losing(inp) struct inpcb *inp; { @@ -488,15 +508,6 @@ in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags) if (inp->inp_lport != lport) continue; wildcard = 0; - if (inp->inp_laddr.s_addr != INADDR_ANY) { - if (laddr.s_addr == INADDR_ANY) - wildcard++; - else if (inp->inp_laddr.s_addr != laddr.s_addr) - continue; - } else { - if (laddr.s_addr != INADDR_ANY) - wildcard++; - } if (inp->inp_faddr.s_addr != INADDR_ANY) { if (faddr.s_addr == INADDR_ANY) wildcard++; @@ -507,6 +518,15 @@ in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags) if (faddr.s_addr != INADDR_ANY) wildcard++; } + if (inp->inp_laddr.s_addr != INADDR_ANY) { + if (laddr.s_addr == INADDR_ANY) + wildcard++; + else if (inp->inp_laddr.s_addr != laddr.s_addr) + continue; + } else { + if (laddr.s_addr != INADDR_ANY) + wildcard++; + } if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) continue; if (wildcard < matchwild) { @@ -518,3 +538,59 @@ in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags) } return (match); } + +void +in_pcbrehash(inp) + struct inpcb *inp; +{ + struct inpcbtable *table = inp->inp_table; + int s; + + s = splnet(); + LIST_REMOVE(inp, inp_hash); + LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr, inp->inp_fport, + &inp->inp_laddr, inp->inp_lport), inp, inp_hash); + splx(s); +} + +#ifdef DIAGNOSTIC +int in_pcbnotifymiss = 0; +#endif + +struct inpcb * +in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg) + struct inpcbtable *table; + struct in_addr faddr, laddr; + u_int fport_arg, lport_arg; +{ + struct inpcbhead *head; + register struct inpcb *inp; + u_int16_t fport = fport_arg, lport = lport_arg; + + head = INPCBHASH(table, &faddr, fport, &laddr, lport); + for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { + if (inp->inp_faddr.s_addr == faddr.s_addr && + inp->inp_fport == fport && + inp->inp_lport == lport && + inp->inp_laddr.s_addr == laddr.s_addr) { + /* + * Move this PCB to the head of hash chain so that + * repeated accesses are quicker. This is analogous to + * the historic single-entry PCB cache. + */ + if (inp != head->lh_first) { + LIST_REMOVE(inp, inp_hash); + LIST_INSERT_HEAD(head, inp, inp_hash); + } + break; + } + } +#ifdef DIAGNOSTIC + if (inp == NULL && in_pcbnotifymiss) { + printf("in_pcbhashlookup: faddr=%08x fport=%d laddr=%08x lport=%d\n", + ntohl(faddr.s_addr), ntohs(fport), + ntohl(laddr.s_addr), ntohs(lport)); + } +#endif + return (inp); +} |