static int send_request(struct net_device *dev, uint16_t pro, uint8_t pln, const void *spa, const void *tpa) { int ret; struct sk_buff *skb; struct net_header_info hdr_info; skb = skb_alloc(dev->hdr_len + ARP_CALC_HEADER_SIZE(dev->addr_len, pln)); if (skb == NULL) { return -ENOMEM; } skb->dev = dev; skb->nh.raw = skb->mac.raw + dev->hdr_len; hdr_info.type = ETH_P_ARP; hdr_info.src_hw = &dev->dev_addr[0]; hdr_info.dst_hw = &dev->broadcast[0]; assert(dev->ops != NULL); assert(dev->ops->build_hdr != NULL); ret = dev->ops->build_hdr(skb, &hdr_info); if (ret != 0) { skb_free(skb); return ret; } arp_build(arp_hdr(skb), dev->type, pro, dev->addr_len, pln, ARP_OP_REQUEST, &dev->dev_addr[0], spa, &dev->broadcast[0], tpa); return net_tx(skb, NULL); }
void process_icmp(ether_header_t *ether, ip_header_t *ip, icmp_header_t *icmp) { unsigned int i; unsigned char tmp[6]; memset(pkt_buf, 0, ntohs(ip->length) + (ntohs(ip->length)%2) - 4*(ip->version_ihl & 0x0f)); /* check icmp checksum */ i = icmp->checksum; icmp->checksum = 0; memcpy(pkt_buf, icmp, ntohs(ip->length) - 4*(ip->version_ihl & 0x0f)); icmp->checksum = checksum((unsigned short *)pkt_buf, (ntohs(ip->length)+1)/2 - 2*(ip->version_ihl & 0x0f)); if (i != icmp->checksum) return; if (icmp->type == 8) { /* echo request */ icmp->type = 0; /* echo reply */ /* swap src and dest hw addresses */ memcpy(tmp, ether->dest, 6); memcpy(ether->dest, ether->src, 6); memcpy(ether->src, tmp, 6); /* swap src and dest ip addresses */ memcpy(&i, &ip->src, 4); memcpy(&ip->src, &ip->dest, 4); memcpy(&ip->dest, &i, 4); /* recompute ip header checksum */ ip->checksum = 0; ip->checksum = checksum((unsigned short *)ip, 2*(ip->version_ihl & 0x0f)); /* recompute icmp checksum */ icmp->checksum = 0; icmp->checksum = checksum((unsigned short *)icmp, ntohs(ip->length)/2 - 2*(ip->version_ihl & 0x0f)); /* transmit */ net_tx(ether, ETHER_H_LEN + ntohs(ip->length), 1); } }
int process_broadcast(unsigned char *pkt, int len) { ether_header_t *ether_header = (ether_header_t *)pkt; arp_header_t *arp_header = (arp_header_t *)(pkt + ETHER_H_LEN); unsigned char tmp[10]; unsigned int ip = htonl(our_ip); if (ether_header->type[1] != 0x06) /* ARP */ { return -1; } /* hardware address space = ethernet */ if (arp_header->hw_addr_space != 0x0100) return -1; /* protocol address space = IP */ if (arp_header->proto_addr_space != 0x0008) return -1; if (arp_header->opcode == 0x0100) { /* arp request */ if (our_ip == 0) /* return if we don't know our ip */ return -1; int i; /* printf("ARP request : "); */ /* for (i=0; i<4; i++) */ /* printf("%d ", arp_header->proto_target[i]); */ /* printf("\n"); */ if (!memcmp(arp_header->proto_target, &ip, 4)) { /* for us */ /* printf("ARP our IP : %x\n", ip); */ /* put src hw address into dest hw address */ memcpy(ether_header->dest, ether_header->src, 6); /* put our hw address into src hw address */ memcpy(ether_header->src, eth_mac, 6); arp_header->opcode = 0x0200; /* arp reply */ /* swap sender and target addresses */ memcpy(tmp, arp_header->hw_sender, 10); memcpy(arp_header->hw_sender, arp_header->hw_target, 10); memcpy(arp_header->hw_target, tmp, 10); /* put our hw address into sender hw address */ memcpy(arp_header->hw_sender, eth_mac, 6); /* transmit */ net_tx(pkt, ETHER_H_LEN + ARP_H_LEN, 1); } } return 0; }
static int ndp_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_header_info hdr_info; assert(skb != NULL); assert(dev != NULL); hdr_info.type = ETH_P_IPV6; hdr_info.src_hw = dev->dev_addr; hdr_info.dst_hw = dev->broadcast; return net_tx(skb, &hdr_info); }
/** * Look up media-specific link-layer address in the ARP cache * * @v netdev Network device * @v net_protocol Network-layer protocol * @v dest_net_addr Destination network-layer address * @v source_net_addr Source network-layer address * @ret dest_ll_addr Destination link layer address * @ret rc Return status code * * This function will use the ARP cache to look up the link-layer * address for the link-layer protocol associated with the network * device and the given network-layer protocol and addresses. If * found, the destination link-layer address will be filled in in @c * dest_ll_addr. * * If no address is found in the ARP cache, an ARP request will be * transmitted on the specified network device and -ENOENT will be * returned. */ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, const void *dest_net_addr, const void *source_net_addr, void *dest_ll_addr ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; const struct arp_entry *arp; struct io_buffer *iobuf; struct arphdr *arphdr; int rc; /* Look for existing entry in ARP table */ arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr ); if ( arp ) { DBG ( "ARP cache hit: %s %s => %s %s\n", net_protocol->name, net_protocol->ntoa ( arp->net_addr ), ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len); return 0; } DBG ( "ARP cache miss: %s %s\n", net_protocol->name, net_protocol->ntoa ( dest_net_addr ) ); /* Allocate ARP packet */ iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) + 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ); if ( ! iobuf ) return -ENOMEM; iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); /* Build up ARP request */ arphdr = iob_put ( iobuf, sizeof ( *arphdr ) ); arphdr->ar_hrd = ll_protocol->ll_proto; arphdr->ar_hln = ll_protocol->ll_addr_len; arphdr->ar_pro = net_protocol->net_proto; arphdr->ar_pln = net_protocol->net_addr_len; arphdr->ar_op = htons ( ARPOP_REQUEST ); memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ), netdev->ll_addr, ll_protocol->ll_addr_len ); memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), source_net_addr, net_protocol->net_addr_len ); memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ), 0, ll_protocol->ll_addr_len ); memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), dest_net_addr, net_protocol->net_addr_len ); /* Transmit ARP request */ if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol, netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) return rc; return -ENOENT; }
static int eth_txts(uint8 *pkt, int len) { int res; int oldirq; for( ; ; ) { if (!irq_inside_int()) tx_lock(); #if 0 STOPIRQ; while (bba_dma_busy) { STARTIRQ; thd_pass(); STOPIRQ; } #endif #ifdef NICE res = net_tx(pkt, len, irq_inside_int()); #else res = net_tx(pkt, len, 1); #endif #if 0 STARTIRQ; #endif if (!irq_inside_int()) tx_unlock(); if (!res || irq_inside_int()) break; thd_pass(); } return res; }
/** * Process incoming marker packet * * @v iobuf I/O buffer * @v netdev Network device * @ret rc Return status code */ static int eth_slow_marker_rx ( struct io_buffer *iobuf, struct net_device *netdev ) { union eth_slow_packet *eth_slow = iobuf->data; struct eth_slow_marker *marker = ð_slow->marker; eth_slow_marker_dump ( iobuf, netdev, "RX" ); if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) { /* Send marker response */ marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE; eth_slow_marker_dump ( iobuf, netdev, "TX" ); return net_tx ( iobuf, netdev, ð_slow_protocol, eth_slow_address, netdev->ll_addr ); } else { /* Discard all other marker packets */ free_iob ( iobuf ); return -EINVAL; } }
static int eth_txts(uint8 *pkt, int len) { int res; for( ; ; ) { if (!irq_inside_int()) tx_lock(); res = net_tx(pkt, len, irq_inside_int()); if (!irq_inside_int()) tx_unlock(); if (!res || irq_inside_int()) break; thd_pass(); } return res; }
int driver_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = (struct net_device_stats*) netdev_priv(dev); int len = skb->len; void* addr = skb->data; /* transmit to nic-session */ while (net_tx(addr, len)) { /* tx queue is full, could not enqueue packet */ printk("TX full\n"); } dev_kfree_skb(skb); /* save timestamp */ dev->trans_start = jiffies; stats->tx_packets++; stats->tx_bytes += len; return NETDEV_TX_OK; }
/** * Process incoming LACP packet * * @v iobuf I/O buffer * @v netdev Network device * @ret rc Return status code */ static int eth_slow_lacp_rx ( struct io_buffer *iobuf, struct net_device *netdev ) { union eth_slow_packet *eth_slow = iobuf->data; struct eth_slow_lacp *lacp = ð_slow->lacp; eth_slow_lacp_dump ( iobuf, netdev, "RX" ); /* Build response */ memset ( lacp->reserved, 0, sizeof ( lacp->reserved ) ); memset ( &lacp->terminator, 0, sizeof ( lacp->terminator ) ); memset ( &lacp->collector, 0, sizeof ( lacp->collector ) ); lacp->collector.tlv.type = ETH_SLOW_TLV_LACP_COLLECTOR; lacp->collector.tlv.length = ETH_SLOW_TLV_LACP_COLLECTOR_LEN; memcpy ( &lacp->partner, &lacp->actor, sizeof ( lacp->partner ) ); lacp->partner.tlv.type = ETH_SLOW_TLV_LACP_PARTNER; lacp->partner.tlv.length = ETH_SLOW_TLV_LACP_PARTNER_LEN; memset ( &lacp->partner.reserved, 0, sizeof ( lacp->partner.reserved ) ); memset ( &lacp->actor, 0, sizeof ( lacp->actor ) ); lacp->actor.tlv.type = ETH_SLOW_TLV_LACP_ACTOR; lacp->actor.tlv.length = ETH_SLOW_TLV_LACP_ACTOR_LEN; lacp->actor.system_priority = htons ( LACP_SYSTEM_PRIORITY_MAX ); memcpy ( lacp->actor.system, netdev->ll_addr, sizeof ( lacp->actor.system ) ); lacp->actor.key = htons ( 1 ); lacp->actor.port_priority = htons ( LACP_PORT_PRIORITY_MAX ); lacp->actor.port = htons ( 1 ); lacp->actor.state = ( LACP_STATE_IN_SYNC | LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING | ( lacp->partner.state & LACP_STATE_FAST ) ); lacp->header.version = ETH_SLOW_LACP_VERSION; /* Send response */ eth_slow_lacp_dump ( iobuf, netdev, "TX" ); return net_tx ( iobuf, netdev, ð_slow_protocol, eth_slow_address, netdev->ll_addr ); }
static int ip6_xmit(struct sk_buff *skb) { const struct in6_addr *daddr; struct net_header_info hdr_info; assert(skb != NULL); assert(skb->nh.iph != NULL); daddr = &skb->nh.ip6h->daddr; hdr_info.type = ETH_P_IPV6; hdr_info.src_hw = NULL; hdr_info.dst_hw = NULL; /* FIXME */ assert(skb->dev != NULL); if (skb->dev->flags & IFF_LOOPBACK) { hdr_info.dst_p = NULL; } else { hdr_info.dst_p = daddr; hdr_info.p_len = sizeof *daddr; } return net_tx(skb, &hdr_info); }
/** * Send AoE command * * @v aoe AoE session * @ret rc Return status code * * This transmits an AoE command packet. It does not wait for a * response. */ static int aoe_send_command ( struct aoe_session *aoe ) { struct ata_command *command = aoe->command; struct io_buffer *iobuf; struct aoehdr *aoehdr; union aoecmd *aoecmd; struct aoeata *aoeata; unsigned int count; unsigned int data_out_len; unsigned int aoecmdlen; /* Fail immediately if we have no netdev to send on */ if ( ! aoe->netdev ) { aoe_done ( aoe, -ENETUNREACH ); return -ENETUNREACH; } /* If we are transmitting anything that requires a response, * start the retransmission timer. Do this before attempting * to allocate the I/O buffer, in case allocation itself * fails. */ start_timer ( &aoe->timer ); /* Calculate count and data_out_len for this subcommand */ switch ( aoe->aoe_cmd_type ) { case AOE_CMD_ATA: count = command->cb.count.native; if ( count > AOE_MAX_COUNT ) count = AOE_MAX_COUNT; data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 ); aoecmdlen = sizeof ( aoecmd->ata ); break; case AOE_CMD_CONFIG: count = 0; data_out_len = 0; aoecmdlen = sizeof ( aoecmd->cfg ); break; default: return -ENOTSUP; } /* Create outgoing I/O buffer */ iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + aoecmdlen + data_out_len ); if ( ! iobuf ) return -ENOMEM; iob_reserve ( iobuf, ETH_HLEN ); aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) ); aoecmd = iob_put ( iobuf, aoecmdlen ); memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) ); /* Fill AoE header */ aoehdr->ver_flags = AOE_VERSION; aoehdr->major = htons ( aoe->major ); aoehdr->minor = aoe->minor; aoehdr->command = aoe->aoe_cmd_type; aoehdr->tag = htonl ( ++aoe->tag ); /* Fill AoE payload */ switch ( aoe->aoe_cmd_type ) { case AOE_CMD_ATA: /* Fill AoE command */ aoeata = &aoecmd->ata; linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ ); aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )| ( command->cb.device & ATA_DEV_SLAVE ) | ( data_out_len ? AOE_FL_WRITE : 0 ) ); aoeata->err_feat = command->cb.err_feat.bytes.cur; aoeata->count = count; aoeata->cmd_stat = command->cb.cmd_stat; aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native ); if ( ! command->cb.lba48 ) aoeata->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK ); /* Fill data payload */ copy_from_user ( iob_put ( iobuf, data_out_len ), command->data_out, aoe->command_offset, data_out_len ); break; case AOE_CMD_CONFIG: /* Nothing to do */ break; default: assert ( 0 ); } /* Send packet */ return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target ); }