*** /tmp/,RCSt1a05559 Wed Jun 1 14:23:02 1994 --- in_pcb.c Wed Jun 1 14:21:02 1994 *************** *** 1,5 **** - /* BSDI $Id: in_pcb.c,v 1.4 1993/12/18 20:51:35 karels Exp $ */ - /* * Copyright (c) 1982, 1986, 1991 Regents of the University of California. * All rights reserved. --- 1,3 ---- *************** *** 53,59 **** --- 51,59 ---- #include "ip.h" #include "in_pcb.h" #include "in_var.h" + #ifdef MULTICAST #include "ip_var.h" + #endif struct in_addr zeroin_addr; *************** *** 75,90 **** return (0); } in_pcbbind(inp, nam) register struct inpcb *inp; struct mbuf *nam; { - register struct socket *so = inp->inp_socket; register struct inpcb *head = inp->inp_head; ! register struct sockaddr_in *sin; ! struct proc *p = curproc; /* XXX */ ! u_short lport = 0; ! int wild = 0; if (in_ifaddr == 0) return (EADDRNOTAVAIL); --- 75,134 ---- return (0); } + /* + * return 1 if there's a pcb whose addresses 'confict' with the + * supplied addresses. Only exact matches (address with address + * or wildcard with wildcard) are considered to be in conflict + * since in_pcblookup will resolve anything else via 'best match'. + */ + int + in_pcbconflict(head, faddr, laddr, fport, lport) + register struct inpcb *head; + register u_long faddr, laddr; + register u_short fport, lport; + { + register struct inpcb *inp = head; + + while ((inp = inp->inp_next) != head) + if (inp->inp_lport == lport && + (fport == 0 || inp->inp_fport == fport) && + (faddr == 0 || inp->inp_faddr.s_addr == faddr) && + (laddr == 0 || inp->inp_laddr.s_addr == laddr)) + return (1); + return (0); + } + + /* + * Chose a unique (non-conflicting) local port for the inpcb list + * starting at 'head'. (A 'rover' is kept in the lport field of + * the list head to make N calls to this routine O(N^2) instead of + * O(N^3)). The port will always be + * IPPORT_RESERVED <= lport <= IPPORT_USERRESERVED + */ + u_short + in_uniqueport(head, faddr, laddr, fport) + register struct inpcb *head; + register u_long faddr, laddr; + register u_short fport; + { + register u_short lport = head->inp_lport; + + do { + ++lport; + if (lport < IPPORT_RESERVED || lport > IPPORT_USERRESERVED) + lport = IPPORT_RESERVED; + } while (in_pcbconflict(head, faddr, laddr, fport, htons(lport))); + head->inp_lport = lport; + return (htons(lport)); + } + in_pcbbind(inp, nam) register struct inpcb *inp; struct mbuf *nam; { register struct inpcb *head = inp->inp_head; ! register u_long laddr = 0; ! register u_short lport = 0; if (in_ifaddr == 0) return (EADDRNOTAVAIL); *************** *** 91,135 **** if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) return (EINVAL); ! if ((so->so_options & SO_REUSEADDR) == 0 && ! ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || ! (so->so_options & SO_ACCEPTCONN) == 0)) ! wild = INPLOOKUP_WILDCARD; ! if (nam == 0) ! goto noname; ! sin = mtod(nam, struct sockaddr_in *); ! if (nam->m_len != sizeof (*sin)) ! return (EINVAL); ! if (sin->sin_addr.s_addr != INADDR_ANY) { ! int tport = sin->sin_port; ! ! sin->sin_port = 0; /* yech... */ ! if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) ! return (EADDRNOTAVAIL); ! sin->sin_port = tport; } - lport = sin->sin_port; - if (lport) { - u_short aport = ntohs(lport); - - /* GROSS */ - if (aport < IPPORT_RESERVED && suser(p->p_ucred, &p->p_acflag)) - return (EACCES); - if (in_pcblookup(head, - zeroin_addr, 0, sin->sin_addr, lport, wild)) - return (EADDRINUSE); - } - inp->inp_laddr = sin->sin_addr; - noname: if (lport == 0) ! do { ! if (head->inp_lport++ < IPPORT_RESERVED || ! head->inp_lport > IPPORT_USERRESERVED) ! head->inp_lport = IPPORT_RESERVED; ! lport = htons(head->inp_lport); ! } while (in_pcblookup(head, ! zeroin_addr, 0, inp->inp_laddr, lport, wild)); inp->inp_lport = lport; return (0); } --- 135,164 ---- if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) return (EINVAL); ! if (nam) { ! struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); ! if (nam->m_len != sizeof (*sin)) ! return (EINVAL); ! ! laddr = sin->sin_addr.s_addr; ! lport = sin->sin_port; ! if (lport) { ! struct proc *p = curproc; /* XXX */ ! /* GROSS */ ! if (ntohs(lport) < IPPORT_RESERVED && ! suser(p->p_ucred, &p->p_acflag)) ! return (EACCES); ! if ((inp->inp_socket->so_options & SO_REUSEADDR) == 0 && ! in_pcbconflict(head, 0, laddr, 0, lport)) ! return (EADDRINUSE); ! } } if (lport == 0) ! lport = in_uniqueport(head, inp->inp_faddr.s_addr, laddr, ! inp->inp_fport); ! ! inp->inp_laddr.s_addr = laddr; inp->inp_lport = lport; return (0); } *************** *** 144,159 **** register struct inpcb *inp; struct mbuf *nam; { - struct in_ifaddr *ia; - struct sockaddr_in *ifaddr; register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof (*sin)) return (EINVAL); if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); ! if (sin->sin_port == 0) return (EADDRNOTAVAIL); if (in_ifaddr) { /* * If the destination address is INADDR_ANY, --- 173,192 ---- register struct inpcb *inp; struct mbuf *nam; { register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); + register u_long faddr = sin->sin_addr.s_addr; + register u_short fport = sin->sin_port; + register u_long laddr; + register u_short lport; if (nam->m_len != sizeof (*sin)) return (EINVAL); if (sin->sin_family != AF_INET) return (EAFNOSUPPORT); ! #ifndef MULTICAST ! if (fport == 0) return (EADDRNOTAVAIL); + #endif if (in_ifaddr) { /* * If the destination address is INADDR_ANY, *************** *** 163,187 **** * choose the broadcast address for that interface. */ #define satosin(sa) ((struct sockaddr_in *)(sa)) ! if (sin->sin_addr.s_addr == INADDR_ANY) ! sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr; ! else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST && ! (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) ! sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr; } ! if (inp->inp_laddr.s_addr == INADDR_ANY) { ! register struct route *ro; struct ifnet *ifp; - ia = (struct in_ifaddr *)0; /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ - ro = &inp->inp_route; if (ro->ro_rt && ! (satosin(&ro->ro_dst)->sin_addr.s_addr != ! sin->sin_addr.s_addr || inp->inp_socket->so_options & SO_DONTROUTE)) { RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; --- 196,223 ---- * choose the broadcast address for that interface. */ #define satosin(sa) ((struct sockaddr_in *)(sa)) ! if (faddr == INADDR_ANY) { ! faddr = IA_SIN(in_ifaddr)->sin_addr.s_addr; ! sin->sin_addr.s_addr = faddr; ! } else if (faddr == (u_long)INADDR_BROADCAST && ! (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST)) { ! faddr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr.s_addr; ! sin->sin_addr.s_addr = faddr; ! } } ! laddr = inp->inp_laddr.s_addr; ! lport = inp->inp_lport; ! if (laddr == INADDR_ANY) { ! register struct route *ro = &inp->inp_route; ! struct in_ifaddr *ia = 0; struct ifnet *ifp; /* * If route is known or can be allocated now, * our src addr is taken from the i/f, else punt. */ if (ro->ro_rt && ! (satosin(&ro->ro_dst)->sin_addr.s_addr != faddr || inp->inp_socket->so_options & SO_DONTROUTE)) { RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; *************** *** 209,220 **** if (ia->ia_ifp == ifp) break; if (ia == 0) { - int fport = sin->sin_port; - sin->sin_port = 0; ia = (struct in_ifaddr *) ifa_ifwithdstaddr((struct sockaddr *)sin); - sin->sin_port = fport; if (ia == 0) ia = in_iaonnetof(in_netof(sin->sin_addr)); if (ia == 0) --- 245,253 ---- *************** *** 228,237 **** * interface has been set as a multicast option, use the * address of that interface as our source address. */ ! if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) && ! inp->inp_moptions != NULL) { struct ip_moptions *imo; - struct ifnet *ifp; imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { --- 261,268 ---- * interface has been set as a multicast option, use the * address of that interface as our source address. */ ! if (IN_MULTICAST(ntohl(faddr)) && inp->inp_moptions != NULL) { struct ip_moptions *imo; imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { *************** *** 244,265 **** } } #endif ! ifaddr = (struct sockaddr_in *)&ia->ia_addr; } ! if (in_pcblookup(inp->inp_head, ! 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) ! (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; return (0); } --- 275,292 ---- } } #endif ! laddr = satosin(&ia->ia_addr)->sin_addr.s_addr; ! if (lport == 0) ! lport = in_uniqueport(inp->inp_head,faddr,laddr,fport); } ! if (in_pcbconflict(inp->inp_head, faddr, laddr, fport, lport)) return (EADDRINUSE); ! ! inp->inp_faddr.s_addr = faddr; ! inp->inp_laddr.s_addr = laddr; ! inp->inp_fport = fport; ! inp->inp_lport = lport; ! return (0); } *************** *** 285,292 **** if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt); #ifdef MULTICAST ! if (inp->inp_moptions) ! ip_freemoptions(inp->inp_moptions); #endif remque(inp); (void) m_free(dtom(inp)); --- 312,318 ---- if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt); #ifdef MULTICAST ! ip_freemoptions(inp->inp_moptions); #endif remque(inp); (void) m_free(dtom(inp)); *************** *** 428,468 **** } } struct inpcb * ! in_pcblookup(head, faddr, fport, laddr, lport, flags) struct inpcb *head; ! struct in_addr faddr, laddr; ! u_short fport, lport; int flags; { register struct inpcb *inp, *match = 0; ! int matchwild = 3, wildcard; for (inp = head->inp_next; inp != head; inp = inp->inp_next) { 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++; ! else if (inp->inp_faddr.s_addr != faddr.s_addr || ! inp->inp_fport != fport) continue; ! } else { ! if (faddr.s_addr != INADDR_ANY) ! wildcard++; } ! if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) ! continue; if (wildcard < matchwild) { match = inp; matchwild = wildcard; --- 454,504 ---- } } + /* + * Find the 'best match' between the datagram address and the list of inpcb's starting at 'head'. + * This routine is *only* used by protocol input routines to locate + * the pcb associated with some datagram. (The unused 'flags' parameter + * is a carry-over from days when this routine was (mis-)used to do the + * job that in_pcbconflict does.) + * + * The rules for best match are: + * - the local port must match + * - the longest match (the fewest wildcards) is preferred + * for the other three fields. + * - if there are multiple best matches, the first is taken. + */ struct inpcb * ! in_pcblookup(head, infor, fport, inloc, lport, flags) struct inpcb *head; ! struct in_addr infor, inloc; ! register u_short fport, lport; int flags; { register struct inpcb *inp, *match = 0; ! register u_long faddr = infor.s_addr; ! register u_long laddr = inloc.s_addr; ! register int matchwild = 4, wildcard; for (inp = head->inp_next; inp != head; inp = inp->inp_next) { if (inp->inp_lport != lport) continue; wildcard = 0; ! if (inp->inp_laddr.s_addr != laddr) { ! if (inp->inp_laddr.s_addr != INADDR_ANY) continue; ! ++wildcard; } ! if (inp->inp_faddr.s_addr != faddr) { ! if (inp->inp_faddr.s_addr != INADDR_ANY) continue; ! ++wildcard; } ! if (inp->inp_fport != fport) { ! if (inp->inp_fport != INADDR_ANY) ! continue; ! ++wildcard; ! } if (wildcard < matchwild) { match = inp; matchwild = wildcard; *** /tmp/,RCSt1a05559 Wed Jun 1 14:23:02 1994 --- udp_usrreq.c Wed Jun 1 14:21:03 1994 *************** *** 394,400 **** goto release; } } else { ! if (inp->inp_faddr.s_addr == INADDR_ANY) { error = ENOTCONN; goto release; } --- 394,401 ---- goto release; } } else { ! if (inp->inp_faddr.s_addr == INADDR_ANY || ! inp->inp_fport == 0) { error = ENOTCONN; goto release; }