+ register struct ifreq *ifr = (struct ifreq *)data;
+ register struct in_ifaddr *ia = 0;
+ u_long tmp;
+ struct ifaddr *ifa;
+ struct mbuf *m;
+ int error;
+
+ /*
+ * Find address for this interface, if it exists.
+ */
+ if (ifp)
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ case SIOCSIFNETMASK:
+ case SIOCSIFDSTADDR:
+ if (!suser())
+ return (u.u_error);
+
+ if (ifp == 0)
+ panic("in_control");
+ if (ia == (struct in_ifaddr *)0) {
+ m = m_getclr(M_WAIT, MT_IFADDR);
+ if (m == (struct mbuf *)NULL)
+ return (ENOBUFS);
+ if (ia = in_ifaddr) {
+ for ( ; ia->ia_next; ia = ia->ia_next)
+ ;
+ ia->ia_next = mtod(m, struct in_ifaddr *);
+ } else
+ in_ifaddr = mtod(m, struct in_ifaddr *);
+ ia = mtod(m, struct in_ifaddr *);
+ if (ifa = ifp->if_addrlist) {
+ for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
+ ;
+ ifa->ifa_next = (struct ifaddr *) ia;
+ } else
+ ifp->if_addrlist = (struct ifaddr *) ia;
+ ia->ia_ifp = ifp;
+ IA_SIN(ia)->sin_family = AF_INET;
+ if (ifp != &loif)
+ in_interfaces++;
+ }
+ break;
+
+ case SIOCSIFBRDADDR:
+ if (!suser())
+ return (u.u_error);
+ /* FALLTHROUGH */
+
+ default:
+ if (ia == (struct in_ifaddr *)0)
+ return (EADDRNOTAVAIL);
+ break;
+ }
+
+ switch (cmd) {
+
+ case SIOCGIFADDR:
+ ifr->ifr_addr = ia->ia_addr;
+ break;
+
+ case SIOCGIFBRDADDR:
+ if ((ifp->if_flags & IFF_BROADCAST) == 0)
+ return (EINVAL);
+ ifr->ifr_dstaddr = ia->ia_broadaddr;
+ break;
+
+ case SIOCGIFDSTADDR:
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ return (EINVAL);
+ ifr->ifr_dstaddr = ia->ia_dstaddr;
+ break;
+
+ case SIOCGIFNETMASK:
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ satosin(&ifr->ifr_addr)->sin_family = AF_INET;
+ satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
+ break;
+
+ case SIOCSIFDSTADDR:
+ {
+ struct sockaddr oldaddr;
+
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ return (EINVAL);
+ oldaddr = ia->ia_dstaddr;
+ ia->ia_dstaddr = ifr->ifr_dstaddr;
+ if (ifp->if_ioctl &&
+ (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
+ ia->ia_dstaddr = oldaddr;
+ return (error);
+ }
+ if (ia->ia_flags & IFA_ROUTE) {
+ rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
+ RTF_HOST);
+ rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
+ RTF_HOST|RTF_UP);
+ }
+ }
+ break;
+
+ case SIOCSIFBRDADDR:
+ if ((ifp->if_flags & IFF_BROADCAST) == 0)
+ return (EINVAL);
+ ia->ia_broadaddr = ifr->ifr_broadaddr;
+ tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
+ if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
+ tmp |= ~ia->ia_netmask;
+ else if ((tmp &~ ia->ia_subnetmask) == 0)
+ tmp &= ia->ia_netmask;
+ ia->ia_netbroadcast.s_addr = htonl(tmp);
+ break;
+
+ case SIOCSIFADDR:
+ return (in_ifinit(ifp, ia, &ifr->ifr_addr));
+
+ case SIOCSIFNETMASK:
+ ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
+ break;
+
+ default:
+ if (ifp == 0 || ifp->if_ioctl == 0)
+ return (EOPNOTSUPP);
+ return ((*ifp->if_ioctl)(ifp, cmd, data));
+ }
+ return (0);
+}
+
+/*
+ * Initialize an interface's internet address
+ * and routing table entry.
+ */
+in_ifinit(ifp, ia, sin)
+ register struct ifnet *ifp;
+ register struct in_ifaddr *ia;
+ struct sockaddr_in *sin;
+{
+ register u_long i = ntohl(sin->sin_addr.s_addr);
+ struct sockaddr oldaddr;
+ struct sockaddr_in netaddr;
+ int s = splimp(), error;
+
+ oldaddr = ia->ia_addr;
+ ia->ia_addr = *(struct sockaddr *)sin;
+
+ /*
+ * Give the interface a chance to initialize
+ * if this is its first address,
+ * and to validate the address if necessary.
+ */
+ if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+ splx(s);
+ ia->ia_addr = oldaddr;
+ return (error);
+ }
+
+ /*
+ * Delete any previous route for an old address.
+ */
+ bzero((caddr_t)&netaddr, sizeof (netaddr));
+ netaddr.sin_family = AF_INET;
+ if (ia->ia_flags & IFA_ROUTE) {
+ if (ifp->if_flags & IFF_LOOPBACK)
+ rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
+ else if (ifp->if_flags & IFF_POINTOPOINT)
+ rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
+ RTF_HOST);
+ else {
+ netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
+ INADDR_ANY);
+ rtinit((struct sockaddr *)&netaddr, &oldaddr,
+ (int)SIOCDELRT, 0);
+ }
+ ia->ia_flags &= ~IFA_ROUTE;
+ }
+ if (IN_CLASSA(i))
+ ia->ia_netmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(i))
+ ia->ia_netmask = IN_CLASSB_NET;
+ else
+ ia->ia_netmask = IN_CLASSC_NET;
+ ia->ia_net = i & ia->ia_netmask;
+ /*
+ * The subnet mask includes at least the standard network part,
+ * but may already have been set to a larger value.
+ */
+ ia->ia_subnetmask |= ia->ia_netmask;
+ ia->ia_subnet = i & ia->ia_subnetmask;
+ if (ifp->if_flags & IFF_BROADCAST) {
+ ia->ia_broadaddr.sa_family = AF_INET;
+ ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
+ in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
+ ia->ia_netbroadcast.s_addr =
+ htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
+ }
+ splx(s);
+ /*
+ * Add route for the network.
+ */
+ if (ifp->if_flags & IFF_LOOPBACK)
+ rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
+ RTF_HOST|RTF_UP);
+ else if (ifp->if_flags & IFF_POINTOPOINT)
+ rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
+ RTF_HOST|RTF_UP);
+ else {
+ netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
+ rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
+ (int)SIOCADDRT, RTF_UP);
+ }
+ ia->ia_flags |= IFA_ROUTE;
+ return (0);
+}
+
+/*
+ * Return address info for specified internet network.
+ */
+struct in_ifaddr *
+in_iaonnetof(net)
+ u_long net;
+{
+ register struct in_ifaddr *ia;
+
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_subnet == net)
+ return (ia);
+ return ((struct in_ifaddr *)0);
+}
+
+/*
+ * Return 1 if the address is a local broadcast address.
+ */
+in_broadcast(in)
+ struct in_addr in;
+{
+ register struct in_ifaddr *ia;
+
+ /*
+ * Look through the list of addresses for a match
+ * with a broadcast address.
+ */
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr ==
+ in.s_addr && (ia->ia_ifp->if_flags & IFF_BROADCAST))
+ return (1);
+ return (0);