📄 in_pcb.c
字号:
}voidin_pcbdisconnect(inp) struct inpcb *inp;{ 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(inp) struct inpcb *inp;{ struct socket *so = inp->inp_socket; int s; so->so_pcb = 0; sofree(so); if (inp->inp_options) (void)m_free(inp->inp_options); if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt); ip_freemoptions(inp->inp_moptions, inp); s = splnet(); LIST_REMOVE(inp, inp_hash); LIST_REMOVE(inp, inp_list); splx(s); FREE(inp, MT_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; 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 splnet. */voidin_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) struct inpcbhead *head; struct sockaddr *dst; u_int fport_arg, lport_arg; struct in_addr laddr; int cmd; void (*notify) (struct inpcb *, int);{ register struct inpcb *inp, *oinp; struct in_addr faddr; u_short fport = fport_arg, lport = lport_arg; int errno, s; if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET) return; faddr = ((struct sockaddr_in *)dst)->sin_addr; if (faddr.s_addr == INADDR_ANY) return; /* * Redirects go to all references to the destination, * and use in_rtchange to invalidate the route cache. * Dead host indications: notify all references to the destination. * Otherwise, if we have knowledge of the local port and address, * deliver only to that socket. */ if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) { fport = 0; lport = 0; laddr.s_addr = 0; if (cmd != PRC_HOSTDEAD) notify = in_rtchange; } errno = inetctlerrmap[cmd]; s = splnet(); for (inp = head->lh_first; inp != NULL;) { if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_socket == 0 || (lport && inp->inp_lport != lport) || (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || (fport && inp->inp_fport != fport)) { inp = inp->inp_list.le_next; continue; } oinp = inp; inp = inp->inp_list.le_next; if (notify) (*notify)(oinp, errno); } splx(s);}/* * 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] = (struct sockaddr *)&inp->inp_route.ro_dst; info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); if (_rtMissMsgHook) (*_rtMissMsgHook) (RTM_LOSING, &info, rt->rt_flags, 0); if (rt->rt_flags & RTF_DYNAMIC) (void) rtrequestDelEqui(rt_key(rt),rt_mask(rt), rt->rt_gateway, rt->rt_flags, RT_PROTO_GET(rt_key(rt)), (ROUTE_ENTRY **)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, error) register struct inpcb *inp; int error;{ 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(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay) struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; int wild_okay;{ register struct inpcb *inp, *match = NULL; int matchwild = 3, wildcard; u_short fport = fport_arg, lport = lport_arg; int s; s = splnet(); for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { if (inp->inp_lport != lport) continue; wildcard = 0; 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++; } if (wildcard && wild_okay == 0) continue; if (wildcard < matchwild) { match = inp; matchwild = wildcard; if (matchwild == 0) { break; } } } splx(s); return (match);}/* * Lookup PCB in hash list. */struct inpcb *in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; int wildcard;{ struct inpcbhead *head; register struct inpcb *inp; u_short fport = fport_arg, lport = lport_arg; int s; s = splnet(); /* * First look for an exact match. */ head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; 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) goto found; } if (wildcard) { struct inpcb *local_wild = NULL; head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_fport == 0 && inp->inp_lport == lport) { if (inp->inp_laddr.s_addr == laddr.s_addr) goto found; else if (inp->inp_laddr.s_addr == INADDR_ANY) local_wild = inp; } } if (local_wild != NULL) { inp = local_wild; goto found; } } splx(s); return (NULL);found: /* * Move PCB to head of this hash chain so that it can be * found more quickly in the future. * XXX - this is a pessimization on machines with few * concurrent connections. */ if (inp != head->lh_first) { LIST_REMOVE(inp, inp_hash); LIST_INSERT_HEAD(head, inp, inp_hash); } splx(s); return (inp);}/* * Insert PCB into hash chain. Must be called at splnet. */voidin_pcbinshash(inp) struct inpcb *inp;{ struct inpcbhead *head; head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; LIST_INSERT_HEAD(head, inp, inp_hash);}voidin_pcbrehash(inp) struct inpcb *inp;{ struct inpcbhead *head; int s; s = splnet(); LIST_REMOVE(inp, inp_hash); head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; LIST_INSERT_HEAD(head, inp, inp_hash); splx(s);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -