/* Accept packet SKB received on an interface. */ void netif_rx (struct sk_buff *skb) { ipc_kmsg_t kmsg; struct ether_header *eh; struct packet_header *ph; struct linux_device *dev = skb->dev; assert (skb != NULL); if (print_packet_size) printf ("netif_rx: length %ld\n", skb->len); /* Allocate a kernel message buffer. */ kmsg = net_kmsg_get (); if (!kmsg) { dev_kfree_skb (skb, FREE_READ); return; } /* Copy packet into message buffer. */ eh = (struct ether_header *) (net_kmsg (kmsg)->header); ph = (struct packet_header *) (net_kmsg (kmsg)->packet); memcpy (eh, skb->data, sizeof (struct ether_header)); /* packet is prefixed with a struct packet_header, see include/device/net_status.h. */ memcpy (ph + 1, skb->data + sizeof (struct ether_header), skb->len - sizeof (struct ether_header)); ph->type = eh->ether_type; ph->length = (skb->len - sizeof (struct ether_header) + sizeof (struct packet_header)); dev_kfree_skb (skb, FREE_READ); net_kmsg(kmsg)->sent = FALSE; /* Mark packet as received. */ /* Pass packet up to the microkernel. */ net_packet (&dev->net_data->ifnet, kmsg, ph->length, ethernet_priority (kmsg)); }
void scerecv(sce_softc_t ssc, ipc_kmsg_t new_kmsg, vm_size_t size) { register struct ether_header *ehp, *ehp2; register struct packet_header *psce, *psce2; TR_DECL("scerecv"); tr2("size = 0x%x", size); ehp = (struct ether_header *)(&net_kmsg(new_kmsg)->header[0]); psce = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]); ehp2 = ((struct ether_header *)(&net_kmsg(new_kmsg)->packet[0])) - 1; psce2 = ((struct packet_header *)ehp2) + 1; bcopy((const char *)psce2, (char *)ehp, sizeof(struct ether_header)); psce->type = ehp->ether_type; psce->length = size - sizeof(struct ether_header) + sizeof(struct packet_header); net_packet(&ssc->sce_if, new_kmsg, psce->length, ethernet_priority(new_kmsg), (io_req_t)0); }
static io_return_t device_write (void *d, ipc_port_t reply_port, mach_msg_type_name_t reply_port_type, dev_mode_t mode, recnum_t bn, io_buf_ptr_t data, unsigned int count, int *bytes_written) { unsigned char *p; int i, amt, skblen, s; io_return_t err = 0; vm_map_copy_t copy = (vm_map_copy_t) data; struct net_data *nd = d; struct linux_device *dev = nd->dev; struct sk_buff *skb; if (count == 0 || count > dev->mtu + dev->hard_header_len) return D_INVALID_SIZE; /* Allocate a sk_buff. */ amt = PAGE_SIZE - (copy->offset & PAGE_MASK); skblen = (amt >= count) ? 0 : count; skb = dev_alloc_skb (skblen); if (!skb) return D_NO_MEMORY; /* Copy user data. This is only required if it spans multiple pages. */ if (skblen == 0) { assert (copy->cpy_npages == 1); skb->copy = copy; skb->data = ((void *) copy->cpy_page_list[0]->phys_addr + (copy->offset & PAGE_MASK)); skb->len = count; skb->head = skb->data; skb->tail = skb->data + skb->len; skb->end = skb->tail; } else { skb->len = skblen; skb->tail = skb->data + skblen; skb->end = skb->tail; memcpy (skb->data, ((void *) copy->cpy_page_list[0]->phys_addr + (copy->offset & PAGE_MASK)), amt); count -= amt; p = skb->data + amt; for (i = 1; count > 0 && i < copy->cpy_npages; i++) { amt = PAGE_SIZE; if (amt > count) amt = count; memcpy (p, (void *) copy->cpy_page_list[i]->phys_addr, amt); count -= amt; p += amt; } assert (count == 0); vm_map_copy_discard (copy); } skb->dev = dev; skb->reply = reply_port; skb->reply_type = reply_port_type; /* Queue packet for transmission and schedule a software interrupt. */ s = splimp (); if (dev->buffs[0].next != (struct sk_buff *) &dev->buffs[0] || (*dev->hard_start_xmit) (skb, dev)) { __skb_queue_tail (&dev->buffs[0], skb); mark_bh (NET_BH); } splx (s); /* Send packet to filters. */ { struct packet_header *packet; struct ether_header *header; ipc_kmsg_t kmsg; kmsg = net_kmsg_get (); if (kmsg != IKM_NULL) { /* Suitable for Ethernet only. */ header = (struct ether_header *) (net_kmsg (kmsg)->header); packet = (struct packet_header *) (net_kmsg (kmsg)->packet); memcpy (header, skb->data, sizeof (struct ether_header)); /* packet is prefixed with a struct packet_header, see include/device/net_status.h. */ memcpy (packet + 1, skb->data + sizeof (struct ether_header), skb->len - sizeof (struct ether_header)); packet->length = skb->len - sizeof (struct ether_header) + sizeof (struct packet_header); packet->type = header->ether_type; net_kmsg (kmsg)->sent = TRUE; /* Mark packet as sent. */ s = splimp (); net_packet (&dev->net_data->ifnet, kmsg, packet->length, ethernet_priority (kmsg)); splx (s); } } return MIG_NO_REPLY; }