* SUCH DAMAGE.
*
* @(#)if_ether.c 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/netinet/if_ether.c,v 1.64.2.11 2001/07/25 17:27:56 jlemon Exp $
*/
/*
* add "inuse/lock" bit (or ref. count) along with valid bit
*/
-#if NOTFB31
-#include "opt_inet.h"
-#include "opt_bdg.h"
-#endif
-
#include <sys/param.h>
#include <sys/kernel.h>
-
+#include <sys/queue.h>
#include <sys/sysctl.h>
-
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <net/if.h>
#include <net/if_dl.h>
+#include <net/if_types.h>
#include <net/route.h>
#include <net/netisr.h>
+#include <net/if_llc.h>
+#if BRIDGE
+#include <net/ethernet.h>
+#include <net/bridge.h>
+#endif
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
+#include <net/iso88025.h>
+
#define SIN(s) ((struct sockaddr_in *)s)
#define SDL(s) ((struct sockaddr_dl *)s)
static int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
static int arpt_down = 20; /* once declared down, don't send for 20 sec */
+/* Apple Hardware SUM16 checksuming */
+int apple_hwcksum_tx = 1;
+int apple_hwcksum_rx = 1;
+
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, prune_intvl, CTLFLAG_RW,
&arpt_prune, 0, "");
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
&arpt_keep, 0, "");
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, host_down_time, CTLFLAG_RW,
&arpt_down, 0, "");
+SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_tx, CTLFLAG_RW,
+ &apple_hwcksum_tx, 0, "");
+SYSCTL_INT(_net_link_ether_inet, OID_AUTO, apple_hwcksum_rx, CTLFLAG_RW,
+ &apple_hwcksum_rx, 0, "");
#define rt_expire rt_rmx.rmx_expire
arptimer(ignored_arg)
void *ignored_arg;
{
- int s ;
- register struct llinfo_arp *la;
+#ifdef __APPLE__
+ boolean_t funnel_state = thread_funnel_set(network_flock, TRUE);
+#endif
+ int s = splnet();
+ register struct llinfo_arp *la = llinfo_arp.lh_first;
struct llinfo_arp *ola;
- boolean_t funnel_state;
-
- funnel_state = thread_funnel_set(network_flock, TRUE);
- s = splnet();
- la = llinfo_arp.lh_first;
-
timeout(arptimer, (caddr_t)0, arpt_prune * hz);
while ((ola = la) != 0) {
register struct rtentry *rt = la->la_rt;
arptfree(ola); /* timer has expired, clear */
}
splx(s);
+#ifdef __APPLE__
(void) thread_funnel_set(network_flock, FALSE);
-
+#endif
}
/*
arpinit_done = 1;
LIST_INIT(&llinfo_arp);
timeout(arptimer, (caddr_t)0, hz);
+#ifndef __APPLE__
+ register_netisr(NETISR_ARP, arpintr);
+#endif
}
if (rt->rt_flags & RTF_GATEWAY)
return;
if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {
memcpy(LLADDR(SDL(gate)), etherbroadcastaddr, 6);
SDL(gate)->sdl_alen = 6;
- rt->rt_expire = 0;
+ rt->rt_expire = time_second;
}
#endif
}
}
-
-
-
/*
* Broadcast an ARP packet, asking who has addr on interface ac.
*/
void
arpwhohas(ac, addr)
- register struct arpcom *ac;
- register struct in_addr *addr;
-{ struct ifnet *ifp = (struct ifnet *)ac;
+ struct arpcom *ac;
+ struct in_addr *addr;
+{
+ struct ifnet *ifp = (struct ifnet *)ac;
struct ifaddr *ifa = TAILQ_FIRST(&ifp->if_addrhead);
- while (ifa)
- { if (ifa->ifa_addr->sa_family == AF_INET)
- { arprequest(ac, &SIN(ifa->ifa_addr)->sin_addr, addr, ac->ac_enaddr);
+ while (ifa) {
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ arprequest(ac, &SIN(ifa->ifa_addr)->sin_addr, addr, ac->ac_enaddr);
return;
}
- ifa = TAILQ_NEXT(ifa, ifa_link);
+ ifa = TAILQ_NEXT(ifa, ifa_link);
}
return; /* XXX */
}
-
-
/*
* Broadcast an ARP request. Caller specifies:
* - arp header source ip address
register struct ether_header *eh;
register struct ether_arp *ea;
struct sockaddr sa;
+ static u_char llcx[] = { 0x82, 0x40, LLC_SNAP_LSAP, LLC_SNAP_LSAP,
+ LLC_UI, 0x00, 0x00, 0x00, 0x08, 0x06 };
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
return;
- m->m_len = sizeof(*ea);
- m->m_pkthdr.len = sizeof(*ea);
m->m_pkthdr.rcvif = (struct ifnet *)0;
- MH_ALIGN(m, sizeof(*ea));
- ea = mtod(m, struct ether_arp *);
- eh = (struct ether_header *)sa.sa_data;
- bzero((caddr_t)ea, sizeof (*ea));
- (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
- eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */
- ea->arp_hrd = htons(ARPHRD_ETHER);
+ switch (ac->ac_if.if_type) {
+ case IFT_ISO88025:
+ m->m_len = sizeof(*ea) + sizeof(llcx);
+ m->m_pkthdr.len = sizeof(*ea) + sizeof(llcx);
+ MH_ALIGN(m, sizeof(*ea) + sizeof(llcx));
+ (void)memcpy(mtod(m, caddr_t), llcx, sizeof(llcx));
+ (void)memcpy(sa.sa_data, etherbroadcastaddr, 6);
+ (void)memcpy(sa.sa_data + 6, enaddr, 6);
+ sa.sa_data[6] |= TR_RII;
+ sa.sa_data[12] = TR_AC;
+ sa.sa_data[13] = TR_LLC_FRAME;
+ ea = (struct ether_arp *)(mtod(m, char *) + sizeof(llcx));
+ bzero((caddr_t)ea, sizeof (*ea));
+ ea->arp_hrd = htons(ARPHRD_IEEE802);
+ break;
+ case IFT_FDDI:
+ case IFT_ETHER:
+ /*
+ * This may not be correct for types not explicitly
+ * listed, but this is our best guess
+ */
+ default:
+ m->m_len = sizeof(*ea);
+ m->m_pkthdr.len = sizeof(*ea);
+ MH_ALIGN(m, sizeof(*ea));
+ ea = mtod(m, struct ether_arp *);
+ eh = (struct ether_header *)sa.sa_data;
+ bzero((caddr_t)ea, sizeof (*ea));
+ /* if_output will not swap */
+ eh->ether_type = htons(ETHERTYPE_ARP);
+ (void)memcpy(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost));
+ ea->arp_hrd = htons(ARPHRD_ETHER);
+ break;
+ }
ea->arp_pro = htons(ETHERTYPE_IP);
ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
(void)memcpy(ea->arp_tpa, tip, sizeof(ea->arp_tpa));
sa.sa_family = AF_UNSPEC;
sa.sa_len = sizeof(sa);
- dlil_output((u_long) ac, m, 0, &sa, 0);
+ dlil_output(ifptodlt(((struct ifnet *)ac), PF_INET), m, 0, &sa, 0);
}
/*
register u_char *desten;
struct rtentry *rt0;
{
- register struct llinfo_arp *la = 0;
+ struct llinfo_arp *la = 0;
struct sockaddr_dl *sdl;
if (m->m_flags & M_BCAST) { /* broadcast */
bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
return 1;
}
+ /*
+ * If ARP is disabled on this interface, stop.
+ * XXX
+ * Probably should not allocate empty llinfo struct if we are
+ * not going to be sending out an arp request.
+ */
+ if (ac->ac_if.if_flags & IFF_NOARP)
+ return (0);
/*
* There is an arptab entry, but no ethernet address
* response yet. Replace the held mbuf with this
splx(s);
if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
panic("arpintr");
- if (m->m_len >= sizeof(struct arphdr) &&
- (ar = mtod(m, struct arphdr *)) &&
- ntohs(ar->ar_hrd) == ARPHRD_ETHER &&
- m->m_len >=
- sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
+
+ if (m->m_len < sizeof(struct arphdr) &&
+ ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {
+ log(LOG_ERR, "arp: runt packet -- m_pullup failed\n");
+ continue;
+ }
+ ar = mtod(m, struct arphdr *);
+
+ if (ntohs(ar->ar_hrd) != ARPHRD_ETHER
+ && ntohs(ar->ar_hrd) != ARPHRD_IEEE802) {
+ log(LOG_ERR,
+ "arp: unknown hardware address format (0x%2D)\n",
+ (unsigned char *)&ar->ar_hrd, "");
+ m_freem(m);
+ continue;
+ }
- switch (ntohs(ar->ar_pro)) {
+ if (m->m_pkthdr.len < sizeof(struct arphdr) + 2 * ar->ar_hln
+ + 2 * ar->ar_pln) {
+ log(LOG_ERR, "arp: runt packet\n");
+ m_freem(m);
+ continue;
+ }
-#if INET
- case ETHERTYPE_IP:
- in_arpinput(m);
- continue;
+ switch (ntohs(ar->ar_pro)) {
+#ifdef INET
+ case ETHERTYPE_IP:
+ in_arpinput(m);
+ continue;
#endif
- }
+ }
m_freem(m);
}
}
-NETISR_SET(NETISR_ARP, arpintr);
-
-
#if INET
/*
* ARP for Internet protocols on 10 Mb/s Ethernet.
* We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
* but formerly didn't normally send requests.
*/
+static int log_arp_wrong_iface = 0;
+
+SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW,
+ &log_arp_wrong_iface, 0,
+ "log arp packets arriving on the wrong interface");
+
static void
in_arpinput(m)
struct mbuf *m;
register struct ether_arp *ea;
register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
struct ether_header *eh;
+ struct iso88025_header *th = (struct iso88025_header *)0;
register struct llinfo_arp *la = 0;
register struct rtentry *rt;
struct in_ifaddr *ia, *maybe_ia = 0;
struct sockaddr_dl *sdl;
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
- int op;
+ int op, rif_len;
unsigned char buf[18];
+ unsigned char buf2[18];
+
+ if (m->m_len < sizeof(struct ether_arp) &&
+ (m = m_pullup(m, sizeof(struct ether_arp))) == NULL) {
+ log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n");
+ return;
+ }
ea = mtod(m, struct ether_arp *);
op = ntohs(ea->arp_op);
(void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr));
(void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr));
- for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next)
-#if BRIDGE
+
+#if __APPLE__
+ /* Don't respond to requests for 0.0.0.0 */
+ if (itaddr.s_addr == 0 && op == ARPOP_REQUEST) {
+ m_freem(m);
+ return;
+ }
+#endif
+
+ for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) {
/*
* For a bridge, we want to check the address irrespective
* of the receive interface. (This will change slightly
* when we have clusters of interfaces).
*/
- {
+#if BRIDGE
+#define BRIDGE_TEST (do_bridge)
#else
- if (ia->ia_ifp == &ac->ac_if) {
+#define BRIDGE_TEST (0) /* cc will optimise the test away */
#endif
+ if ((BRIDGE_TEST) || (ia->ia_ifp == &ac->ac_if)) {
maybe_ia = ia;
if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
- (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
+ (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) {
break;
+ }
}
+ }
if (maybe_ia == 0) {
m_freem(m);
return;
}
myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
-
-#if 0
- /*
- * In order to support BlueBox networking, we need to allow
- * "self-addressed" stamped envelopes
- */
if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
sizeof (ea->arp_sha))) {
m_freem(m); /* it's from me, ignore it. */
return;
}
-#endif
if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
sizeof (ea->arp_sha))) {
log(LOG_ERR,
return;
}
if (isaddr.s_addr == myaddr.s_addr) {
- log(LOG_ERR,
- "duplicate IP address %s sent from ethernet address %s\n",
- inet_ntoa(isaddr), ether_sprintf(buf, ea->arp_sha));
+ struct kev_msg ev_msg;
+ struct kev_in_collision *in_collision;
+ u_char storage[sizeof(struct kev_in_collision) + 6];
+ in_collision = (struct kev_in_collision*)storage;
+
+ log(LOG_ERR,
+ "duplicate IP address %s sent from ethernet address %s\n",
+ inet_ntoa(isaddr), ether_sprintf(buf, ea->arp_sha));
+
+ /* Send a kernel event so anyone can learn of the conflict */
+ in_collision->link_data.if_family = ac->ac_if.if_family;
+ in_collision->link_data.if_unit = ac->ac_if.if_unit;
+ strncpy(&in_collision->link_data.if_name[0], ac->ac_if.if_name, IFNAMSIZ);
+ in_collision->ia_ipaddr = isaddr;
+ in_collision->hw_len = ETHER_ADDR_LEN;
+ bcopy((caddr_t)ea->arp_sha, (caddr_t)in_collision->hw_addr, sizeof(ea->arp_sha));
+ ev_msg.vendor_code = KEV_VENDOR_APPLE;
+ ev_msg.kev_class = KEV_NETWORK_CLASS;
+ ev_msg.kev_subclass = KEV_INET_SUBCLASS;
+ ev_msg.event_code = KEV_INET_ARPCOLLISION;
+ ev_msg.dv[0].data_ptr = in_collision;
+ ev_msg.dv[0].data_length = sizeof(struct kev_in_collision) + 6;
+ ev_msg.dv[1].data_length = 0;
+ kev_post_msg(&ev_msg);
+
itaddr = myaddr;
goto reply;
}
la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
-#ifndef BRIDGE /* the following is not an error when doing bridging */
- if (rt->rt_ifp != &ac->ac_if) {
- log(LOG_ERR, "arp: %s is on %s%d but got reply from %6D on %s%d\n",
+ /* the following is not an error when doing bridging */
+ if (!BRIDGE_TEST && rt->rt_ifp != &ac->ac_if) {
+ if (log_arp_wrong_iface)
+ log(LOG_ERR, "arp: %s is on %s%d but got reply from %s on %s%d\n",
inet_ntoa(isaddr),
rt->rt_ifp->if_name, rt->rt_ifp->if_unit,
- ea->arp_sha, ":",
+ ether_sprintf(buf, ea->arp_sha),
ac->ac_if.if_name, ac->ac_if.if_unit);
- goto reply;
+ goto reply;
}
-#endif
if (sdl->sdl_alen &&
- bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen))
+ bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) {
if (rt->rt_expire)
- log(LOG_INFO, "arp: %s moved from %6D to %6D on %s%d\n",
- inet_ntoa(isaddr), (u_char *)LLADDR(sdl), ":",
- ea->arp_sha, ":",
+ log(LOG_INFO, "arp: %s moved from %s to %s on %s%d\n",
+ inet_ntoa(isaddr),
+ ether_sprintf(buf, (u_char *)LLADDR(sdl)),
+ ether_sprintf(buf2, ea->arp_sha),
ac->ac_if.if_name, ac->ac_if.if_unit);
else {
log(LOG_ERR,
- "arp: %6D attempts to modify permanent entry for %s on %s%d",
- ea->arp_sha, ":", inet_ntoa(isaddr),
+ "arp: %s attempts to modify permanent entry for %s on %s%d",
+ ether_sprintf(buf, ea->arp_sha), inet_ntoa(isaddr),
ac->ac_if.if_name, ac->ac_if.if_unit);
goto reply;
}
+ }
(void)memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
sdl->sdl_alen = sizeof(ea->arp_sha);
+#ifndef __APPLE__
+ /* TokenRing */
+ sdl->sdl_rcf = (u_short)0;
+ /*
+ * If we receive an arp from a token-ring station over
+ * a token-ring nic then try to save the source
+ * routing info.
+ */
+ if (ac->ac_if.if_type == IFT_ISO88025) {
+ th = (struct iso88025_header *)m->m_pkthdr.header;
+ rif_len = TR_RCF_RIFLEN(th->rcf);
+ if ((th->iso88025_shost[0] & TR_RII) &&
+ (rif_len > 2)) {
+ sdl->sdl_rcf = th->rcf;
+ sdl->sdl_rcf ^= htons(TR_RCF_DIR);
+ memcpy(sdl->sdl_route, th->rd, rif_len - 2);
+ sdl->sdl_rcf &= ~htons(TR_RCF_BCST_MASK);
+ /*
+ * Set up source routing information for
+ * reply packet (XXX)
+ */
+ m->m_data -= rif_len;
+ m->m_len += rif_len;
+ m->m_pkthdr.len += rif_len;
+ } else {
+ th->iso88025_shost[0] &= ~TR_RII;
+ }
+ m->m_data -= 8;
+ m->m_len += 8;
+ m->m_pkthdr.len += 8;
+ th->rcf = sdl->sdl_rcf;
+ }
+#endif
if (rt->rt_expire)
rt->rt_expire = time_second + arpt_keep;
rt->rt_flags &= ~RTF_REJECT;
la->la_asked = 0;
if (la->la_hold) {
- dlil_output((u_long) ac, la->la_hold, rt,
+ dlil_output(((struct ifnet *)ac)->if_data.default_proto, la->la_hold, rt,
rt_key(rt), 0);
la->la_hold = 0;
}
(void)memcpy(ea->arp_spa, &itaddr, sizeof(ea->arp_spa));
ea->arp_op = htons(ARPOP_REPLY);
ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
- eh = (struct ether_header *)sa.sa_data;
- (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
- eh->ether_type = htons(ETHERTYPE_ARP);
+ switch (ac->ac_if.if_type) {
+ case IFT_ISO88025:
+ /* Re-arrange the source/dest address */
+ memcpy(th->iso88025_dhost, th->iso88025_shost,
+ sizeof(th->iso88025_dhost));
+ memcpy(th->iso88025_shost, ac->ac_enaddr,
+ sizeof(th->iso88025_shost));
+ /* Set the source routing bit if neccesary */
+ if (th->iso88025_dhost[0] & TR_RII) {
+ th->iso88025_dhost[0] &= ~TR_RII;
+ if (TR_RCF_RIFLEN(th->rcf) > 2)
+ th->iso88025_shost[0] |= TR_RII;
+ }
+ /* Copy the addresses, ac and fc into sa_data */
+ memcpy(sa.sa_data, th->iso88025_dhost,
+ sizeof(th->iso88025_dhost) * 2);
+ sa.sa_data[(sizeof(th->iso88025_dhost) * 2)] = TR_AC;
+ sa.sa_data[(sizeof(th->iso88025_dhost) * 2) + 1] = TR_LLC_FRAME;
+ break;
+ case IFT_ETHER:
+ case IFT_FDDI:
+ /*
+ * May not be correct for types not explictly
+ * listed, but it is our best guess.
+ */
+ default:
+ eh = (struct ether_header *)sa.sa_data;
+#ifdef __APPLE__
+ if (IN_LINKLOCAL(ntohl(*((u_int32_t*)ea->arp_spa))))
+ (void)memcpy(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost));
+ else
+#endif
+ (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost));
+ eh->ether_type = htons(ETHERTYPE_ARP);
+ break;
+ }
sa.sa_family = AF_UNSPEC;
sa.sa_len = sizeof(sa);
- dlil_output((u_long) ac, m, 0, &sa, 0);
+ dlil_output(((struct ifnet *)ac)->if_data.default_proto, m, 0, &sa, 0);
return;
}
#endif
rt = rtalloc1((struct sockaddr *)&sin, create, 0UL);
if (rt == 0)
return (0);
- rt->rt_refcnt--;
-
- if (rt->rt_flags & RTF_GATEWAY)
+ rtunref(rt);
+
+ if (rt->rt_flags & RTF_GATEWAY) {
why = "host is not on local network";
+
+ /* If there are no references to this route, purge it */
+ if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_WASCLONED) != 0) {
+ rtrequest(RTM_DELETE,
+ (struct sockaddr *)rt_key(rt),
+ rt->rt_gateway, rt_mask(rt),
+ rt->rt_flags, 0);
+ }
+ }
else if ((rt->rt_flags & RTF_LLINFO) == 0)
why = "could not allocate llinfo";
else if (rt->rt_gateway->sa_family != AF_LINK)