/*
- * Copyright (c) 1982 Regents of the University of California.
- * All rights reserved. The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
+ * All rights reserved.
*
- * @(#)ns.c 6.2 (Berkeley) %G%
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)ns.c 7.4 (Berkeley) %G%
*/
#include "param.h"
#ifdef NS
struct ns_ifaddr *ns_ifaddr;
-
-ns_hash(sns, hp)
- register struct sockaddr_ns *sns;
- struct afhash *hp;
-{
- register long hash = 0;
- register u_short *s = sns->sns_addr.x_host.s_host;
-
- hp->afh_nethash = ns_netof(sns->sns_addr);
- hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
- hp->afh_hosthash = hash;
-}
-
-
-ns_netmatch(sns1, sns2)
- struct sockaddr_ns *sns1, *sns2;
-{
-
- return (ns_netof(sns1->sns_addr) == ns_netof(sns2->sns_addr));
-}
+int ns_interfaces;
+extern struct sockaddr_ns ns_netmask, ns_hostmask;
/*
* Generic internet control operations (ioctl's).
*/
+/* ARGSUSED */
ns_control(so, cmd, data, ifp)
struct socket *so;
int cmd;
register struct ifnet *ifp;
{
register struct ifreq *ifr = (struct ifreq *)data;
+ register struct ns_aliasreq *ifra = (struct ns_aliasreq *)data;
register struct ns_ifaddr *ia;
struct ifaddr *ifa;
+ struct ns_ifaddr *oia;
struct mbuf *m;
- int error;
-
- if (!suser())
- return (u.u_error);
+ int dstIsNew, hostIsNew;
/*
* Find address for this interface, if it exists.
*/
+ if (ifp == 0)
+ return (EADDRNOTAVAIL);
for (ia = ns_ifaddr; ia; ia = ia->ia_next)
if (ia->ia_ifp == ifp)
break;
switch (cmd) {
case SIOCGIFADDR:
+ if (ia == (struct ns_ifaddr *)0)
+ return (EADDRNOTAVAIL);
+ *(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr;
+ return (0);
+
+
case SIOCGIFBRDADDR:
+ if (ia == (struct ns_ifaddr *)0)
+ return (EADDRNOTAVAIL);
+ if ((ifp->if_flags & IFF_BROADCAST) == 0)
+ return (EINVAL);
+ *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
+ return (0);
+
case SIOCGIFDSTADDR:
if (ia == (struct ns_ifaddr *)0)
return (EADDRNOTAVAIL);
- break;
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ return (EINVAL);
+ *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
+ return (0);
+ }
- case SIOCSIFDSTADDR:
- return (EOPNOTSUPP);
+ if (!suser())
+ return (u.u_error);
+
+ switch (cmd) {
+ case SIOCAIFADDR:
+ case SIOCDIFADDR:
+ if (ifra->ifra_addr.sns_family == AF_NS)
+ for (oia = ia; ia; ia = ia->ia_next) {
+ if (ia->ia_ifp == ifp &&
+ ns_neteq(ia->ia_addr.sns_addr,
+ ifra->ifra_addr.sns_addr))
+ break;
+ }
+ if (cmd == SIOCDIFADDR && ia == 0)
+ return (EADDRNOTAVAIL);
+ /* FALLTHROUGH */
case SIOCSIFADDR:
+ case SIOCSIFDSTADDR:
if (ia == (struct ns_ifaddr *)0) {
m = m_getclr(M_WAIT, MT_IFADDR);
if (m == (struct mbuf *)NULL)
} else
ifp->if_addrlist = (struct ifaddr *) ia;
ia->ia_ifp = ifp;
- IA_SNS(ia)->sns_family = AF_NS;
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+
+ ia->ia_ifa.ifa_netmask =
+ (struct sockaddr *)&ns_netmask;
+
+ ia->ia_ifa.ifa_dstaddr =
+ (struct sockaddr *)&ia->ia_dstaddr;
+ if (ifp->if_flags & IFF_BROADCAST) {
+ ia->ia_broadaddr.sns_family = AF_NS;
+ ia->ia_broadaddr.sns_len = sizeof(ia->ia_addr);
+ ia->ia_broadaddr.sns_addr.x_host = ns_broadhost;
+ }
+ ns_interfaces++;
}
- break;
}
switch (cmd) {
+ int error;
- case SIOCGIFADDR:
- ifr->ifr_addr = ia->ia_addr;
- break;
-
- case SIOCGIFBRDADDR:
- if (ia == (struct ns_ifaddr *)0)
- return (EADDRNOTAVAIL);
- if ((ifp->if_flags & IFF_BROADCAST) == 0)
- return (EINVAL);
- ifr->ifr_dstaddr = ia->ia_broadaddr;
- break;
-
- case SIOCGIFDSTADDR:
- if (ia == (struct ns_ifaddr *)0)
- return (EADDRNOTAVAIL);
+ case SIOCSIFDSTADDR:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
return (EINVAL);
- ifr->ifr_dstaddr = ia->ia_dstaddr;
- break;
+ if (ia->ia_flags & IFA_ROUTE) {
+ rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+ ia->ia_flags &= ~IFA_ROUTE;
+ }
+ if (ifp->if_ioctl) {
+ error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia);
+ if (error)
+ return (error);
+ }
+ *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
+ return (0);
case SIOCSIFADDR:
- return
- (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr));
+ return (ns_ifinit(ifp, ia,
+ (struct sockaddr_ns *)&ifr->ifr_addr, 1));
+
+ case SIOCDIFADDR:
+ ns_ifscrub(ifp, ia);
+ if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
+ ifp->if_addrlist = ifa->ifa_next;
+ else {
+ while (ifa->ifa_next &&
+ (ifa->ifa_next != (struct ifaddr *)ia))
+ ifa = ifa->ifa_next;
+ if (ifa->ifa_next)
+ ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
+ else
+ printf("Couldn't unlink nsifaddr from ifp\n");
+ }
+ oia = ia;
+ if (oia == (ia = ns_ifaddr)) {
+ ns_ifaddr = ia->ia_next;
+ } else {
+ while (ia->ia_next && (ia->ia_next != oia)) {
+ ia = ia->ia_next;
+ }
+ if (ia->ia_next)
+ ia->ia_next = oia->ia_next;
+ else
+ printf("Didn't unlink nsifadr from list\n");
+ }
+ (void) m_free(dtom(oia));
+ if (0 == --ns_interfaces) {
+ /*
+ * We reset to virginity and start all over again
+ */
+ ns_thishost = ns_zerohost;
+ }
+ return (0);
+
+ case SIOCAIFADDR:
+ dstIsNew = 0; hostIsNew = 1;
+ if (ia->ia_addr.sns_family == AF_NS) {
+ if (ifra->ifra_addr.sns_len == 0) {
+ ifra->ifra_addr = ia->ia_addr;
+ hostIsNew = 0;
+ } else if (ns_neteq(ifra->ifra_addr.sns_addr,
+ ia->ia_addr.sns_addr))
+ hostIsNew = 0;
+ }
+ if ((ifp->if_flags & IFF_POINTOPOINT) &&
+ (ifra->ifra_dstaddr.sns_family == AF_NS)) {
+ if (hostIsNew == 0)
+ ns_ifscrub(ifp, ia);
+ ia->ia_dstaddr = ifra->ifra_dstaddr;
+ dstIsNew = 1;
+ }
+ if (ifra->ifra_addr.sns_family == AF_NS &&
+ (hostIsNew || dstIsNew))
+ error = ns_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+ return (error);
default:
if (ifp->if_ioctl == 0)
return (EOPNOTSUPP);
return ((*ifp->if_ioctl)(ifp, cmd, data));
}
- return (0);
}
+/*
+* Delete any previous route for an old address.
+*/
+ns_ifscrub(ifp, ia)
+ register struct ifnet *ifp;
+ register struct ns_ifaddr *ia;
+{
+ if (ia->ia_flags & IFA_ROUTE) {
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+ } else
+ rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
+ ia->ia_flags &= ~IFA_ROUTE;
+ }
+}
/*
* Initialize an interface's internet address
* and routing table entry.
*/
-ns_ifinit(ifp, ia, sns)
+ns_ifinit(ifp, ia, sns, scrub)
register struct ifnet *ifp;
register struct ns_ifaddr *ia;
- struct sockaddr_ns *sns;
+ register struct sockaddr_ns *sns;
{
- struct sockaddr_ns netaddr;
- register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host);
+ struct sockaddr_ns oldaddr;
+ register union ns_host *h = &ia->ia_addr.sns_addr.x_host;
int s = splimp(), error;
+ /*
+ * Set up new addresses.
+ */
+ oldaddr = ia->ia_addr;
+ ia->ia_addr = *sns;
/*
* The convention we shall adopt for naming is that
* a supplied address of zero means that "we don't care".
* if there are multiple interfaces, use any address already
* used.
*
- * If we have gotten into trouble and want to reset back to
- * virginity, we recognize a request of the broadcast address.
- */
- if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) {
- ns_thishost = ns_zerohost;
- splx(s);
- return(EINVAL);
- }
-
- /*
- * Delete any previous route for an old address.
- */
-
- bzero((caddr_t)&netaddr, sizeof (netaddr));
- netaddr.sns_family = AF_NS;
- netaddr.sns_addr.x_host = ns_broadhost;
- netaddr.sns_addr.x_net = ia->ia_net;
- if (ia->ia_flags & IFA_ROUTE) {
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
- rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, -1);
- } else
- rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1);
- }
-
- /*
- * Set up new addresses.
- */
- ia->ia_addr = *(struct sockaddr *)sns;
- ia->ia_net = sns->sns_addr.x_net;
- netaddr.sns_addr.x_net = ia->ia_net;
- if (ifp->if_flags & IFF_BROADCAST) {
- ia->ia_broadaddr = * (struct sockaddr *) &netaddr;
- }
- /*
- * Point to point links are a little touchier --
- * We have to have an address of our own first,
- * and will use the supplied address as that of the other end.
- */
- if (ifp->if_flags & IFF_POINTOPOINT) {
- struct sockaddr_ns *sns2 = IA_SNS(ia);
- if (ns_hosteqnh(ns_zerohost,ns_thishost))
- return(EINVAL);
- ia->ia_dstaddr = ia->ia_addr;
- sns2->sns_addr.x_host = ns_thishost;
- sns->sns_addr.x_host = ns_thishost;
- }
- /*
* Give the interface a chance to initialize
* if this is its first address,
* and to validate the address if necessary.
*/
-
if (ns_hosteqnh(ns_thishost, ns_zerohost)) {
if (ifp->if_ioctl &&
(error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+ ia->ia_addr = oldaddr;
splx(s);
return (error);
}
*h = ns_thishost;
if (ifp->if_ioctl &&
(error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+ ia->ia_addr = oldaddr;
splx(s);
return (error);
}
- if(!ns_hosteqnh(ns_thishost,*h)) {
+ if (!ns_hosteqnh(ns_thishost,*h)) {
+ ia->ia_addr = oldaddr;
splx(s);
return (EINVAL);
}
} else {
+ ia->ia_addr = oldaddr;
splx(s);
- return(EINVAL);
+ return (EINVAL);
}
/*
* Add route for the network.
*/
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
- rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP);
- } else
- rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
- RTF_HOST|RTF_UP);
+ if (scrub) {
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
+ ns_ifscrub(ifp, ia);
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+ }
+ if (ifp->if_flags & IFF_POINTOPOINT)
+ rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
+ else {
+ ia->ia_broadaddr.sns_addr.x_net = ia->ia_net;
+ rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
+ }
ia->ia_flags |= IFA_ROUTE;
- return(0);
+ return (0);
}
/*
* Return address info for specified internet network.
*/
struct ns_ifaddr *
-ns_iaonnetof(net)
- union ns_net net;
+ns_iaonnetof(dst)
+ register struct ns_addr *dst;
{
register struct ns_ifaddr *ia;
-
-#define NtoL(x) (*(long *)(&(x)))
- for (ia = ns_ifaddr; ia; ia = ia->ia_next)
- if (NtoL(ia->ia_net) == NtoL(net))
- return (ia);
- return ((struct ns_ifaddr *)0);
+ register struct ns_addr *compare;
+ register struct ifnet *ifp;
+ struct ns_ifaddr *ia_maybe = 0;
+ union ns_net net = dst->x_net;
+
+ for (ia = ns_ifaddr; ia; ia = ia->ia_next) {
+ if (ifp = ia->ia_ifp) {
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ compare = &satons_addr(ia->ia_dstaddr);
+ if (ns_hosteq(*dst, *compare))
+ return (ia);
+ if (ns_neteqnn(net, ia->ia_net))
+ ia_maybe = ia;
+ } else {
+ if (ns_neteqnn(net, ia->ia_net))
+ return (ia);
+ }
+ }
+ }
+ return (ia_maybe);
}
#endif