/* * Builds and sends a single ARP request to locate the server * * Return value: * 0 on success * errno on error */ static int netdump_send_arp(in_addr_t dst) { struct ether_addr bcast; struct mbuf *m; struct arphdr *ah; int pktlen; MPASS(nd_ifp != NULL); /* Fill-up a broadcast address. */ memset(&bcast, 0xFF, ETHER_ADDR_LEN); m = m_gethdr(M_NOWAIT, MT_DATA); if (m == NULL) { printf("netdump_send_arp: Out of mbufs\n"); return (ENOBUFS); } pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr)); m->m_len = pktlen; m->m_pkthdr.len = pktlen; MH_ALIGN(m, pktlen); ah = mtod(m, struct arphdr *); ah->ar_hrd = htons(ARPHRD_ETHER); ah->ar_pro = htons(ETHERTYPE_IP); ah->ar_hln = ETHER_ADDR_LEN; ah->ar_pln = sizeof(struct in_addr); ah->ar_op = htons(ARPOP_REQUEST); memcpy(ar_sha(ah), IF_LLADDR(nd_ifp), ETHER_ADDR_LEN); ((struct in_addr *)ar_spa(ah))->s_addr = nd_client.s_addr; bzero(ar_tha(ah), ETHER_ADDR_LEN); ((struct in_addr *)ar_tpa(ah))->s_addr = dst; return (netdump_ether_output(m, nd_ifp, bcast, ETHERTYPE_ARP)); }
static int send_arp (interface_t *iface, int op, struct in_addr sip, unsigned char *taddr, struct in_addr tip) { struct arphdr *arp; int arpsize = arphdr_len2 (iface->hwlen, sizeof (struct in_addr)); int retval; arp = xmalloc (arpsize); memset (arp, 0, arpsize); arp->ar_hrd = htons (iface->family); arp->ar_pro = htons (ETHERTYPE_IP); arp->ar_hln = iface->hwlen; arp->ar_pln = sizeof (struct in_addr); arp->ar_op = htons (op); memcpy (ar_sha (arp), &iface->hwaddr, arp->ar_hln); memcpy (ar_spa (arp), &sip, arp->ar_pln); if (taddr) memcpy (ar_tha (arp), taddr, arp->ar_hln); memcpy (ar_tpa (arp), &tip, arp->ar_pln); retval = send_packet (iface, ETHERTYPE_ARP, (unsigned char *) arp, arphdr_len (arp)); free (arp); return (retval); }
void arp_print(netdissect_options *ndo, const u_char *bp, u_int length, u_int caplen) { const struct arp_pkthdr *ap; u_short pro, hrd, op, linkaddr; ap = (const struct arp_pkthdr *)bp; ND_TCHECK(*ap); hrd = HRD(ap); pro = PRO(ap); op = OP(ap); /* if its ATM then call the ATM ARP printer for Frame-relay ARP most of the fields are similar to Ethernet so overload the Ethernet Printer and set the linkaddr type for linkaddr_string() accordingly */ switch(hrd) { case ARPHRD_ATM2225: atmarp_print(ndo, bp, length, caplen); return; case ARPHRD_FRELAY: linkaddr = LINKADDR_FRELAY; break; default: linkaddr = LINKADDR_ETHER; break; } if (!ND_TTEST2(*ar_tpa(ap), PROTO_LEN(ap))) { ND_PRINT((ndo, "[|ARP]")); ND_DEFAULTPRINT((const u_char *)ap, length); return; } if (!ndo->ndo_eflag) { ND_PRINT((ndo, "ARP, ")); } /* print hardware type/len and proto type/len */ if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) || PROTO_LEN(ap) != 4 || HRD_LEN(ap) == 0 || ndo->ndo_vflag) { ND_PRINT((ndo, "%s (len %u), %s (len %u)", tok2str(arphrd_values, "Unknown Hardware (%u)", hrd), HRD_LEN(ap), tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro), PROTO_LEN(ap))); /* don't know know about the address formats */ if (!ndo->ndo_vflag) { goto out; } } /* print operation */ printf("%s%s ", ndo->ndo_vflag ? ", " : "", tok2str(arpop_values, "Unknown (%u)", op)); switch (op) { case ARPOP_REQUEST: ND_PRINT((ndo, "who-has %s", ipaddr_string(TPA(ap)))); if (memcmp((const char *)ezero, (const char *)THA(ap), HRD_LEN(ap)) != 0) ND_PRINT((ndo, " (%s)", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)))); ND_PRINT((ndo, " tell %s", ipaddr_string(SPA(ap)))); break; case ARPOP_REPLY: ND_PRINT((ndo, "%s is-at %s", ipaddr_string(SPA(ap)), linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); break; case ARPOP_REVREQUEST: ND_PRINT((ndo, "who-is %s tell %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); break; case ARPOP_REVREPLY: ND_PRINT((ndo, "%s at %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), ipaddr_string(TPA(ap)))); break; case ARPOP_INVREQUEST: ND_PRINT((ndo, "who-is %s tell %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); break; case ARPOP_INVREPLY: ND_PRINT((ndo,"%s at %s", linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), ipaddr_string(TPA(ap)))); break; default: ND_DEFAULTPRINT((const u_char *)ap, caplen); return; } out: ND_PRINT((ndo, ", length %u", length)); return; trunc: ND_PRINT((ndo, "[|ARP]")); }
static int firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro) { struct fw_com *fc = IFP2FWC(ifp); int error, type; struct m_tag *mtag; union fw_encap *enc; struct fw_hwaddr *destfw; uint8_t speed; uint16_t psize, fsize, dsize; struct mbuf *mtail; int unicast, dgl, foff; static int next_dgl; #if defined(INET) || defined(INET6) struct llentry *lle; #endif #ifdef MAC error = mac_ifnet_check_transmit(ifp, m); if (error) goto bad; #endif if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))) { error = ENETDOWN; goto bad; } /* * For unicast, we make a tag to store the lladdr of the * destination. This might not be the first time we have seen * the packet (for instance, the arp code might be trying to * re-send it after receiving an arp reply) so we only * allocate a tag if there isn't one there already. For * multicast, we will eventually use a different tag to store * the channel number. */ unicast = !(m->m_flags & (M_BCAST | M_MCAST)); if (unicast) { mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL); if (!mtag) { mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, sizeof (struct fw_hwaddr), M_NOWAIT); if (!mtag) { error = ENOMEM; goto bad; } m_tag_prepend(m, mtag); } destfw = (struct fw_hwaddr *)(mtag + 1); } else { destfw = 0; } switch (dst->sa_family) { #ifdef INET case AF_INET: /* * Only bother with arp for unicast. Allocation of * channels etc. for firewire is quite different and * doesn't fit into the arp model. */ if (unicast) { error = arpresolve(ifp, ro ? ro->ro_rt : NULL, m, dst, (u_char *) destfw, &lle); if (error) return (error == EWOULDBLOCK ? 0 : error); } type = ETHERTYPE_IP; break; case AF_ARP: { struct arphdr *ah; ah = mtod(m, struct arphdr *); ah->ar_hrd = htons(ARPHRD_IEEE1394); type = ETHERTYPE_ARP; if (unicast) *destfw = *(struct fw_hwaddr *) ar_tha(ah); /* * The standard arp code leaves a hole for the target * hardware address which we need to close up. */ bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln); m_adj(m, -ah->ar_hln); break; } #endif #ifdef INET6 case AF_INET6: if (unicast) { error = nd6_storelladdr(fc->fc_ifp, m, dst, (u_char *) destfw, &lle); if (error) return (error); } type = ETHERTYPE_IPV6; break; #endif default: if_printf(ifp, "can't handle af%d\n", dst->sa_family); error = EAFNOSUPPORT; goto bad; } /* * Let BPF tap off a copy before we encapsulate. */ if (bpf_peers_present(ifp->if_bpf)) { struct fw_bpfhdr h; if (unicast) bcopy(destfw, h.firewire_dhost, 8); else bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); bcopy(&fc->fc_hwaddr, h.firewire_shost, 8); h.firewire_type = htons(type); bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); } /* * Punt on MCAP for now and send all multicast packets on the * broadcast channel. */ if (m->m_flags & M_MCAST) m->m_flags |= M_BCAST; /* * Figure out what speed to use and what the largest supported * packet size is. For unicast, this is the minimum of what we * can speak and what they can hear. For broadcast, lets be * conservative and use S100. We could possibly improve that * by examining the bus manager's speed map or similar. We * also reduce the packet size for broadcast to account for * the GASP header. */ if (unicast) { speed = min(fc->fc_speed, destfw->sspd); psize = min(512 << speed, 2 << destfw->sender_max_rec); } else { speed = 0; psize = 512 - 2*sizeof(uint32_t); } /* * Next, we encapsulate, possibly fragmenting the original * datagram if it won't fit into a single packet. */ if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) { /* * No fragmentation is necessary. */ M_PREPEND(m, sizeof(uint32_t), M_NOWAIT); if (!m) { error = ENOBUFS; goto bad; } enc = mtod(m, union fw_encap *); enc->unfrag.ether_type = type; enc->unfrag.lf = FW_ENCAP_UNFRAG; enc->unfrag.reserved = 0; /* * Byte swap the encapsulation header manually. */ enc->ul[0] = htonl(enc->ul[0]); error = (ifp->if_transmit)(ifp, m); return (error); } else {
int arp_check (interface_t *iface, struct in_addr address) { if (! iface->arpable) { logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", iface->name); return 0; } unsigned char buf[256]; struct arphdr *ah = (struct arphdr *) buf; memset (buf, 0, sizeof (buf)); ah->ar_hrd = htons (ARPHRD_ETHER); ah->ar_pro = htons (ETHERTYPE_IP); ah->ar_hln = ETHER_ADDR_LEN; ah->ar_pln = sizeof (struct in_addr); ah->ar_op = htons (ARPOP_REQUEST); memcpy (ar_sha (ah), &iface->ethernet_address, ah->ar_hln); memcpy (ar_tpa (ah), &address, ah->ar_pln); logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); open_socket (iface, true); send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &buf, arphdr_len(ah)); unsigned char reply[4096]; int bytes; unsigned char buffer[iface->buffer_length]; struct timeval tv; long timeout = 0; fd_set rset; timeout = uptime() + TIMEOUT; while (1) { tv.tv_sec = timeout - uptime (); tv.tv_usec = 0; if (tv.tv_sec < 1) break; /* Time out */ FD_ZERO (&rset); FD_SET (iface->fd, &rset); if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) break; if (! FD_ISSET (iface->fd, &rset)) continue; memset (buffer, 0, sizeof (buffer)); int buflen = sizeof (buffer); int bufpos = -1; while (bufpos != 0) { memset (reply, 0, sizeof (reply)); if ((bytes = get_packet (iface, (unsigned char *) &reply, buffer, &buflen, &bufpos)) < 0) break; ah = (struct arphdr *) reply; /* Only these types are recognised */ if (ah->ar_op != htons(ARPOP_REPLY) || ah->ar_hrd != htons (ARPHRD_ETHER)) continue; /* Protocol must be IP. */ if (ah->ar_pro != htons (ETHERTYPE_IP)) continue; if (ah->ar_pln != sizeof (struct in_addr)) continue; if (ah->ar_hln != ETHER_ADDR_LEN) continue; if (bytes < sizeof (*ah) + 2 * (4 + ah->ar_hln)) continue; logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (* (struct in_addr *) ar_spa (ah)), ether_ntoa ((struct ether_addr *) ar_sha (ah))); close (iface->fd); iface->fd = -1; return 1; } } close (iface->fd); iface->fd = -1; return 0; }
int arp_check (interface_t *iface, struct in_addr address) { union { unsigned char buffer[iface->buffer_length]; struct arphdr ah; } arp; int bytes; struct timeval tv; long timeout = 0; fd_set rset; if (! iface->arpable) { logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", iface->name); return 0; } memset (arp.buffer, 0, sizeof (arp.buffer)); arp.ah.ar_hrd = htons (iface->family); arp.ah.ar_pro = htons (ETHERTYPE_IP); arp.ah.ar_hln = iface->hwlen; arp.ah.ar_pln = sizeof (struct in_addr); arp.ah.ar_op = htons (ARPOP_REQUEST); memcpy (ar_sha (&arp.ah), &iface->hwaddr, arp.ah.ar_hln); memcpy (ar_tpa (&arp.ah), &address, arp.ah.ar_pln); logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); open_socket (iface, true); send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &arp.buffer, arphdr_len (&arp.ah)); timeout = uptime() + TIMEOUT; while (1) { int buflen = sizeof (arp.buffer); int bufpos = -1; tv.tv_sec = timeout - uptime (); tv.tv_usec = 0; if (tv.tv_sec < 1) break; /* Time out */ FD_ZERO (&rset); FD_SET (iface->fd, &rset); if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) break; if (! FD_ISSET (iface->fd, &rset)) continue; memset (arp.buffer, 0, sizeof (arp.buffer)); while (bufpos != 0) { union { unsigned char buffer[buflen]; struct arphdr hdr; } reply; union { unsigned char *c; struct in_addr *a; } rp; union { unsigned char *c; struct ether_addr *a; } rh; memset (reply.buffer, 0, sizeof (reply.buffer)); if ((bytes = get_packet (iface, reply.buffer, arp.buffer, &buflen, &bufpos)) < 0) break; /* Only these types are recognised */ if (reply.hdr.ar_op != htons(ARPOP_REPLY)) continue; /* Protocol must be IP. */ if (reply.hdr.ar_pro != htons (ETHERTYPE_IP)) continue; if (reply.hdr.ar_pln != sizeof (struct in_addr)) continue; if (reply.hdr.ar_hln != ETHER_ADDR_LEN) continue; if ((unsigned) bytes < sizeof (reply.hdr) + 2 * (4 + reply.hdr.ar_hln)) continue; rp.c = (unsigned char *) ar_spa (&reply.hdr); rh.c = (unsigned char *) ar_sha (&reply.hdr); logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (*rp.a), ether_ntoa (rh.a)); close (iface->fd); iface->fd = -1; return 1; } } close (iface->fd); iface->fd = -1; return 0; }