Example #1
0
int ethernet_output(cbuf *buf, ifnet *i, netaddr *target, int protocol_type)
{
    cbuf *eheader_buf;
    ethernet2_header *eheader;
    //printf("eth out");
    if(target->type != ADDR_TYPE_ETHERNET) {
        cbuf_free_chain(buf);
        return ERR_INVALID_ARGS;
    }

    eheader_buf = cbuf_get_chain(sizeof(ethernet2_header));
    if(!eheader_buf) {
        dprintf("ethernet_output: error allocating cbuf for eheader\n");
        cbuf_free_chain(buf);
        return ERR_NO_MEMORY;
    }

    // put together an ethernet header
    eheader = (ethernet2_header *)cbuf_get_ptr(eheader_buf, 0);
    memcpy(&eheader->dest, &target->addr[0], 6);
    memcpy(&eheader->src, &i->link_addr->addr.addr[0], 6);
    eheader->type = htons(protocol_type);

    // chain the buffers together
    buf = cbuf_merge_chains(eheader_buf, buf);

    return if_output(buf, i);
}
Example #2
0
static void if_tx_thread(void *args)
{
    ifnet *i = args;
    cbuf *buf;
    ssize_t len;

    t_current_set_name("IF Xmit");

#if IF_PRIO
    thread_set_priority(i->tx_thread, THREAD_MAX_RT_PRIORITY - 2);
#endif
    //if(i->fd < 0)        return -1;


//printf("if %x tx thread inited", i);
    for(;;) {
        sem_acquire(i->tx_queue_sem);
//printf("if %x tx thread gogo\n", i);

        for(;;) {
            // pull a packet out of the queue
            mutex_lock(&i->tx_queue_lock);
            buf = fixed_queue_dequeue(&i->tx_queue);
            mutex_unlock(&i->tx_queue_lock);
            if(!buf)
                break;

#if LOSE_TX_PACKETS
            if(rand() % 100 < LOSE_TX_PERCENTAGE) {
                cbuf_free_chain(buf);
                continue;
            }
#endif

            // put the cbuf chain into a flat buffer
            len = cbuf_get_len(buf);
            cbuf_memcpy_from_chain(i->tx_buf, buf, 0, len);

            cbuf_free_chain(buf);

#if 0||NET_CHATTY
            dprintf("if_tx_thread: sending packet size %ld\n", (long)len);
#endif
            //sys_write(i->fd, i->tx_buf, 0, len);
            i->dev->dops.write(i->dev, i->tx_buf, len);
        }
    }
}
Example #3
0
int if_output(cbuf *b, ifnet *i)
{
    bool release_sem = false;
    bool enqueue_failed = false;
//printf("if out");

    // stick the buffer on a transmit queue
    mutex_lock(&i->tx_queue_lock);
    if(fixed_queue_enqueue(&i->tx_queue, b) < 0)
        enqueue_failed = true;
    if(i->tx_queue.count == 1)
        release_sem = true;
    mutex_unlock(&i->tx_queue_lock);

    if(enqueue_failed) {
        cbuf_free_chain(b);
        return ERR_NO_MEMORY;
    }

    if(release_sem)
        sem_release(i->tx_queue_sem);

//printf("if %x out ok\n", i);
    return NO_ERROR;
}
Example #4
0
int ethernet_input(cbuf *buf, ifnet *i)
{
    int err;
    ethernet2_header *e2_head;
    uint16 type;

    if(cbuf_get_len(buf) < MIN_ETHERNET2_LEN)
    {
        cbuf_free_chain(buf);
        return -1;
    }

    e2_head = cbuf_get_ptr(buf, 0);
    type = ntohs(e2_head->type);

    dump_ethernet_header(e2_head);

    // strip out the ethernet header
    buf = cbuf_truncate_head(buf, sizeof(ethernet2_header), true);

    switch(type) {
    case PROT_TYPE_IPV4:
        err = ipv4_input(buf, i);
        break;
    case PROT_TYPE_ARP:
        err = arp_input(buf, i);
        break;
    default:
        dprintf("ethernet_receive: unknown ethernet type 0x%x\n", type);
        err = -1;
    }

    return err;
}
Example #5
0
int
port_delete(port_id id)
{
	int slot;
	sem_id	r_sem, w_sem;
	int capacity;
	int i;

	char *old_name;
	struct port_msg *q;

	if(ports_active == false)
		return ERR_PORT_NOT_ACTIVE;
	if(id < 0)
		return ERR_INVALID_HANDLE;

	slot = id % MAX_PORTS;

	int_disable_interrupts();
	GRAB_PORT_LOCK(ports[slot]);

	if(ports[slot].id != id) {
		RELEASE_PORT_LOCK(ports[slot]);
		int_restore_interrupts();
		dprintf("port_delete: invalid port_id %d\n", id);
		return ERR_INVALID_HANDLE;
	}

	/* mark port as invalid */
	ports[slot].id	 = -1;
	old_name 		 = ports[slot].name;
	q				 = ports[slot].msg_queue;
	r_sem			 = ports[slot].read_sem;
	w_sem			 = ports[slot].write_sem;
	capacity		 = ports[slot].capacity;
	ports[slot].name = NULL;

	RELEASE_PORT_LOCK(ports[slot]);
	int_restore_interrupts();

	// delete the cbuf's that are left in the queue (if any)
	for (i=0; i<capacity; i++) {
		if (q[i].data_cbuf != NULL)
	 		cbuf_free_chain(q[i].data_cbuf);
	}

	kfree(q);
	kfree(old_name);

	// release the threads that were blocking on this port by deleting the sem
	// read_port() will see the ERR_SEM_DELETED acq_sem() return value, and act accordingly
	sem_delete(r_sem);
	sem_delete(w_sem);

	return NO_ERROR;
}
Example #6
0
File: if.c Project: HTshandou/newos
static int if_tx_thread(void *args)
{
	ifnet *i = args;
	cbuf *buf;
	ssize_t len;

	if(i->fd < 0)
		return -1;

	for(;;) {
 		sem_acquire(i->tx_queue_sem, 1);

		for(;;) {
	 		// pull a packet out of the queue
			mutex_lock(&i->tx_queue_lock);
			buf = fixed_queue_dequeue(&i->tx_queue);
			mutex_unlock(&i->tx_queue_lock);
			if(!buf)
				break;

#if LOSE_TX_PACKETS
			if(rand() % 100 < LOSE_TX_PERCENTAGE) {
				cbuf_free_chain(buf);
				continue;
			}
#endif

			// put the cbuf chain into a flat buffer
			len = cbuf_get_len(buf);
			cbuf_memcpy_from_chain(i->tx_buf, buf, 0, len);

			cbuf_free_chain(buf);

#if NET_CHATTY
		dprintf("if_tx_thread: sending packet size %Ld\n", (long long)len);
#endif
			sys_write(i->fd, i->tx_buf, 0, len);
		}
	}
}
Example #7
0
static void udp_endpoint_release_ref(udp_endpoint *e)
{
    if(atomic_add(&e->ref_count, -1) == 1) {
        udp_queue_elem *qe;

        mutex_destroy(&e->lock);
        sem_delete(e->blocking_sem);

        // clear out the queue of packets
        for(qe = udp_queue_pop(&e->q); qe; qe = udp_queue_pop(&e->q)) {
            if(qe->buf)
                cbuf_free_chain(qe->buf);
            kfree(qe);
        }
    }
}
Example #8
0
ssize_t
port_read_etc(port_id id,
				int32	*msg_code,
				void	*msg_buffer,
				size_t	buffer_size,
				uint32	flags,
				bigtime_t	timeout)
{
	int		slot;
	sem_id	cached_semid;
	size_t 	siz;
	int		res;
	int		t;
	cbuf*	msg_store;
	int32	code;
	int		err;

	if(ports_active == false)
		return ERR_PORT_NOT_ACTIVE;
	if(id < 0)
		return ERR_INVALID_HANDLE;
	if(msg_code == NULL)
		return ERR_INVALID_ARGS;
	if((msg_buffer == NULL) && (buffer_size > 0))
		return ERR_INVALID_ARGS;
	if (timeout < 0)
		return ERR_INVALID_ARGS;

	flags = flags & (PORT_FLAG_USE_USER_MEMCPY | PORT_FLAG_INTERRUPTABLE | PORT_FLAG_TIMEOUT);

	slot = id % MAX_PORTS;

	int_disable_interrupts();
	GRAB_PORT_LOCK(ports[slot]);

	if(ports[slot].id != id) {
		RELEASE_PORT_LOCK(ports[slot]);
		int_restore_interrupts();
		dprintf("read_port_etc: invalid port_id %d\n", id);
		return ERR_INVALID_HANDLE;
	}
	// store sem_id in local variable
	cached_semid = ports[slot].read_sem;

	// unlock port && enable ints/
	RELEASE_PORT_LOCK(ports[slot]);
	int_restore_interrupts();

	// XXX -> possible race condition if port gets deleted (->sem deleted too), therefore
	// sem_id is cached in local variable up here

	// get 1 entry from the queue, block if needed
	res = sem_acquire_etc(cached_semid, 1,
						flags, timeout, NULL);

	// XXX: possible race condition if port read by two threads...
	//      both threads will read in 2 different slots allocated above, simultaneously
	// 		slot is a thread-local variable

	if (res == ERR_SEM_DELETED) {
		// somebody deleted the port
		return ERR_PORT_DELETED;
	}

	if (res == ERR_INTERRUPTED) {
		// XXX: somebody signaled the process the port belonged to, deleting the sem ?
		return ERR_INTERRUPTED;
	}

	if (res == ERR_SEM_TIMED_OUT) {
		// timed out, or, if timeout=0, 'would block'
		return ERR_PORT_TIMED_OUT;
	}

	if (res != NO_ERROR) {
		dprintf("write_port_etc: res unknown error %d\n", res);
		return res;
	}

	int_disable_interrupts();
	GRAB_PORT_LOCK(ports[slot]);

	t = ports[slot].tail;
	if (t < 0)
		panic("port %id: tail < 0", ports[slot].id);
	if (t > ports[slot].capacity)
		panic("port %id: tail > cap %d", ports[slot].id, ports[slot].capacity);

	ports[slot].tail = (ports[slot].tail + 1) % ports[slot].capacity;

	msg_store	= ports[slot].msg_queue[t].data_cbuf;
	code 		= ports[slot].msg_queue[t].msg_code;

	// mark queue entry unused
	ports[slot].msg_queue[t].data_cbuf	= NULL;

	// check output buffer size
	siz	= min(buffer_size, ports[slot].msg_queue[t].data_len);

	cached_semid = ports[slot].write_sem;

	RELEASE_PORT_LOCK(ports[slot]);
	int_restore_interrupts();

	// copy message
	*msg_code = code;
	if (siz > 0) {
		if (flags & PORT_FLAG_USE_USER_MEMCPY) {
			if ((err = cbuf_user_memcpy_from_chain(msg_buffer, msg_store, 0, siz) < 0))	{
				// leave the port intact, for other threads that might not crash
				cbuf_free_chain(msg_store);
				sem_release(cached_semid, 1);
				return err;
			}
		} else
			cbuf_memcpy_from_chain(msg_buffer, msg_store, 0, siz);
	}
	// free the cbuf
	cbuf_free_chain(msg_store);

	// make one spot in queue available again for write
	sem_release(cached_semid, 1);

	return siz;
}
Example #9
0
ssize_t udp_sendto(void *prot_data, const void *inbuf, ssize_t len, i4sockaddr *toaddr)
{
    udp_endpoint *e = prot_data;
    udp_header *header;
    int total_len;
    cbuf *buf;
    udp_pseudo_header pheader;
    ipv4_addr srcaddr;
    int err;

    // make sure the args make sense
    if(len < 0 || len + sizeof(udp_header) > 0xffff)
        return ERR_INVALID_ARGS;
    if(toaddr->port < 0 || toaddr->port > 0xffff)
        return ERR_INVALID_ARGS;

    // allocate a buffer to hold the data + header
    total_len = len + sizeof(udp_header);
    buf = cbuf_get_chain(total_len);
    if(!buf)
        return ERR_NO_MEMORY;

    // copy the data to this new buffer
    //err = cbuf_user_memcpy_to_chain(buf, sizeof(udp_header), inbuf, len);
    err = cbuf_memcpy_to_chain(buf, sizeof(udp_header), inbuf, len);
    if(err < 0) {
        cbuf_free_chain(buf);
        return ERR_VM_BAD_USER_MEMORY;
    }

    // set up the udp pseudo header
    if(ipv4_lookup_srcaddr_for_dest(NETADDR_TO_IPV4(toaddr->addr), &srcaddr) < 0) {
        cbuf_free_chain(buf);
        return ERR_NET_NO_ROUTE;
    }
    pheader.source_addr = htonl(srcaddr);
    pheader.dest_addr = htonl(NETADDR_TO_IPV4(toaddr->addr));
    pheader.zero = 0;
    pheader.protocol = IP_PROT_UDP;
    pheader.udp_length = htons(total_len);

    // start setting up the header
    header = cbuf_get_ptr(buf, 0);
    header->source_port = htons(e->port);
    header->dest_port = htons(toaddr->port);
    header->length = htons(total_len);
    header->checksum = 0;
    header->checksum = cbuf_ones_cksum16_2(buf, 0, total_len, &pheader, sizeof(pheader));
    if(header->checksum == 0)
        header->checksum = 0xffff;

#if NET_CHATTY
    printf("UDP SEND port %d to %d, len %d (%d)\n", e->port, toaddr->port, total_len, len );
#endif
    // send it away
    err = ipv4_output(buf, NETADDR_TO_IPV4(toaddr->addr), IP_PROT_UDP);

    STAT_INC_CNT(STAT_CNT_UDP_TX);

    // if it returns ARP_QUEUED, then it's actually okay
    if(err == ERR_NET_ARP_QUEUED) {
        err = 0;
    }

    return err;
}
Example #10
0
ssize_t udp_recvfrom(
                     void *prot_data,
                     void *buf, ssize_t len,
                     i4sockaddr *saddr,
                     int flags, bigtime_t timeout)
{
    udp_endpoint *e = prot_data;
    udp_queue_elem *qe;
    int err;
    ssize_t ret;

retry:
//#warning timeout ignored
#if 1
    if(flags & SOCK_FLAG_TIMEOUT)
        err = hal_sem_acquire_etc( &e->blocking_sem, 1, SEM_FLAG_TIMEOUT, timeout );
    else
#endif
        err = sem_acquire(e->blocking_sem);

    //if(err < 0)
    if(err)
        return -err;

    // pop an item off the list, if there are any
    mutex_lock(&e->lock);
    qe = udp_queue_pop(&e->q);
    mutex_unlock(&e->lock);

    if(!qe)
    {
#if 1||NET_CHATTY
        printf("UDP read retry");
#endif
        goto retry;
    }

    // we have the data, copy it out
    //err = cbuf_user_memcpy_from_chain(buf, qe->buf, 0, min(qe->len, len));
    err = cbuf_memcpy_from_chain(buf, qe->buf, 0, min(qe->len, len));
    if(err < 0) {
        ret = err;
        goto out;
    }
    ret = qe->len;

    // copy the address out
    if(saddr) {
        saddr->addr.len = 4;
        saddr->addr.type = ADDR_TYPE_IP;
        NETADDR_TO_IPV4(saddr->addr) = qe->src_address;
        saddr->port = qe->src_port;
    }

out:
    // free this queue entry
    cbuf_free_chain(qe->buf);
    kfree(qe);

    return ret;
}
Example #11
0
int udp_input(cbuf *buf, ifnet *i, ipv4_addr source_address, ipv4_addr target_address)
{
    (void) i;

    udp_header *header;
    udp_endpoint *e;
    udp_queue_elem *qe;
    uint16 port;
    int err;

    STAT_INC_CNT(STAT_CNT_UDP_RX);

    header = cbuf_get_ptr(buf, 0);

#if NET_CHATTY
    dprintf("udp_input: src port %d, dest port %d, len %d, buf len %d, checksum 0x%x\n",
            ntohs(header->source_port), ntohs(header->dest_port), ntohs(header->length), (int)cbuf_get_len(buf), ntohs(header->checksum));
#endif
    if(ntohs(header->length) > (uint16)cbuf_get_len(buf)) {
        err = ERR_NET_BAD_PACKET;
        goto ditch_packet;
    }

    // deal with the checksum check
    if(header->checksum) {
        udp_pseudo_header pheader;
        uint16 checksum;

        // set up the pseudo header for checksum purposes
        pheader.source_addr = htonl(source_address);
        pheader.dest_addr = htonl(target_address);
        pheader.zero = 0;
        pheader.protocol = IP_PROT_UDP;
        pheader.udp_length = header->length;

        checksum = cbuf_ones_cksum16_2(buf, 0, ntohs(header->length), &pheader, sizeof(pheader));
        if(checksum != 0) {
#if NET_CHATTY
            dprintf("udp_receive: packet failed checksum\n");
#endif
            err = ERR_NET_BAD_PACKET;
            goto ditch_packet;
        }
    }

    // see if we have an endpoint
    port = ntohs(header->dest_port);
    mutex_lock(&endpoints_lock);
    e = hash_lookup(endpoints, &port);
    if(e)
        udp_endpoint_acquire_ref(e);
    mutex_unlock(&endpoints_lock);

    if(!e) {
        err = NO_ERROR;
#if NET_CHATTY
        dprintf("udp_receive: no endpoint found\n");
#endif
        goto ditch_packet;
    }

    // okay, we have an endpoint, lets queue our stuff up and move on
    qe = kmalloc(sizeof(udp_queue_elem));
    if(!qe) {
        udp_endpoint_release_ref(e);
        err = ERR_NO_MEMORY;
        goto ditch_packet;
    }
    qe->src_port = ntohs(header->source_port);
    qe->target_port = port;
    qe->src_address = source_address;
    qe->target_address = target_address;
    qe->len = ntohs(header->length) - sizeof(udp_header);

    // trim off the udp header
    buf = cbuf_truncate_head(buf, sizeof(udp_header), true);
    qe->buf = buf;

    mutex_lock(&e->lock);
    udp_queue_push(&e->q, qe);
    mutex_unlock(&e->lock);

    sem_release(e->blocking_sem);

    udp_endpoint_release_ref(e);

    err = NO_ERROR;
    return err;

ditch_packet:
#if NET_CHATTY
    dprintf("udp_receive: packet thrown away\n");
#endif
    cbuf_free_chain(buf);

    return err;
}