📄 in_pcb.c
字号:
if (ia->ia_ifp == ifp) break; if (ia == 0) return (EADDRNOTAVAIL); } } ifaddr = satosin(&ia->ia_addr); } 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) return (EADDRINUSE); if (inp->inp_laddr.s_addr == INADDR_ANY) { if (inp->inp_lport == 0 && in_pcbbind(inp, (struct mbuf *)0) == EADDRNOTAVAIL) return (EADDRNOTAVAIL); inp->inp_laddr = ifaddr->sin_addr; } inp->inp_faddr = sin->sin_addr; inp->inp_fport = sin->sin_port; in_pcbrehash(inp);#ifdef IPSEC return (check_ipsec_policy(inp, 0));#else return (0);#endif}voidin_pcbdisconnect(v) void *v;{ struct inpcb *inp = v;#ifdef INET6 if (sotopf(inp->inp_socket) == PF_INET6) { inp->inp_faddr6 = in6addr_any; /* Disconnected AF_INET6 sockets cannot be "v4-mapped" */ inp->inp_flags &= ~INP_IPV6_MAPPED; } else#endif 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);}voidin_pcbdetach(v) void *v;{ struct inpcb *inp = v; struct socket *so = inp->inp_socket; int s; so->so_pcb = 0; sofree(so); if (inp->inp_options) (void)m_freem(inp->inp_options); if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt);#ifdef NOTUSED_BY_PMON#ifdef INET6 if (inp->inp_flags & INP_IPV6_MCAST) ipv6_freemoptions(inp->inp_moptions6); else #endif /* INET6 */ ip_freemoptions(inp->inp_moptions);#endif /* NOTUSED_BY_PMON */#ifdef IPSEC /* XXX IPsec cleanup here */ s = spltdb(); if (inp->inp_tdb) TAILQ_REMOVE(&inp->inp_tdb->tdb_inp, inp, inp_tdb_next); splx(s);#endif s = splnet(); LIST_REMOVE(inp, inp_hash); CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue); splx(s); FREE(inp, M_PCB);}voidin_setsockaddr(inp, nam) register struct inpcb *inp; struct mbuf *nam;{ register struct sockaddr_in *sin; nam->m_len = sizeof (*sin); sin = mtod(nam, struct sockaddr_in *); bzero((caddr_t)sin, sizeof (*sin)); sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_port = inp->inp_lport; sin->sin_addr = inp->inp_laddr;}voidin_setpeeraddr(inp, nam) struct inpcb *inp; struct mbuf *nam;{ register struct sockaddr_in *sin; #ifdef INET6 if (sotopf(inp->inp_socket) == PF_INET6) in6_setpeeraddr(inp, nam);#endif /* INET6 */ nam->m_len = sizeof (*sin); sin = mtod(nam, struct sockaddr_in *); bzero((caddr_t)sin, sizeof (*sin)); sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_port = inp->inp_fport; sin->sin_addr = inp->inp_faddr;}/* * Pass some notification to all connections of a protocol * associated with address dst. The local address and/or port numbers * may be specified to limit the search. The "usual action" will be * taken, depending on the ctlinput cmd. The caller must filter any * cmds that are uninteresting (e.g., no error in the map). * Call the protocol specific routine (if any) to report * any errors for each matching socket. * * Must be called at splsoftnet. */voidin_pcbnotify(table, dst, fport_arg, laddr, lport_arg, errno, notify) struct inpcbtable *table; struct sockaddr *dst; u_int fport_arg, lport_arg; struct in_addr laddr; int errno; void (*notify) __P((struct inpcb *, int));{ register struct inpcb *inp, *oinp; struct in_addr faddr; u_int16_t fport = fport_arg, lport = lport_arg;#ifdef INET6 /* * See in6_pcbnotify() for IPv6 codepath. By the time this * gets called, the addresses passed are either definitely IPv4 or * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses. */#endif /* INET6 */ if (dst->sa_family != AF_INET) return; faddr = satosin(dst)->sin_addr; if (faddr.s_addr == INADDR_ANY) return; for (inp = table->inpt_queue.cqh_first; inp != (struct inpcb *)&table->inpt_queue;) { if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_socket == 0 || inp->inp_fport != fport || inp->inp_lport != lport || inp->inp_laddr.s_addr != laddr.s_addr) { inp = inp->inp_queue.cqe_next; continue; } oinp = inp; inp = inp->inp_queue.cqe_next; if (notify) (*notify)(oinp, errno); }}voidin_pcbnotifyall(table, dst, errno, notify) struct inpcbtable *table; struct sockaddr *dst; int errno; void (*notify) __P((struct inpcb *, int));{ register struct inpcb *inp, *oinp; struct in_addr faddr;#ifdef INET6 /* * See in6_pcbnotify() for IPv6 codepath. By the time this * gets called, the addresses passed are either definitely IPv4 or * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses. */#endif /* INET6 */ if (dst->sa_family != AF_INET) return; faddr = satosin(dst)->sin_addr; if (faddr.s_addr == INADDR_ANY) return; for (inp = table->inpt_queue.cqh_first; inp != (struct inpcb *)&table->inpt_queue;) { if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_socket == 0) { inp = inp->inp_queue.cqe_next; continue; } oinp = inp; inp = inp->inp_queue.cqe_next; if (notify) (*notify)(oinp, errno); }}/* * Check for alternatives when higher level complains * about service problems. For now, invalidate cached * routing information. If the route was created dynamically * (by a redirect), time to try a default gateway again. */voidin_losing(inp) struct inpcb *inp;{ register struct rtentry *rt; struct rt_addrinfo info; if ((rt = inp->inp_route.ro_rt)) { inp->inp_route.ro_rt = 0; bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst; info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0); if (rt->rt_flags & RTF_DYNAMIC) (void) rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, (struct rtentry **)0); else /* * A new route can be allocated * the next time output is attempted. */ rtfree(rt); }}/* * After a routing change, flush old routing * and allocate a (hopefully) better one. */voidin_rtchange(inp, errno) register struct inpcb *inp; int errno;{ if (inp->inp_route.ro_rt) { rtfree(inp->inp_route.ro_rt); inp->inp_route.ro_rt = 0; /* * A new route can be allocated the next time * output is attempted. */ }}struct inpcb *in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags) struct inpcbtable *table; void *faddrp, *laddrp; u_int fport_arg, lport_arg; int flags;{ register struct inpcb *inp, *match = 0; int matchwild = 3, wildcard; u_int16_t fport = fport_arg, lport = lport_arg; struct in_addr faddr = *(struct in_addr *)faddrp; struct in_addr laddr = *(struct in_addr *)laddrp; for (inp = table->inpt_queue.cqh_first; inp != (struct inpcb *)&table->inpt_queue; inp = inp->inp_queue.cqe_next) { if (inp->inp_lport != lport) continue; wildcard = 0;#ifdef INET6 if (flags & INPLOOKUP_IPV6) { struct in6_addr *laddr6 = (struct in6_addr *)laddrp; struct in6_addr *faddr6 = (struct in6_addr *)faddrp; /* * Always skip AF_INET sockets when looking for AF_INET6 * addresses. The only problem with this comes if the * PF_INET6 addresses are v4-mapped addresses. From what * I've been able to see, none of the callers cause such * a situation to occur. If such a situation DID occur, * then it is possible to miss a matching PCB. */ if (!(inp->inp_flags & INP_IPV6)) continue; if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) { if (IN6_IS_ADDR_UNSPECIFIED(laddr6)) wildcard++; else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6)) continue; } else { if (!IN6_IS_ADDR_UNSPECIFIED(laddr6)) wildcard++; } if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) { if (IN6_IS_ADDR_UNSPECIFIED(faddr6)) wildcard++; else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr6) || inp->inp_fport != fport) continue; } else { if (!IN6_IS_ADDR_UNSPECIFIED(faddr6)) wildcard++; } } else {#endif /* INET6 */ if (inp->inp_faddr.s_addr != INADDR_ANY) { if (faddr.s_addr == INADDR_ANY) wildcard++; else if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_fport != fport) continue; } else { 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++; }#ifdef INET6 }#endif /* INET6 */ if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) && wildcard < matchwild) { match = inp; if ((matchwild = wildcard) == 0) break; } } return (match);}voidin_pcbrehash(inp) struct inpcb *inp;{ struct inpcbtable *table = inp->inp_table; int s; s = splnet(); LIST_REMOVE(inp, inp_hash);#ifdef INET6 if (inp->inp_flags & INP_IPV6) { LIST_INSERT_HEAD(IN6PCBHASH(table, &inp->inp_faddr6, inp->inp_fport, &inp->inp_laddr6, inp->inp_lport), inp, inp_hash); } else {#endif /* INET6 */ LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr, inp->inp_fport, &inp->inp_laddr, inp->inp_lport), inp, inp_hash);#ifdef INET6 }#endif /* INET6 */ splx(s);}#ifdef DIAGNOSTICint in_pcbnotifymiss = 0;#endifstruct 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);}#ifdef INET6struct inpcb *in6_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg) struct inpcbtable *table; struct in6_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 = IN6PCBHASH(table, faddr, fport, laddr, lport); for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { if (!(inp->inp_flags & INP_IPV6)) continue; if (IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) && inp->inp_fport == fport && inp->inp_lport == lport && IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr)) { /* * 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("in6_pcblookup_connect: faddr="); printf(" fport=%d laddr=", ntohs(fport)); printf(" lport=%d\n", ntohs(lport)); }#endif return (inp);}#endif /* INET6 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -