+
+arpioctl(cmd, data)
+ int cmd;
+ caddr_t data;
+{
+ register struct arpreq *ar = (struct arpreq *)data;
+ register struct arptab *at;
+ register struct sockaddr_in *sin;
+ int s;
+
+ sin = (struct sockaddr_in *)&ar->arp_ha;
+#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
+ if (sin->sin_family == 0 && sin->sin_len < 16)
+ sin->sin_family = sin->sin_len;
+#endif
+ sin->sin_len = sizeof(ar->arp_ha);
+ sin = (struct sockaddr_in *)&ar->arp_pa;
+#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
+ if (sin->sin_family == 0 && sin->sin_len < 16)
+ sin->sin_family = sin->sin_len;
+#endif
+ sin->sin_len = sizeof(ar->arp_pa);
+ if (ar->arp_pa.sa_family != AF_INET ||
+ ar->arp_ha.sa_family != AF_UNSPEC)
+ return (EAFNOSUPPORT);
+ s = splimp();
+ ARPTAB_LOOK(at, sin->sin_addr.s_addr);
+ if (at == NULL) { /* not found */
+ if (cmd != SIOCSARP) {
+ splx(s);
+ return (ENXIO);
+ }
+ if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
+ splx(s);
+ return (ENETUNREACH);
+ }
+ }
+ switch (cmd) {
+
+ case SIOCSARP: /* set entry */
+ if (at == NULL) {
+ at = arptnew(&sin->sin_addr);
+ if (at == NULL) {
+ splx(s);
+ return (EADDRNOTAVAIL);
+ }
+ if (ar->arp_flags & ATF_PERM) {
+ /* never make all entries in a bucket permanent */
+ register struct arptab *tat;
+
+ /* try to re-allocate */
+ tat = arptnew(&sin->sin_addr);
+ if (tat == NULL) {
+ arptfree(at);
+ splx(s);
+ return (EADDRNOTAVAIL);
+ }
+ arptfree(tat);
+ }
+ }
+ bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
+ sizeof(at->at_enaddr));
+ at->at_flags = ATF_COM | ATF_INUSE |
+ (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
+ at->at_timer = 0;
+ break;
+
+ case SIOCDARP: /* delete entry */
+ arptfree(at);
+ break;
+
+ case SIOCGARP: /* get entry */
+ case OSIOCGARP:
+ bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
+ sizeof(at->at_enaddr));
+#ifdef COMPAT_43
+ if (cmd == OSIOCGARP)
+ *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family;
+#endif
+ ar->arp_flags = at->at_flags;
+ break;
+ }
+ splx(s);
+ return (0);
+}