+
+/*
+ * Map interface name to
+ * interface structure pointer.
+ */
+struct ifnet *
+ifunit(name)
+ register char *name;
+{
+ register char *cp;
+ register struct ifnet *ifp;
+ int unit;
+ unsigned len;
+ char *ep, c;
+
+ for (cp = name; cp < name + IFNAMSIZ && *cp; cp++)
+ if (*cp >= '0' && *cp <= '9')
+ break;
+ if (*cp == '\0' || cp == name + IFNAMSIZ)
+ return ((struct ifnet *)0);
+ /*
+ * Save first char of unit, and pointer to it,
+ * so we can put a null there to avoid matching
+ * initial substrings of interface names.
+ */
+ len = cp - name + 1;
+ c = *cp;
+ ep = cp;
+ for (unit = 0; *cp >= '0' && *cp <= '9'; )
+ unit = unit * 10 + *cp++ - '0';
+ *ep = 0;
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ if (bcmp(ifp->if_name, name, len))
+ continue;
+ if (unit == ifp->if_unit)
+ break;
+ }
+ *ep = c;
+ return (ifp);
+}
+
+/*
+ * Interface ioctls.
+ */
+ifioctl(so, cmd, data, p)
+ struct socket *so;
+ int cmd;
+ caddr_t data;
+ struct proc *p;
+{
+ register struct ifnet *ifp;
+ register struct ifreq *ifr;
+ int error;
+
+ switch (cmd) {
+
+ case SIOCGIFCONF:
+ case OSIOCGIFCONF:
+ return (ifconf(cmd, data));
+
+#if defined(INET) && NETHER > 0
+ case SIOCSARP:
+ case SIOCDARP:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ /* FALL THROUGH */
+ case SIOCGARP:
+ case OSIOCGARP:
+ return (arpioctl(cmd, data));
+#endif
+ }
+ ifr = (struct ifreq *)data;
+ ifp = ifunit(ifr->ifr_name);
+ if (ifp == 0)
+ return (ENXIO);
+ switch (cmd) {
+
+ case SIOCGIFFLAGS:
+ ifr->ifr_flags = ifp->if_flags;
+ break;
+
+ case SIOCGIFMETRIC:
+ ifr->ifr_metric = ifp->if_metric;
+ break;
+
+ case SIOCSIFFLAGS:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) {
+ int s = splimp();
+ if_down(ifp);
+ splx(s);
+ }
+ ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
+ (ifr->ifr_flags &~ IFF_CANTCHANGE);
+ if (ifp->if_ioctl)
+ (void) (*ifp->if_ioctl)(ifp, cmd, data);
+ break;
+
+ case SIOCSIFMETRIC:
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ ifp->if_metric = ifr->ifr_metric;
+ break;
+
+ default:
+ if (so->so_proto == 0)
+ return (EOPNOTSUPP);
+#ifndef COMPAT_43
+ return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
+ cmd, data, ifp));
+#else
+ {
+ int ocmd = cmd;
+
+ switch (cmd) {
+
+ case SIOCSIFDSTADDR:
+ case SIOCSIFADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCSIFNETMASK:
+#if BYTE_ORDER != BIG_ENDIAN
+ if (ifr->ifr_addr.sa_family == 0 &&
+ ifr->ifr_addr.sa_len < 16) {
+ ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
+ ifr->ifr_addr.sa_len = 16;
+ }
+#else
+ if (ifr->ifr_addr.sa_len == 0)
+ ifr->ifr_addr.sa_len = 16;
+#endif
+ break;
+
+ case OSIOCGIFADDR:
+ cmd = SIOCGIFADDR;
+ break;
+
+ case OSIOCGIFDSTADDR:
+ cmd = SIOCGIFDSTADDR;
+ break;
+
+ case OSIOCGIFBRDADDR:
+ cmd = SIOCGIFBRDADDR;
+ break;
+
+ case OSIOCGIFNETMASK:
+ cmd = SIOCGIFNETMASK;
+ }
+ error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
+ cmd, data, ifp));
+ switch (ocmd) {
+
+ case OSIOCGIFADDR:
+ case OSIOCGIFDSTADDR:
+ case OSIOCGIFBRDADDR:
+ case OSIOCGIFNETMASK:
+ *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
+ }
+ return (error);
+
+ }
+#endif
+ }
+ return (0);
+}
+
+/*
+ * Return interface configuration
+ * of system. List may be used
+ * in later ioctl's (above) to get
+ * other information.
+ */
+/*ARGSUSED*/
+ifconf(cmd, data)
+ int cmd;
+ caddr_t data;
+{
+ register struct ifconf *ifc = (struct ifconf *)data;
+ register struct ifnet *ifp = ifnet;
+ register struct ifaddr *ifa;
+ register char *cp, *ep;
+ struct ifreq ifr, *ifrp;
+ int space = ifc->ifc_len, error = 0;
+
+ ifrp = ifc->ifc_req;
+ ep = ifr.ifr_name + sizeof (ifr.ifr_name) - 2;
+ for (; space > sizeof (ifr) && ifp; ifp = ifp->if_next) {
+ bcopy(ifp->if_name, ifr.ifr_name, sizeof (ifr.ifr_name) - 2);
+ for (cp = ifr.ifr_name; cp < ep && *cp; cp++)
+ ;
+ *cp++ = '0' + ifp->if_unit; *cp = '\0';
+ if ((ifa = ifp->if_addrlist) == 0) {
+ bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp, sizeof (ifr));
+ if (error)
+ break;
+ space -= sizeof (ifr), ifrp++;
+ } else
+ for ( ; space > sizeof (ifr) && ifa; ifa = ifa->ifa_next) {
+ register struct sockaddr *sa = ifa->ifa_addr;
+#ifdef COMPAT_43
+ if (cmd == OSIOCGIFCONF) {
+ struct osockaddr *osa =
+ (struct osockaddr *)&ifr.ifr_addr;
+ ifr.ifr_addr = *sa;
+ osa->sa_family = sa->sa_family;
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr));
+ ifrp++;
+ } else
+#endif
+ if (sa->sa_len <= sizeof(*sa)) {
+ ifr.ifr_addr = *sa;
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr));
+ ifrp++;
+ } else {
+ space -= sa->sa_len - sizeof(*sa);
+ if (space < sizeof (ifr))
+ break;
+ error = copyout((caddr_t)&ifr, (caddr_t)ifrp,
+ sizeof (ifr.ifr_name));
+ if (error == 0)
+ error = copyout((caddr_t)sa,
+ (caddr_t)&ifrp->ifr_addr, sa->sa_len);
+ ifrp = (struct ifreq *)
+ (sa->sa_len + (caddr_t)&ifrp->ifr_addr);
+ }
+ if (error)
+ break;
+ space -= sizeof (ifr);
+ }
+ }
+ ifc->ifc_len -= space;
+ return (error);
+}
+
+static char *
+sprint_d(n, buf, buflen)
+ u_int n;
+ char *buf;
+ int buflen;
+{
+ register char *cp = buf + buflen - 1;
+
+ *cp = 0;
+ do {
+ cp--;
+ *cp = "0123456789"[n % 10];
+ n /= 10;
+ } while (n != 0);
+ return (cp);
+}