/* Caller must leave room for ethernet header in front!! */ ssize_t sendether(struct iodesc *d, void *pkt, size_t len, u_char *dea, int etype) { ssize_t n; struct ether_header *eh; #ifdef ETHER_DEBUG if (debug) printf("sendether: called\n"); #endif eh = (struct ether_header *)pkt - 1; len += sizeof(*eh); MACPY(d->myea, eh->ether_shost); /* by byte */ MACPY(dea, eh->ether_dhost); /* by byte */ eh->ether_type = htons(etype); n = netif_put(d, eh, len); if (n == -1 || (size_t)n < sizeof(*eh)) return -1; n -= sizeof(*eh); return n; }
static int arpsend(struct nbuf *nbuf,unsigned char *dest_hw,unsigned short ptype) { struct ethhdr *eh = nbuf->lh.ethernet; struct nic *d = nbuf->nic; nbuf->data -= ETH_HLEN; nbuf->len += ETH_HLEN; MACPY(d->node_addr, eh->ether_shost); /* by byte */ MACPY(dest_hw, eh->ether_dhost); /* by byte */ eh->ether_type = htons(ptype); if(d->transmit) return d->transmit(d, nbuf->data,nbuf->len); return 0; }
/* Fetch required bootp information */ void bootp(int sock) { struct iodesc *d; struct bootp *bp; struct { u_char header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[HEADER_SIZE]; struct bootp rbootp; } rbuf; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%x\n", (u_int)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = HTYPE_ETHERNET; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); bzero(bp->bp_file, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); d->myip = myip; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); (void)sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)); /* Bump xid so next request will be unique. */ ++d->xid; }
int netif_attach(struct netif *nif, struct iodesc *s, void *aux) { struct devdata *dd; dd = nif->nif_devdata; if (dd == NULL) { dd = netif_init(aux); if (dd == NULL) return (ENXIO); nif->nif_devdata = dd; } dd->dd_opens++; MACPY(dd->dd_myea, s->myea); s->io_netif = nif; return(0); }
/* Fetch required bootp infomation */ void bootp(int sock, int flag) { struct iodesc *d; struct bootp *bp; struct { u_char header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[HEADER_SIZE]; struct bootp rbootp; } rbuf; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); #ifdef SUPPORT_DHCP bp->bp_vend[4] = TAG_DHCP_MSGTYPE; bp->bp_vend[5] = 1; bp->bp_vend[6] = DHCPDISCOVER; /* * If we are booting from PXE, we want to send the string * 'PXEClient' to the DHCP server so you have the option of * only responding to PXE aware dhcp requests. */ if (flag & BOOTP_PXE) { bp->bp_vend[7] = TAG_CLASSID; bp->bp_vend[8] = 9; bcopy("PXEClient", &bp->bp_vend[9], 9); bp->bp_vend[18] = TAG_PARAM_REQ; bp->bp_vend[19] = 7; bp->bp_vend[20] = TAG_ROOTPATH; bp->bp_vend[21] = TAG_HOSTNAME; bp->bp_vend[22] = TAG_SWAPSERVER; bp->bp_vend[23] = TAG_GATEWAY; bp->bp_vend[24] = TAG_SUBNET_MASK; bp->bp_vend[25] = TAG_INTF_MTU; bp->bp_vend[26] = TAG_SERVERID; bp->bp_vend[27] = TAG_END; } else bp->bp_vend[7] = TAG_END; #else bp->bp_vend[4] = TAG_END; #endif d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if(sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if(dhcp_ok) { u_int32_t leasetime; bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[8] = 4; bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4); bp->bp_vend[13] = TAG_SERVERID; bp->bp_vend[14] = 4; bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); bp->bp_vend[19] = TAG_LEASETIME; bp->bp_vend[20] = 4; leasetime = htonl(300); bcopy(&leasetime, &bp->bp_vend[21], 4); if (flag & BOOTP_PXE) { bp->bp_vend[25] = TAG_CLASSID; bp->bp_vend[26] = 9; bcopy("PXEClient", &bp->bp_vend[27], 9); bp->bp_vend[36] = TAG_END; } else bp->bp_vend[25] = TAG_END; expected_dhcpmsgtype = DHCPACK; if(sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif myip = d->myip = rbuf.rbootp.bp_yiaddr; servip = rbuf.rbootp.bp_siaddr; if(rootip.s_addr == INADDR_ANY) rootip = servip; bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); bootfile[sizeof(bootfile) - 1] = '\0'; if (!netmask) { if (IN_CLASSA(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSB_NET); else netmask = htonl(IN_CLASSC_NET); #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(netmask)); #endif } #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } /* Bump xid so next request will be unique. */ ++d->xid; }
/* Broadcast an ARP packet, asking who has addr on interface d */ unsigned char * arpwhohas(struct nic *d, struct in_addr addr) { int i; struct ether_arp *ah; struct arp_list *al; struct { struct ethhdr eh; struct { struct ether_arp arp; unsigned char pad[18]; /* 60 - sizeof(...) */ } data; } wbuf; struct { struct ethhdr eh; struct { struct ether_arp arp; unsigned char pad[24]; /* extra space */ } data; } rbuf; /* Try for cached answer first */ for (i = 0, al = arp_list; i < arp_num; ++i, ++al) if (addr.s_addr == al->addr.s_addr) return (al->ea); /* Don't overflow cache */ if (arp_num > ARP_NUM - 1) { arp_num = 1; /* recycle */ debug_print("arpwhohas: overflowed arp_list!\r\n"); } #ifdef ARP_DEBUG if (debug) debug_print("arpwhohas: send request for %08x\r\n", addr.s_addr); #endif bzero((char*)&wbuf.data, sizeof(wbuf.data)); ah = &wbuf.data.arp; ah->arp_hrd = htons(ARPHRD_ETHER); ah->arp_pro = htons(ETHERTYPE_IP); ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */ ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */ ah->arp_op = htons(ARPOP_REQUEST); MACPY(d->node_addr, ah->arp_sha); bcopy(&d->ip_addr, ah->arp_spa, sizeof(ah->arp_spa)); /* Leave zeros in arp_tha */ bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa)); /* Store ip address in cache (incomplete entry). */ al->addr = addr; /* send packet */ /* Store ethernet address in cache */ ah = &rbuf.data.arp; MACPY(ah->arp_sha, al->ea); ++arp_num; return (al->ea); }
/* Fetch required bootp information */ void bootp(int sock) { struct iodesc *d; struct bootp *bp; struct { u_char header[UDP_TOTAL_HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[UDP_TOTAL_HEADER_SIZE]; struct bootp rbootp; } rbuf; unsigned int index; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; (void)memset(bp, 0, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); (void)strncpy((char *)bp->bp_file, bootfile, sizeof(bp->bp_file)); (void)memcpy(bp->bp_vend, vm_rfc1048, sizeof(vm_rfc1048)); index = 4; #ifdef SUPPORT_DHCP bp->bp_vend[index++] = TAG_DHCP_MSGTYPE; bp->bp_vend[index++] = 1; bp->bp_vend[index++] = DHCPDISCOVER; #endif bootp_addvend(&bp->bp_vend[index]); d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if (sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if (dhcp_ok) { u_int32_t leasetime; index = 6; bp->bp_vend[index++] = DHCPREQUEST; bp->bp_vend[index++] = TAG_REQ_ADDR; bp->bp_vend[index++] = 4; (void)memcpy(&bp->bp_vend[9], &rbuf.rbootp.bp_yiaddr, 4); index += 4; bp->bp_vend[index++] = TAG_SERVERID; bp->bp_vend[index++] = 4; (void)memcpy(&bp->bp_vend[index], &dhcp_serverip.s_addr, 4); index += 4; bp->bp_vend[index++] = TAG_LEASETIME; bp->bp_vend[index++] = 4; leasetime = htonl(300); (void)memcpy(&bp->bp_vend[index], &leasetime, 4); index += 4; bootp_addvend(&bp->bp_vend[index]); expected_dhcpmsgtype = DHCPACK; if (sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif myip = d->myip = rbuf.rbootp.bp_yiaddr; servip = rbuf.rbootp.bp_siaddr; if (rootip.s_addr == INADDR_ANY) rootip = servip; (void)memcpy(bootfile, rbuf.rbootp.bp_file, sizeof(bootfile)); bootfile[sizeof(bootfile) - 1] = '\0'; if (IN_CLASSA(myip.s_addr)) nmask = IN_CLASSA_NET; else if (IN_CLASSB(myip.s_addr)) nmask = IN_CLASSB_NET; else nmask = IN_CLASSC_NET; #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(nmask)); #endif /* Get subnet (or natural net) mask */ netmask = nmask; if (smask) netmask = smask; #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } #ifdef BOOTP_DEBUG if (debug) { printf("client addr: %s\n", inet_ntoa(myip)); if (smask) printf("subnet mask: %s\n", intoa(smask)); if (gateip.s_addr != 0) printf("net gateway: %s\n", inet_ntoa(gateip)); printf("server addr: %s\n", inet_ntoa(rootip)); if (rootpath[0] != '\0') printf("server path: %s\n", rootpath); if (bootfile[0] != '\0') printf("file name: %s\n", bootfile); } #endif /* Bump xid so next request will be unique. */ ++d->xid; }
/* Fetch required bootp infomation */ void bootp(int sock) { void *pkt; struct iodesc *d; struct bootp *bp; struct { uchar_t header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct bootp *rbootp; #ifdef BOOTP_DEBUG if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUG if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof (*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof (bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof (vm_rfc1048)); #ifdef SUPPORT_DHCP bp->bp_vend[4] = TAG_DHCP_MSGTYPE; bp->bp_vend[5] = 1; bp->bp_vend[6] = DHCPDISCOVER; bootp_fill_request(&bp->bp_vend[7]); #else bp->bp_vend[4] = TAG_END; #endif d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); #ifdef SUPPORT_DHCP expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif if (sendrecv(d, bootpsend, bp, sizeof (*bp), bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if (dhcp_ok) { uint32_t leasetime; bp->bp_vend[6] = DHCPREQUEST; bp->bp_vend[7] = TAG_REQ_ADDR; bp->bp_vend[8] = 4; bcopy(&rbootp->bp_yiaddr, &bp->bp_vend[9], 4); bp->bp_vend[13] = TAG_SERVERID; bp->bp_vend[14] = 4; bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4); bp->bp_vend[19] = TAG_LEASETIME; bp->bp_vend[20] = 4; leasetime = htonl(300); bcopy(&leasetime, &bp->bp_vend[21], 4); bootp_fill_request(&bp->bp_vend[25]); expected_dhcpmsgtype = DHCPACK; free(pkt); if (sendrecv(d, bootpsend, bp, sizeof (*bp), bootprecv, &pkt, (void **)&rbootp, NULL) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif myip = d->myip = rbootp->bp_yiaddr; servip = rbootp->bp_siaddr; if (rootip.s_addr == INADDR_ANY) rootip = servip; bcopy(rbootp->bp_file, bootfile, sizeof (bootfile)); bootfile[sizeof (bootfile) - 1] = '\0'; if (!netmask) { if (IN_CLASSA(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSA_NET); else if (IN_CLASSB(ntohl(myip.s_addr))) netmask = htonl(IN_CLASSB_NET); else netmask = htonl(IN_CLASSC_NET); #ifdef BOOTP_DEBUG if (debug) printf("'native netmask' is %s\n", intoa(netmask)); #endif } #ifdef BOOTP_DEBUG if (debug) printf("mask: %s\n", intoa(netmask)); #endif /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("gateway ip (%s) bad\n", inet_ntoa(gateip)); #endif gateip.s_addr = 0; } /* Bump xid so next request will be unique. */ ++d->xid; free(pkt); }
/* Broadcast an ARP packet, asking who has addr on interface d */ uchar_t * arpwhohas(struct iodesc *d, struct in_addr addr) { int i; struct ether_arp *ah; struct arp_list *al; void *pkt; struct { struct ether_header eh; struct { struct ether_arp arp; uchar_t pad[18]; /* 60 - sizeof (...) */ } data; } wbuf; /* Try for cached answer first */ for (i = 0, al = arp_list; i < arp_num; ++i, ++al) if (addr.s_addr == al->addr.s_addr) return (al->ea); /* Don't overflow cache */ if (arp_num > ARP_NUM - 1) { arp_num = 1; /* recycle */ printf("arpwhohas: overflowed arp_list!\n"); } #ifdef ARP_DEBUG if (debug) printf("arpwhohas: send request for %s\n", inet_ntoa(addr)); #endif bzero((char *)&wbuf.data, sizeof (wbuf.data)); ah = &wbuf.data.arp; ah->arp_hrd = htons(ARPHRD_ETHER); ah->arp_pro = htons(ETHERTYPE_IP); ah->arp_hln = sizeof (ah->arp_sha); /* hardware address length */ ah->arp_pln = sizeof (ah->arp_spa); /* protocol address length */ ah->arp_op = htons(ARPOP_REQUEST); MACPY(d->myea, ah->arp_sha); bcopy(&d->myip, ah->arp_spa, sizeof (ah->arp_spa)); /* Leave zeros in arp_tha */ bcopy(&addr, ah->arp_tpa, sizeof (ah->arp_tpa)); /* Store ip address in cache (incomplete entry). */ al->addr = addr; pkt = NULL; ah = NULL; i = sendrecv(d, arpsend, &wbuf.data, sizeof (wbuf.data), arprecv, &pkt, (void **)&ah, NULL); if (i == -1) panic("arp: no response for %s", inet_ntoa(addr)); /* Store ethernet address in cache */ #ifdef ARP_DEBUG if (debug) { struct ether_header *eh; eh = (struct ether_header *)((uintptr_t)pkt + ETHER_ALIGN); printf("arp: response from %s\n", ether_sprintf(eh->ether_shost)); printf("arp: cacheing %s --> %s\n", inet_ntoa(addr), ether_sprintf(ah->arp_sha)); } #endif MACPY(ah->arp_sha, al->ea); ++arp_num; free(pkt); return (al->ea); }