?? in_pcb.c
字號:
if (ia == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_ERROR, 16, 8, WV_NETEVENT_PCBLADDR_BADIF, inp->inp_socket->so_fd)#endif /* INCLUDE_WVNET */#endif return (EADDRNOTAVAIL); } } } /* * Don't do pcblookup call here; return interface in plocal_sin * and exit to caller, that will do the lookup. */ *plocal_sin = &ia->ia_addr; } return(0);}/* * Outer subroutine: * Connect from a socket to a specified address. * Both address and port must be specified in argument sin. * If don't have a local address for this socket yet, * then pick one. */intin_pcbconnect(inp, nam) register struct inpcb *inp; struct mbuf *nam;{ struct sockaddr_in *ifaddr; register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); int error;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_VERBOSE, 24, 12, WV_NETEVENT_PCBCONNECT_START, inp->inp_socket->so_fd)#endif /* INCLUDE_WVNET */#endif /* * Call inner routine, to assign local interface address. */ if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0) return(error); if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, ((inp->inp_laddr.s_addr) ? inp->inp_laddr : ifaddr->sin_addr), inp->inp_lport, 0) != NULL) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_MARKER_4 (NET_AUX_EVENT, WV_NET_ERROR, 17, 9, WV_NETEVENT_PCBCONNECT_BADADDR, inp->inp_socket->so_fd, sin->sin_addr.s_addr, inp->inp_laddr.s_addr, inp->inp_lport);#endif /* INCLUDE_WVNET */#endif return (EADDRINUSE); } if (inp->inp_laddr.s_addr == INADDR_ANY) { if (inp->inp_lport == 0) (void)in_pcbbind(inp, (struct mbuf *)0); inp->inp_laddr = ifaddr->sin_addr; } inp->inp_faddr = sin->sin_addr; inp->inp_fport = sin->sin_port; in_pcbrehash(inp); return (0);}voidin_pcbdisconnect(inp) struct inpcb *inp;{#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_VERBOSE, 25, 13, WV_NETEVENT_PCBDISCONN_START, inp->inp_socket->so_fd)#endif /* INCLUDE_WVNET */#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(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;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_VERBOSE event */ WV_NET_MARKER_3 (NET_AUX_EVENT, WV_NET_VERBOSE, 26, 14, WV_NETEVENT_PCBNOTIFY_START, cmd, laddr.s_addr, ((struct sockaddr_in *)dst)->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif 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;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_WARNING event */ WV_NET_MARKER_0 (NET_CORE_EVENT, WV_NET_WARNING, 7, 10, WV_NETEVENT_TCPTIMER_ROUTEDROP)#endif /* INCLUDE_WVNET */#endif 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); /* * Remove the route if appropriate. Do not report the change * since the preceding hook generates both types of messages. */ if (rt->rt_flags & RTF_DYNAMIC) rtrequestDelEqui (rt_key(rt),rt_mask(rt), rt->rt_gateway, rt->rt_flags, RT_PROTO_GET(rt_key(rt)), FALSE, FALSE, (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 + -