/*------------------------------------------------------------------------
 *  udpnet2h -  convert UDP header fields from net to host byte order
 *------------------------------------------------------------------------
 */
void
udpnet2h(struct udp *pudp)
{
	pudp->u_src = net2hs(pudp->u_src);
	pudp->u_dst = net2hs(pudp->u_dst);
	pudp->u_len = net2hs(pudp->u_len);
}
Example #2
0
/*------------------------------------------------------------------------
 *  ipnet2h - convert an IP packet header from net to host byte order
 *------------------------------------------------------------------------
 */
struct ip *
ipnet2h(struct ip *pip)
{
	/* NOTE: does not include IP options	*/

	pip->ip_len = net2hs(pip->ip_len);
	pip->ip_id = net2hs(pip->ip_id);
	pip->ip_fragoff = net2hs(pip->ip_fragoff);
	return pip;
}
Example #3
0
//------------------------------------------------------------------------
//  rarp_in  -  handle RARP packet coming in from Ethernet network
//------------------------------------------------------------------------
int
rarp_in(struct epacket *packet, int dev)
{
	int ps;
	int pid;
	int ret;
	struct arppak *apacptr;
	struct etblk *etptr;

	apacptr = (struct arppak *)packet->ep_data;
	ret = SYSERR;
	if (net2hs(apacptr->ar_op) == AR_RRLY) {
		etptr = (struct etblk *)devtab[dev].iobuf;
		if (memcmp(apacptr->ar_tha, etptr->etpaddr, EPADLEN) == 0) {
			memmove(Net.myaddr, apacptr->ar_tpa, IPLEN);
			netnum(Net.mynet, Net.myaddr);
			ps = disable();
			Net.mavalid = TRUE;
			pid = Arp.rarppid;
			if (!isbadpid(pid)) {
				Arp.rarppid = BADPID;
				send(pid, OK);
			}
			restore(ps);
		}
		ret = OK;
	}
	freebuf(packet);

	return ret;
}
/*------------------------------------------------------------------------
 *  tcpsmss - set sender MSS from option in incoming segment
 *------------------------------------------------------------------------
 */
int
tcpsmss(struct tcb *ptcb, struct tcp *ptcp, u_char *popt)
{
	unsigned	mss, len;

	len = *++popt;
	++popt;		/* skip length field */
	if ((ptcp->tcp_code & TCPF_SYN) == 0)
		return len;
	switch (len-2) {	/* subtract kind & len	*/
	case sizeof(char):
		mss = *popt;
		break;
	case sizeof(short):
		mss = net2hs(*(unsigned short *)popt);
		break;
	case sizeof(long):
		mss = net2hl(*(unsigned long *)popt);
		break;
	default:
		mss = ptcb->tcb_smss;
		break;
	}
	mss -= TCPMHLEN;	/* save just the data buffer size */
	if (ptcb->tcb_smss)
		ptcb->tcb_smss = min(mss, ptcb->tcb_smss);
	else
		ptcb->tcb_smss = mss;
	return len;
}
Example #5
0
/**
 * Send an ICMP Echo (Ping) Request.
 * @param dst destination address
 * @param id  ping stream identifier
 * @param seq sequence number
 * @return OK if packet was sent, otherwise SYSERR
 */
syscall icmpEchoRequest(struct netaddr *dst, ushort id, ushort seq)
{
    struct packet *pkt = NULL;
    struct icmpEcho *echo = NULL;
    int result = OK;
    irqmask im;

    ICMP_TRACE("echo request(%d, %d)", id, seq);
    pkt = netGetbuf();
    if (SYSERR == (int)pkt)
    {
        ICMP_TRACE("Failed to acquire packet buffer");
        return SYSERR;
    }

    pkt->len = sizeof(struct icmpEcho);
    pkt->curr -= pkt->len;

    echo = (struct icmpEcho *)pkt->curr;
    echo->id = hs2net(id);
    echo->seq = hs2net(seq);
    /* Our optional data payload includes room for the departure */
    /*  and arrival timestamps, in seconds, milliseconds, and    */
    /*  clock cycles.                                            */
    im = disable();
    echo->timecyc = hl2net(clkcount());
    echo->timetic = hl2net(clkticks);
    echo->timesec = hl2net(clktime);
    restore(im);
    echo->arrivcyc = 0;
    echo->arrivtic = 0;
    echo->arrivsec = 0;

    ICMP_TRACE("Sending Echo Request id = %d, seq = %d, time = %d.%d",
               net2hs(echo->id), net2hs(echo->seq),
               net2hl(echo->timesec), net2hl(echo->timetic));

    result = icmpSend(pkt, ICMP_ECHO, 0, sizeof(struct icmpEcho), dst);
    netFreebuf(pkt);
    return result;
}
Example #6
0
/*------------------------------------------------------------------------
 *  ospfcheck - check if a packet is a valid OSPF packet
 *------------------------------------------------------------------------
 */
int
ospfcheck(struct ep *pep)
{
	struct	ip	*pip = (struct ip *)pep->ep_data;
	struct	ospf	*po = (struct ospf *)((char *)pip + IP_HLEN(pip));
	struct	ospf_if	*pif = &ospf_if[pep->ep_ifn];

	if (pif->if_state == IFS_DOWN)
		return FALSE;
	if (po->ospf_version != OSPF_VERSION)
		return FALSE;
	if (net2hs(po->ospf_authtype) != pif->if_area->ar_authtype)
		return FALSE;
	if (pif->if_area->ar_authtype &&
	    memcmp(po->ospf_auth, pif->if_area->ar_auth, AUTHLEN))
		return FALSE;
	memset(po->ospf_auth, 0, AUTHLEN);
	if (cksum((WORD *)po, net2hs(po->ospf_len)))
		return FALSE;
	return TRUE;
}
Example #7
0
/**
 * Print out a echo reply packet.
 */
static void echoPrintPkt(struct packet *pkt, ulong elapsed)
{
    struct icmpPkt *icmp = NULL;
    struct icmpEcho *echo = NULL;
    struct ipv4Pkt *ip = NULL;
    struct netaddr src;
    char str[50];

    ip = (struct ipv4Pkt *)pkt->nethdr;
    icmp = (struct icmpPkt *)pkt->curr;
    echo = (struct icmpEcho *)icmp->data;

    src.type = NETADDR_IPv4;
    src.len = IPv4_ADDR_LEN;
    memcpy(src.addr, ip->src, src.len);

    netaddrsprintf(str, &src);
    printf("%d bytes from %s: ", net2hs(ip->len), str);
    printf("icmp_seq=%d ttl=%d ", net2hs(echo->seq), ip->ttl);
    printf("time=%d.%03d ms\n", elapsed / 1000, elapsed % 1000);
}
Example #8
0
/**
 * Print contents of Ethernet packet
 * @param ether Ethernet packet
 * @return OK if print successful, SYSERR if error occurs
 */
int snoopPrintEthernet(struct etherPkt *ether, char verbose)
{
    char output[40];
    struct netaddr hwaddr;

    /* Error check pointer */
    if (NULL == ether)
    {
        return SYSERR;
    }

    if (verbose >= SNOOP_VERBOSE_TWO)
    {
        /* Print ethernet header */
        printf(" ----- Ethernet Header -----\n", "");
        hwaddr.type = NETADDR_ETHERNET;
        hwaddr.len = ETH_ADDR_LEN;
        memcpy(hwaddr.addr, ether->dst, hwaddr.len);
        netaddrsprintf(output, &hwaddr);
        printf("  Dst: %-25s ", output);
        memcpy(hwaddr.addr, ether->src, hwaddr.len);
        netaddrsprintf(output, &hwaddr);
        printf("Src: %-25s ", output);
        switch (net2hs(ether->type))
        {
        case ETHER_TYPE_IPv4:
            sprintf(output, "IP");
            break;
        case ETHER_TYPE_ARP:
            sprintf(output, "ARP");
            break;
        default:
            sprintf(output, "0x%04X", net2hs(ether->type));
            break;
        }
        printf("Type: %-5s\n", output);
    }

    return OK;
}
Example #9
0
static void snoopPrintTcpPort(ushort port, char *descrp)
{
    switch (net2hs(port))
    {
    case TCP_PORT_HTTP:
        sprintf(descrp, "(HTTP)");
        break;
    case TCP_PORT_TELNET:
        sprintf(descrp, "(Telnet)");
        break;
    default:
        sprintf(descrp, "");
        break;
    }
}
Example #10
0
//------------------------------------------------------------------------
//  ip_in  -  handle IP packet coming in from the network
//------------------------------------------------------------------------
int
ip_in(struct epacket *packet, int icmpp, int lim)
{
	struct udp *udpptr;
	struct ip *ipptr;
	struct netq *nqptr;
	int dport;
	int i;
	int to;
	int ps;

	ipptr = (struct ip *)packet->ep_data;
	switch (ipptr->i_proto) {
	case IPRO_ICMP:	// ICMP: pass to icmp input routine
		return icmp_in(packet, icmpp, lim);
	case IPRO_UDP:		// UDP: demultiplex based on UDP "port"
		udpptr = (struct udp *)ipptr->i_data;
		dport = net2hs(udpptr->u_dport);
		for (i = 0; i < NETQS; i++) {
			nqptr = &Net.netqs[i];
			if (nqptr->uport == dport) {
				// drop instead of blocking on psend
				if (pcount(nqptr->xport) >= NETQLEN) {
					Net.ndrop++;
					Net.nover++;
					freebuf(packet);
					return SYSERR;
				}
				psend(nqptr->xport, (uword)packet);
				ps = disable();
				to = nqptr->pid;
				if (!isbadpid(to)) {
					nqptr->pid = BADPID;
					send(to, OK);
				}
				restore(ps);
				return OK;
			}
		}
		break;
	default:
		break;
	}
	Net.ndrop++;
	freebuf(packet);

	return OK;
}
Example #11
0
//------------------------------------------------------------------------
//  netout  -  start network by finding address and forward IP packets
//------------------------------------------------------------------------
PROCESS
netout(int userpid, int icmpp)
{
	struct epacket *packet;
	struct ip *ipptr;
	long tim;
	int len;
	char name[MNAMELEN];
	IPaddr addr;

	getaddr(addr);
	gettime(&tim);
	getname(name, MNAMELEN);
	resume(userpid);
	while (TRUE) {
		packet = (struct epacket *)preceive(icmpp);
		ipptr = (struct ip *)packet->ep_data;
		memmove(addr, ipptr->i_dest, IPLEN);
		len = net2hs(ipptr->i_paclen) - IPHLEN;
		ipsend(addr, packet, len);
	}
}
Example #12
0
/**
 * Receive a UDP packet and place it in the UDP device's input buffer
 * @param pkt Incoming UDP packet
 * @param src Source address
 * @param dst Destination address
 * @return OK if UDP packet is received properly, otherwise SYSERR
 */
syscall udpRecv(struct packet *pkt, struct netaddr *src,
                struct netaddr *dst)
{
    struct udpPkt *udppkt;
    struct udp *udpptr;
    struct udpPkt *tpkt;
#ifdef TRACE_UDP
    char strA[20];
    char strB[20];
#endif                          /* TRACE_UDP */

    irqmask im;

    /* Point to the start of the UDP header */
    udppkt = (struct udpPkt *)pkt->curr;

    if (NULL == udppkt)
    {
        UDP_TRACE("Invalid UDP packet.");
        netFreebuf(pkt);
        return SYSERR;
    }

    /* Calculate checksum */
    if (0 != udpChksum(pkt, net2hs(udppkt->len), src, dst))
    {
        UDP_TRACE("Invalid UDP checksum.");
        netFreebuf(pkt);
        return SYSERR;
    }

    /* Convert UDP header fields to host order */
    udppkt->srcPort = net2hs(udppkt->srcPort);
    udppkt->dstPort = net2hs(udppkt->dstPort);
    udppkt->len = net2hs(udppkt->len);

    im = disable();

    /* Locate the UDP socket (device) for the UDP packet */
    udpptr = udpDemux(udppkt->dstPort, udppkt->srcPort, dst, src);

    if (NULL == udpptr)
    {
#ifdef TRACE_UDP
        UDP_TRACE("No UDP socket found for this UDP packet.");
        netaddrsprintf(strA, src);
        netaddrsprintf(strB, dst);
        UDP_TRACE("Source: %s:%d, Destination: %s:%d", strA,
                  udppkt->srcPort, strB, udppkt->dstPort);
#endif                          /* TRACE_UDP */
        restore(im);
        /* Send ICMP port unreachable message */
        icmpDestUnreach(pkt, ICMP_PORT_UNR);
        netFreebuf(pkt);
        return SYSERR;
    }
    if (udpptr->icount >= UDP_MAX_PKTS)
    {
        UDP_TRACE("UDP buffer is full. Dropping UDP packet.");
        restore(im);
        netFreebuf(pkt);
        return SYSERR;
    }

    /* Check "bind first" flag and update connection if set,
     * and clear the flag */
    if (UDP_FLAG_BINDFIRST & udpptr->flags)
    {
        udpptr->remotept = udppkt->srcPort;
        netaddrcpy(&(udpptr->localip), dst);
        netaddrcpy(&(udpptr->remoteip), src);
        udpptr->flags &= ~UDP_FLAG_BINDFIRST;
    }

    /* Get some buffer space to store the packet */
    tpkt = udpGetbuf(udpptr);

    if (SYSERR == (int)tpkt)
    {
        UDP_TRACE("Unable to get UDP buffer from pool. Dropping packet.");
        netFreebuf(pkt);
        return SYSERR;
    }

    /* Copy the data of the packet into the input buffer at the current 
     * position */
    memcpy(tpkt, udppkt, udppkt->len);

    /* Store the temporary UDP packet in a FIFO buffer */
    udpptr->in[(udpptr->istart + udpptr->icount) % UDP_MAX_PKTS] = tpkt;
    udpptr->icount++;

    restore(im);

    signal(udpptr->isem);

    netFreebuf(pkt);

    return OK;
}
/*------------------------------------------------------------------------
 *  ip2name  -  return DNS name for a host given its IP address
 *------------------------------------------------------------------------
 */
char	*
ip2name(IPaddr ip, char *nam)
{
	char	tmpstr[20];		/* temporary string buffer	*/
	char	*buf;			/* buffer to hold domain query	*/
	int	dg, i;
	register char	*p;
	register struct	dn_mesg *dnptr;

	dnptr = (struct dn_mesg *) (buf = (char *) getmem(DN_MLEN));
	*nam = NULLCH;
	dnptr->dn_id = 0;
	dnptr->dn_opparm = hs2net(DN_RD);
	dnptr->dn_qcount = hs2net(1);
	dnptr->dn_acount = dnptr->dn_ncount = dnptr->dn_dcount = 0;
	p = dnptr->dn_qaaa;

	/* Fill in question with  ip[3].ip[2].ip[1].ip[0].in-addr.arpa  */

	for (i=3 ; i >= 0 ; i--) {
		sprintf(tmpstr, "%u", ((char *)&ip)[i] & LOWBYTE);
		dn_cat(p, tmpstr);
	}

	dn_cat(p, "in-addr");
	dn_cat(p, "arpa");
	*p++ = NULLCH;	/* terminate name */

	/* Add query type and query class fields to name */

	( (struct dn_qsuf *)p )->dn_type = hs2net(DN_QTPR);
	( (struct dn_qsuf *)p )->dn_clas = hs2net(DN_QCIN);
	p += sizeof(struct dn_qsuf);

	/* Send query */

	dg = open(UDP, NSERVER, ANYLPORT);
	control(dg, DG_SETMODE, DG_DMODE | DG_TMODE);
	if (write (dg, buf, p - buf) == SYSERR)
		panic("ip2name write(%d) failed\n", dg);
	i = read(dg, buf, DN_MLEN);
	if (i == SYSERR)
		panic("ip2name read(%d) failed\n", dg);
	if (i == TIMEOUT) {
		close(dg);
		return ip2dot(nam, ip);
	}
	close(dg);
	if (net2hs(dnptr->dn_opparm) & DN_RESP ||
	    net2hs(dnptr->dn_acount) <= 0) {
		freemem(buf, DN_MLEN);
		return ip2dot(nam, ip);
	}

	/* In answer, skip name and remainder of resource record header	*/

	while (*p != NULLCH)
		if (*p & DN_CMPRS) 	/* compressed section of name	*/
			*++p = NULLCH;
		else
			p += *p + 1;
	p += DN_RLEN + 1;
	/* Copy name to user */
	*nam = NULLCH;
	while (*p != NULLCH) {
		if (*p & DN_CMPRS)
			p = buf + (net2hs(*(int *)p) & DN_CPTR);
		else {
			strncat(nam, p+1, *p);
			strcat(nam, ".");
			p += *p + 1;
		}
	}
	if (strlen(nam))	/* remove trailing dot */
		nam[strlen(nam) - 1] = NULLCH;
	else
		ip2dot(nam, ip);
	freemem(buf, DN_MLEN);
	return nam;
}
Example #14
0
/**
 * @ingroup icmp
 *
 * Processes an incoming ICMP packet.
 * @param pkt pointer to the incoming packet
 * return OK if packet was processed succesfully, otherwise SYSERR
 */
syscall icmpRecv(struct packet *pkt)
{
    struct icmpPkt *icmp;
    struct icmpEcho *echo;
    int id;

    /* Error check pointers */
    if (NULL == pkt)
    {
        return SYSERR;
    }

    icmp = (struct icmpPkt *)pkt->curr;

    switch (icmp->type)
    {
    case ICMP_ECHOREPLY:
        ICMP_TRACE("Received Echo Reply");
        echo = (struct icmpEcho *)icmp->data;
        id = net2hs(echo->id);
        if ((id >= 0) && (id < NTHREAD))
        {
            int i;
            irqmask im;

            im = disable();

            echo->arrivcyc = clkcount();
            echo->arrivtic = clkticks;
            echo->arrivsec = clktime;

            for (i = 0; i < NPINGQUEUE; i++)
            {
                struct icmpEchoQueue *eq;

                eq = &echotab[i];
                if (id == eq->tid)
                {
                    ICMP_TRACE("Ping matches queue %d", i);
                    if (((eq->head + 1) % NPINGHOLD) == eq->tail)
                    {
                        ICMP_TRACE("Queue full, discarding");
                        restore(im);
                        netFreebuf(pkt);
                        return SYSERR;
                    }
                    eq->pkts[eq->head] = pkt;
                    eq->head = ((eq->head + 1) % NPINGHOLD);
                    send(id, (message)pkt);
                    restore(im);
                    return OK;
                }
            }
            restore(im);
        }
        ICMP_TRACE("Reply id %d does not correspond to ping queue", id);
        netFreebuf(pkt);
        return SYSERR;

    case ICMP_ECHO:
        ICMP_TRACE("Enqueued Echo Request for daemon to reply");
        mailboxSend(icmpqueue, (int)pkt);
        return OK;

    case ICMP_UNREACH:
    case ICMP_SRCQNCH:
    case ICMP_REDIRECT:
    case ICMP_TIMEEXCD:
    case ICMP_PARAMPROB:
    case ICMP_TMSTMP:
    case ICMP_TMSTMPREPLY:
    case ICMP_INFORQST:
    case ICMP_INFOREPLY:
    case ICMP_TRACEROUTE:
        ICMP_TRACE("ICMP message type %d not handled", icmp->type);
        break;

    default:
        ICMP_TRACE("ICMP message type %d unknown", icmp->type);
        break;
    }

    netFreebuf(pkt);
    return OK;
}
Example #15
0
/**
 * The comments for dhcpRecvReply() apply, but for do_dhcpRecvReply() there is
 * no timeout and it is executed in a separate thread; furthermore, since this
 * thread can be killed at any time, it must use the memory passed in the @p pkt
 * parameter rather than allocating its own memory.
 */
static thread do_dhcpRecvReply(int descrp, struct dhcpData *data,
                               struct packet *pkt)
{
    const struct etherPkt *epkt;
    const struct ipv4Pkt *ipv4;
    const struct udpPkt *udp;
    const struct dhcpPkt *dhcp;
    const uchar *opts;
    uint maxlen;
    int found_msg;
    int retval;
    const uchar *gatewayptr;
    const uchar *maskptr;
    const uchar *opts_end;
    uint serverIpv4Addr;
    int mtu;
    int linkhdrlen;

    mtu = control(descrp, NET_GET_MTU, 0, 0);
    linkhdrlen = control(descrp, NET_GET_LINKHDRLEN, 0, 0);
    if (SYSERR == mtu || SYSERR == linkhdrlen)
    {
        return SYSERR;
    }

    maxlen = linkhdrlen + mtu;

    /* Receive packets until we find a response we're waiting for.  */

next_packet:
    do
    {
        /* Receive next packet from the network device.  */
        int len = read(descrp, pkt->data, maxlen);
        if (len == SYSERR || len <= 0)
        {
            data->recvStatus = SYSERR;
            return SYSERR;
        }

        pkt->len = len;
        DHCP_TRACE("Received packet (len=%u).", pkt->len);

        /* Make sure packet is at least the minimum length of a DHCP packet.  */
        if (pkt->len < (ETH_HDR_LEN + IPv4_HDR_LEN +
                        UDP_HDR_LEN + DHCP_HDR_LEN))
        {
            DHCP_TRACE("Too short to be a DHCP packet.");
            goto next_packet;
        }

        /* Set up header pointers  */
        epkt = (const struct etherPkt *)pkt->data;
        ipv4 = (const struct ipv4Pkt *)epkt->data;
        udp = (const struct udpPkt *)ipv4->opts;
        dhcp = (const struct dhcpPkt *)udp->data;

        /* DHCP packets must be type IPv4, protocol UDP, UDP dest port DHCPC,
         * and UDP source port DHCPS.
         *
         * Also check the DHCP header:  Is it actually a reply to this client?
         * */
        if ((ETHER_TYPE_IPv4 != net2hs(epkt->type))
            || (IPv4_PROTO_UDP != ipv4->proto)
            || (UDP_PORT_DHCPC != net2hs(udp->dstPort))
            || (UDP_PORT_DHCPS != net2hs(udp->srcPort))
            || (DHCP_OP_REPLY != dhcp->op)
            || (data->cxid != net2hl(dhcp->xid)))
        {
            DHCP_TRACE("Not a DHCP reply to this client.");
            goto next_packet;
        }

        DHCP_TRACE("Received DHCP reply.");

    #if DHCP_DROP_PACKET_PERCENT != 0
        /* Stress testing.  */
        if (rand() % 100 < DHCP_DROP_PACKET_PERCENT)
        {
            DHCP_TRACE("WARNING: Ignoring valid DHCP packet for test purposes.");
            goto next_packet;
        }
    #endif

        /* We got a valid DHCP reply.  Now parse the DHCP options.  This needs
         * to be done carefully to avoid overrunning the packet buffer if the
         * options data is invalid.  */
        opts = dhcp->opts;
        maskptr = NULL;
        gatewayptr = NULL;
        serverIpv4Addr = 0;
        opts_end = opts + (pkt->len - (ETH_HDR_LEN + IPv4_HDR_LEN +
                                       UDP_HDR_LEN + DHCP_HDR_LEN));
        found_msg = -1;
        for (;;)
        {
            uchar opt, len;

            /* Get the next option type.  */
            if (opts >= opts_end)
            {
                DHCP_TRACE("Invalid DHCP options.");
                goto next_packet;
            }
            opt = *opts++;

            /* Break on DHCP_OPT_END (marks end of DHCP options).  */
            if (DHCP_OPT_END == opt)
            {
                DHCP_TRACE("Reached DHCP_OPT_END.");
                break;
            }

            /* Get length of the data for this option.  */
            if (opts >= opts_end)
            {
                DHCP_TRACE("Invalid DHCP options.");
                goto next_packet;
            }
            len = *opts++;

            if (opts + len >= opts_end)
            {
                DHCP_TRACE("Invalid DHCP options.");
                goto next_packet;
            }

            /* Process the specific DHCP option.  Ignore unrecognized options.
             * */
            switch (opt)
            {
            case DHCP_OPT_MSGTYPE:
                DHCP_TRACE("DHCP_OPT_MSGTYPE: %d", *opts);
                if (len >= 1)
                {
                    if ((DHCPC_STATE_SELECTING == data->state &&
                         *opts == DHCPOFFER)
                        || (DHCPC_STATE_REQUESTING == data->state &&
                            (DHCPACK == *opts || DHCPNAK == *opts)))
                    {
                        found_msg = *opts;
                    }
                }
                break;

            case DHCP_OPT_SUBNET:
                if (len >= IPv4_ADDR_LEN)
                {
                    maskptr = opts;
                }
                break;

            case DHCP_OPT_GATEWAY:
                if (len >= IPv4_ADDR_LEN)
                {
                    gatewayptr = opts;
                }
                break;

            case DHCP_OPT_SERVER:
                if (len >= IPv4_ADDR_LEN)
                {
                    /* Server Identifier option.  */
                    serverIpv4Addr = ((uint)opts[0] << 24) |
                                     ((uint)opts[1] << 16) |
                                     ((uint)opts[2] << 8) |
                                     ((uint)opts[3] << 0);
                }
                break;
            }

            /* Advance by the length of the option's data.  */
            opts += len;
        }
    } while (found_msg < 0);

    /* We received a reply of at least the right type as one we were looking
     * for.  */

    /* Don't consider a DHCPACK reply to be valid unless it provided a subnet
     * mask.  */
    if (DHCPACK == found_msg && NULL == maskptr)
    {
        DHCP_TRACE("Ignoring DHCPACK (no subnet mask provided).");
        goto next_packet;
    }

    /* Note: The server's IP address is supposed to be specified in the Server
     * Identifier option, *not* in the siaddr (Server IP Address) field.  This
     * is because, somewhat unintuitively, siaddr is used for the address of the
     * next server in the bootstrap process, which may not be the same as the
     * DHCP server.  But if the Server Identifier option wasn't present, use
     * siaddr anyway.  */
    if (0 == serverIpv4Addr)
    {
        serverIpv4Addr = net2hl(dhcp->siaddr);
        if (0 == serverIpv4Addr)
        {
            DHCP_TRACE("Server IP address empty.");
            goto next_packet;
        }
    }

    if (DHCPOFFER == found_msg)
    {
        /* DHCPOFFER:  Remember offer and server addresses.  */
        data->serverIpv4Addr = serverIpv4Addr;
        data->offeredIpv4Addr = net2hl(dhcp->yiaddr);
        memcpy(data->serverHwAddr, epkt->src, ETH_ADDR_LEN);
        retval = OK;
    }
    else
    {
        /* Received DHCPACK or DHCPNAK.  Ensure it's from the same server to
         * which we sent the DHCPREQUEST; if not, ignore the packet.  */
        if (serverIpv4Addr != data->serverIpv4Addr)
        {
            DHCP_TRACE("Reply from wrong server.");
            goto next_packet;
        }

        if (DHCPNAK == found_msg)
        {
            /* DHCPNAK:  Return error to make client try DHCPDISCOVER again  */
            retval = SYSERR;
        }
        else
        {
            /* DHCPACK:  Set network interface addresses  */
            data->ip.type = NETADDR_IPv4;
            data->ip.len = IPv4_ADDR_LEN;
            /* yiaddr in a DHCPACK should be the same as the yiaddr stored from
             * the DHCPOFFER, but using the value in DHCPACK is preferable since
             * it's the value the server thinks it assigned.  */
            memcpy(data->ip.addr, &dhcp->yiaddr, IPv4_ADDR_LEN);
            data->clientIpv4Addr = net2hl(dhcp->yiaddr);

            data->mask.type = NETADDR_IPv4;
            data->mask.len = IPv4_ADDR_LEN;
            memcpy(data->mask.addr, maskptr, IPv4_ADDR_LEN);

            if (NULL != gatewayptr)
            {
                data->gateway.type = NETADDR_IPv4;
                data->gateway.len = IPv4_ADDR_LEN;
                memcpy(data->gateway.addr, gatewayptr, IPv4_ADDR_LEN);
            }

            /* If provided in the DHCPACK, set the address of next server and
             * the boot file (e.g. for TFTP).  */
            if (0 != dhcp->siaddr)
            {
                data->next_server.type = NETADDR_IPv4;
                data->next_server.len = IPv4_ADDR_LEN;
                memcpy(data->next_server.addr, &dhcp->siaddr, IPv4_ADDR_LEN);
            }
            if ('\0' != dhcp->file[0])
            {
                memcpy(data->bootfile, dhcp->file, sizeof(data->bootfile) - 1);
            }
        #ifdef ENABLE_DHCP_TRACE
            {
                char str_addr[24];
                netaddrsprintf(str_addr, &data->ip);
                DHCP_TRACE("Set ip=%s", str_addr);

                netaddrsprintf(str_addr, &data->mask);
                DHCP_TRACE("Set mask=%s", str_addr);

                if (NULL != gatewayptr)
                {
                    netaddrsprintf(str_addr, &data->gateway);
                    DHCP_TRACE("Set gateway=%s", str_addr);
                }
                else
                {
                    DHCP_TRACE("No gateway.");
                }

                netaddrsprintf(str_addr, &data->next_server);
                DHCP_TRACE("TFTP server=%s", str_addr);
                DHCP_TRACE("Bootfile=%s", data->bootfile);
            }
        #endif
            retval = OK;
        }
    }
    data->recvStatus = retval;
    return retval;
}
Example #16
0
/**
 * @ingroup tftp
 *
 * Download a file from a remote server using TFTP and passes its contents,
 * block-by-block, to a callback function.  This callback function can do
 * whatever it wants with the file data, such as store it all into a buffer or
 * write it to persistent storage.
 *
 * @param[in] filename
 *      Name of the file to download.
 * @param[in] local_ip
 *      Local protocol address to use for the connection.
 * @param[in] server_ip
 *      Remote protocol address to use for the connection (address of TFTP
 *      server).
 * @param[in] recvDataFunc
 *      Callback function that will be passed the file data block-by-block.  For
 *      each call of the callback function, the @p data (first) argument will be
 *      set to a pointer to the next block of data and the @p len (second)
 *      argument will be set to the block's length.  All data blocks will be the
 *      same size, except possibly the last, which can be anywhere from 0 bytes
 *      up to the size of the previous block(s) if any.
 *      <br/>
 *      In the current implementation, the block size (other than possibly for
 *      the last block) is fixed at 512 bytes.  However, implementations of this
 *      callback SHOULD handle larger block sizes since tftpGet() could be
 *      extended to support TFTP block size negotiation.
 *      <br/>
 *      This callback is expected to return ::OK if successful.  If it does not
 *      return ::OK, the TFTP transfer is aborted and tftpGet() returns this
 *      value.
 * @param[in] recvDataCtx
 *      Extra parameter that will be passed literally to @p recvDataFunc.
 *
 * @return
 *      ::OK on success; ::SYSERR if the TFTP transfer times out or fails, or if
 *      one of several other errors occur; or the value returned by @p
 *      recvDataFunc, if it was not ::OK.
 */
syscall tftpGet(const char *filename, const struct netaddr *local_ip,
                const struct netaddr *server_ip, tftpRecvDataFunc recvDataFunc,
                void *recvDataCtx)
{
    int udpdev;
    int udpdev2;
    int send_udpdev;
    int recv_udpdev;
    int retval;
    tid_typ recv_tid;
    uint num_rreqs_sent;
    uint block_recv_tries;
    uint next_block_number;
    ushort localpt;
    uint block_max_end_time = 0;  /* This value is not used, but
                                     gcc fails to detect it.  */
    uint block_attempt_time;
    struct tftpPkt pkt;

    /* Make sure the required parameters have been specified.  */
    if (NULL == filename || NULL == local_ip ||
        NULL == server_ip || NULL == recvDataFunc)
    {
        TFTP_TRACE("Invalid parameter.");
        return SYSERR;
    }

#ifdef ENABLE_TFTP_TRACE
    {
        char str_local_ip[20];
        char str_server_ip[20];
        netaddrsprintf(str_local_ip, local_ip);
        netaddrsprintf(str_server_ip, server_ip);
        TFTP_TRACE("Downloading %s from %s (using local_ip=%s)",
                   filename, str_server_ip, str_local_ip);
    }
#endif

    /* Allocate and open a UDP device (socket) to communicate with the TFTP
     * server on.  The local and remote protocol addresses are specified as
     * required parameters to this function.  The local port, which corresponds
     * to the client's TFTP Transfer Identifier (TID) as per RFC 1350, must be
     * allocated randomly; the UDP code handles this if 0 is passed as the local
     * port.  The remote port is always initially the well-known TFTP port (69),
     * but after receiving the first data packet it must be changed to the port
     * on which the server actually responded.
     *
     * However... the last point about the server responding on a different port
     * (which is unavoidable; it's how TFTP is designed) complicates things
     * significantly.  This is because the UDP code will *not* route the
     * server's response to the initial UDP device, as this device will be bound
     * to port 69, not the actual port the server responded on.  To work around
     * this problem without manually dealing with UDP headers, we create a
     * *second* UDP device, which initially listens on the port from which the
     * client sends the initial RRQ, but is initially *not* bound to any remote
     * port or address.  We then set UDP_FLAG_BINDFIRST on this second UDP
     * device so that the remote port and address are automatically filled in
     * when the response from the server is received.  Further packets sent from
     * the server are then received on this second UDP device, while further
     * packets sent from the client are then sent over this second UDP device
     * rather than the first since the second has the remote port correctly set.
     * */

    udpdev = udpAlloc();

    if (SYSERR == udpdev)
    {
        TFTP_TRACE("Failed to allocate first UDP device.");
        return SYSERR;
    }

    if (SYSERR == open(udpdev, local_ip, server_ip, 0, UDP_PORT_TFTP))
    {
        TFTP_TRACE("Failed to open first UDP device.");
        udptab[udpdev - UDP0].state = UDP_FREE;
        return SYSERR;
    }

    localpt = udptab[udpdev - UDP0].localpt;

    udpdev2 = udpAlloc();
    if (SYSERR == udpdev2)
    {
        TFTP_TRACE("Failed to allocate second UDP device.");
        retval = SYSERR;
        goto out_close_udpdev;
    }

    if (SYSERR == open(udpdev2, local_ip, NULL, localpt, 0))
    {
        TFTP_TRACE("Failed to open second UDP device.");
        retval = SYSERR;
        udptab[udpdev2 - UDP0].state = UDP_FREE;
        goto out_close_udpdev;
    }

    send_udpdev = udpdev;
    recv_udpdev = udpdev2;

    /* See lengthy comment above for explanation of this flag.  */
    control(recv_udpdev, UDP_CTRL_SETFLAG, UDP_FLAG_BINDFIRST, 0);

    TFTP_TRACE("Using UDP%d (for initial send) "
               "and UDP%d (for binding reply), client port %u",
               send_udpdev - UDP0, recv_udpdev - UDP0, localpt);

    /* Create receive thread.  This is a workaround to avoid having the
     * currently executing thread call read() on the UDP device, which can block
     * indefinitely.  */
    recv_tid = create(tftpRecvPackets, TFTP_RECV_THR_STK,
                      TFTP_RECV_THR_PRIO, "tftpRecvPackets", 3,
                      recv_udpdev, &pkt, gettid());
    if (isbadtid(recv_tid))
    {
        TFTP_TRACE("Failed to create TFTP receive thread.");
        retval = SYSERR;
        goto out_close_udpdev2;
    }
    ready(recv_tid, RESCHED_NO);

    /* Begin the download by requesting the file.  */
    retval = tftpSendRRQ(send_udpdev, filename);
    if (SYSERR == retval)
    {
        retval = SYSERR;
        goto out_kill_recv_thread;
    }
    num_rreqs_sent = 1;
    next_block_number = 1;

    /* Loop until file is fully downloaded or an error condition occurs.  The
     * basic idea is that the client receives DATA packets one-by-one, each of
     * which corresponds to the next block of file data, and the client ACK's
     * each one before the server sends the next.  But the actual code below is
     * a bit more complicated as it must handle timeouts, retries, invalid
     * packets, etc.  */
    block_recv_tries = 0;
    for (;;)
    {
        ushort opcode;
        ushort recv_block_number;
        struct netaddr *remote_address;
        bool wrong_source;
        ushort block_nbytes;

        /* Handle bookkeeping for timing out.  */

        block_attempt_time = clktime;
        if (block_recv_tries == 0)
        {
            uint timeout_secs;

            if (next_block_number == 1)
            {
                timeout_secs = TFTP_INIT_BLOCK_TIMEOUT;
            }
            else
            {
                timeout_secs = TFTP_BLOCK_TIMEOUT;
            }
            block_max_end_time = block_attempt_time + timeout_secs;
        }

        if (block_attempt_time <= block_max_end_time)
        {
            /* Try to receive the block using the appropriate timeout.  The
             * actual receive is done by another thread, executing
             * tftpRecvPacket(s).  */
            TFTP_TRACE("Waiting for block %u", next_block_number);
            block_recv_tries++;
            send(recv_tid, 0);
            retval = recvtime(1000 * (block_max_end_time -
                                      block_attempt_time) + 500);
        }
        else
        {
            /* Timeout was reached.  */
            retval = TIMEOUT;
        }

        /* Handle timeout.  */
        if (TIMEOUT == retval)
        {
            TFTP_TRACE("Receive timed out.");

            /* If the client is still waiting for the very first reply from the
             * server, don't fail on the first timeout; instead wait until the
             * client has had the chance to re-send the RRQ a few times.  */
            if (next_block_number == 1 &&
                num_rreqs_sent < TFTP_INIT_BLOCK_MAX_RETRIES)
            {
                TFTP_TRACE("Trying RRQ again (try %u of %u)",
                           num_rreqs_sent + 1, TFTP_INIT_BLOCK_MAX_RETRIES);
                retval = tftpSendRRQ(send_udpdev, filename);
                if (SYSERR == retval)
                {
                    break;
                }
                block_recv_tries = 0;
                num_rreqs_sent++;
                continue;
            }

            /* Timed out for real; clean up and return failure status.  */
            retval = SYSERR;
            break;
        }

        /* Return failure status if packet was not otherwise successfully
         * received for some reason.  */
        if (SYSERR == retval)
        {
            TFTP_TRACE("UDP device or message passing error; aborting.");
            break;
        }

        /* Otherwise, 'retval' is the length of the received TFTP packet.  */

        /* Begin extracting information from and validating the received packet.
         * What we're looking for is a well-formed TFTP DATA packet from the
         * correct IP address, where the block number is either that of the next
         * block or that of the previous block.  The very first block needs some
         * special handling, however; in particular, there is no previous block
         * in that case, and the remote network address needs to be checked to
         * verify the socket was actually bound to the server's network address
         * as expected.
         */
        remote_address = &udptab[recv_udpdev - UDP0].remoteip;
        opcode = net2hs(pkt.opcode);
        recv_block_number = net2hs(pkt.DATA.block_number);
        wrong_source = !netaddrequal(server_ip, remote_address);

        if (wrong_source || retval < 4 || TFTP_OPCODE_DATA != opcode ||
            (recv_block_number != (ushort)next_block_number &&
             (next_block_number == 1 ||
              recv_block_number != (ushort)next_block_number - 1)))
        {
            /* Check for TFTP ERROR packet  */
            if (!wrong_source && (retval >= 2 && TFTP_OPCODE_ERROR == opcode))
            {
                TFTP_TRACE("Received TFTP ERROR opcode packet; aborting.");
                retval = SYSERR;
                break;
            }
            TFTP_TRACE("Received invalid or unexpected packet.");

            /* If we're still waiting for the first valid reply from the server
             * but the bound connection is *not* from the server, reset the
             * BINDFIRST flag.  */
            if (wrong_source && next_block_number == 1)
            {
                irqmask im;
                TFTP_TRACE("Received packet is from wrong source; "
                           "re-setting bind flag.");
                im = disable();
                control(recv_udpdev, UDP_CTRL_BIND, 0, (long)NULL);
                control(recv_udpdev, UDP_CTRL_SETFLAG, UDP_FLAG_BINDFIRST, 0);
                restore(im);
            }

            /* Ignore the bad packet and try receiving again.  */
            continue;
        }

        /* Received packet is a valid TFTP DATA packet for either the next block
         * or the previous block.  */


    #if TFTP_DROP_PACKET_PERCENT != 0
        /* Stress testing.  */
        if (rand() % 100 < TFTP_DROP_PACKET_PERCENT)
        {
            TFTP_TRACE("WARNING: Ignoring valid TFTP packet for test purposes.");
            continue;
        }
    #endif

        /* If this is the first response from the server, set the actual port
         * that it responded on.  */
        if (next_block_number == 1)
        {
            send_udpdev = recv_udpdev;
            TFTP_TRACE("Server responded on port %u; bound socket",
                       udptab[recv_udpdev - UDP0].remotept);
        }

        /* Handle receiving the next data block.  */
        block_nbytes = TFTP_BLOCK_SIZE;
        if (recv_block_number == (ushort)next_block_number)
        {
            block_nbytes = retval - 4;
            TFTP_TRACE("Received block %u (%u bytes)",
                       recv_block_number, block_nbytes);

            /* Feed received data into the callback function.  */
            retval = (*recvDataFunc)(pkt.DATA.data, block_nbytes,
                                     recvDataCtx);
            /* Return if callback did not return OK.  */
            if (OK != retval)
            {
                break;
            }
            next_block_number++;
            block_recv_tries = 0;
        }

        /* Acknowledge the block received.  */
        retval = tftpSendACK(send_udpdev, recv_block_number);

        /* A TFTP Get transfer is complete when a short data block has been
         * received.   Note that it doesn't really matter from the client's
         * perspective whether the last data block is acknowledged or not;
         * however, the server would like to know so it doesn't keep re-sending
         * the last block.  For this reason we did send the final ACK packet but
         * will ignore failure to send it.  */
        if (block_nbytes < TFTP_BLOCK_SIZE)
        {
            retval = OK;
            break;
        }

        /* Break if sending the ACK failed.  */
        if (SYSERR == retval)
        {
            break;
        }
    }
    /* Clean up and return.  */
out_kill_recv_thread:
    kill(recv_tid);
out_close_udpdev2:
    close(udpdev2);
out_close_udpdev:
    close(udpdev);
    return retval;
}
Example #17
0
/**
 * Fragments packet into maximum transmission unit sized chunks.
 * @param pkt the packet to fragment
 * @return OK
 */
syscall ipv4SendFrag(struct packet *pkt, struct netaddr *nxthop)
{
    uint ihl;
    uchar *data;
    uint dRem = 0;              // The amount of data remaining to be fragmented
    ushort froff;
    ushort lastFlag;
    ushort dLen;

    // Incoming packet structures
    struct ipv4Pkt *ip;

    // Outgoing packet structures
    struct ipv4Pkt *outip;
    struct packet *outpkt;

    IPv4_TRACE("Declaration");

    if (NULL == pkt)
    {
        return SYSERR;
    }

    // Setup incoming packet structures
    ip = (struct ipv4Pkt *)pkt->curr;

    if (net2hs(ip->len) <= pkt->nif->mtu)
    {
        IPv4_TRACE("NetSend");

        if (netaddrequal(&pkt->nif->ipbrc, nxthop))
        {
            IPv4_TRACE("Subnet Broadcast");
            return netSend(pkt, &NETADDR_GLOBAL_ETH_BRC,
                           nxthop, ETHER_TYPE_IPv4);
        }
        return netSend(pkt, NULL, nxthop, ETHER_TYPE_IPv4);
    }

    // Verify header does not have DF
    if (net2hs(ip->flags_froff) & IPv4_FLAG_DF)
    {
        IPv4_TRACE("net2hs of froff");
        /* Send ICMP message */
        icmpDestUnreach(pkt, ICMP_FOFF_DFSET);
        return SYSERR;
    }

    ihl = (ip->ver_ihl & IPv4_IHL) * 4;
    data = ((uchar *)ip) + ihl;
    dRem = net2hs(ip->len) - ihl;
    froff = net2hs(ip->flags_froff) & IPv4_FROFF;
    lastFlag = net2hs(ip->flags_froff) & IPv4_FLAGS;

    // Length of data in this packet will be MTU - header length,
    //  rounded down to nearest multiple of 8 bytes.
    dLen = (pkt->nif->mtu - ihl) & ~0x7;

    pkt->len = ihl + dLen;
    ip->len = hs2net(pkt->len);

    // Set more fragments flag
    ip->flags_froff = IPv4_FLAG_MF & froff;
    ip->flags_froff = hs2net(ip->flags_froff);

    ip->chksum = 0;
    ip->chksum = netChksum((uchar *)ip, ihl);

    netSend(pkt, NULL, nxthop, ETHER_TYPE_IPv4);
    dRem -= dLen;
    data += dLen;
    froff += (dLen / 8);

    // Get memory from stack for outgoing fragment
    outpkt = netGetbuf();

    if (SYSERR == (int)outpkt)
    {
        IPv4_TRACE("allocating outpkt");
        return SYSERR;
    }

    // Set up outgoing packet pointers and variables
    outpkt->curr -= pkt->nif->mtu;
    outip = (struct ipv4Pkt *)outpkt->curr;
    outpkt->nif = pkt->nif;

    memcpy(outip, ip, IPv4_HDR_LEN);

    // While packet must be fragmented
    while (dRem > 0)
    {
        if (((dRem + 7) & ~0x7) > pkt->nif->mtu + IPv4_HDR_LEN)
        {
            dLen = (pkt->nif->mtu - IPv4_HDR_LEN) & ~0x7;
        }
        else
        {
            dLen = dRem;
        }
        // Copy data segment
        memcpy(outip->opts, data, dLen);

        // Set more fragments flag
        if (dLen == dRem)
        {
            outip->flags_froff = lastFlag & froff;
        }
        else
        {
            outip->flags_froff = IPv4_FLAG_MF & froff;
        }
        outip->flags_froff = hs2net(outip->flags_froff);

        // Update fields
        outip->len = hs2net(IPv4_HDR_LEN + dLen);
        outip->chksum = 0;
        outip->chksum = netChksum((uchar *)outip, IPv4_HDR_LEN);

        // Update outgoing packet length
        outpkt->len = net2hs(outip->len);

        // Send fragment
        netSend(outpkt, NULL, nxthop, ETHER_TYPE_IPv4);

        dRem -= dLen;
        data += dLen;
        froff += (dLen / 8);
    }

    IPv4_TRACE("freeing outpkt");
    netFreebuf(outpkt);
    return OK;
}
Example #18
0
/**
 * @ingroup snoop
 *
 * Print contents of an TCP packet
 * @param tcp TCP packet
 * @return OK if print successful, SYSERR if error occurs
 */
int snoopPrintTcp(struct tcpPkt *tcp, char verbose)
{
    char descrp[40];
    char output[40];

    /* Error check pointer */
    if (NULL == tcp)
    {
        return SYSERR;
    }

    if (verbose >= SNOOP_VERBOSE_ONE)
    {
        printf(" ----- TCP Header -----\n", "");
        /* Source Port */
        if (verbose >= SNOOP_VERBOSE_TWO)
        {
            snoopPrintTcpPort(net2hs(tcp->srcpt), descrp);
        }
        else
        {
            sprintf(descrp, "");
        }
        sprintf(output, "%d %s", net2hs(tcp->srcpt), descrp);
        printf("  Src Port: %-25s ", output);

        /* Destination Port */
        if (verbose >= SNOOP_VERBOSE_TWO)
        {
            snoopPrintTcpPort(net2hs(tcp->dstpt), descrp);
        }
        else
        {
            sprintf(descrp, "");
        }
        sprintf(output, "%d %s", net2hs(tcp->dstpt), descrp);
        printf("Dst Port: %-25s\n", output);

        /* Sequence number */
        printf("  Seq Num: %-14u ", net2hl(tcp->seqnum));
        /* Acknowledgement number */
        printf("Ack Num: %-14u ", net2hl(tcp->acknum));
        /* Control flags */
        printf("Ctrl: ");
        if (tcp->control & TCP_CTRL_URG)
        {
            printf("U ");
        }
        if (tcp->control & TCP_CTRL_ACK)
        {
            printf("A ");
        }
        if (tcp->control & TCP_CTRL_PSH)
        {
            printf("P ");
        }
        if (tcp->control & TCP_CTRL_RST)
        {
            printf("R ");
        }
        if (tcp->control & TCP_CTRL_SYN)
        {
            printf("S ");
        }
        if (tcp->control & TCP_CTRL_FIN)
        {
            printf("F ");
        }
        printf("\n");

        if (verbose >= SNOOP_VERBOSE_TWO)
        {
            sprintf(output, "%d bytes", offset2octets(tcp->offset));
            printf("  Offset: %-15s ", output);
            sprintf(output, "%d bytes", net2hs(tcp->window));
            printf("Window: %-15s ", output);
            printf("Chksum: 0x%04X\n", net2hs(tcp->chksum));
        }
    }

    return OK;
}
Example #19
0
/*------------------------------------------------------------------------
 *  x_rls  -  (command rls) list contents of remote file system directory
 *------------------------------------------------------------------------
 */
COMMAND
x_rls(int stdin, int stdout, int stderr, int nargs, char *args[])
{
	char	*p, *buf;
	int	dev, len;
	char	str[256];
	struct	dirent	{	/* UNIX directory entry		*/
		long	d_inum;	/* file's inode number		*/
		short	d_rlen;	/* length of this record	*/
		short	d_nlen;	/* length of this file's name	*/
		char	d_nam[1]; /* start of file name		*/
	};
	struct	dirent	*d;
	Bool	aflag;

	aflag = FALSE;
	if (nargs > 1 && strcmp(p=args[1],"-a") == 0) {
		nargs--;
		aflag = TRUE;
		p = args[2];
        }
	if (nargs == 1)
	  p = ".";
	else if (nargs != 2) {
		printf("Usage: rls [-a] directory\n");
		return(SYSERR);
	}
	if ( ((long)(buf=(char *)getmem(512))) == SYSERR) {
		fprintf(stderr, "rls: no memory\n");
		return(SYSERR);
	}
	if (nammap(p, buf) != RFILSYS || (dev=open(NAMESPACE, p, "ro")) == SYSERR) {
		fprintf(stderr, "cannot open %s\n", p);
		freemem(buf, 512);
		return(SYSERR);
	}
	while ( (len = read(dev, buf, 512)) > 0) {
		for (p=buf ; p< &buf[512] ; p += d->d_rlen) {
			d = (struct dirent *)p;
			/* this could be a Vax or a Sun, so be */
			/* prepared to swap integer fields     */
			if (d->d_nlen != strlen(d->d_nam)) {
			    d->d_nlen = net2hs(d->d_nlen);
			    d->d_rlen = net2hs(d->d_rlen);
			}
			
			if (d->d_inum == 0)
			  continue;
			if (len < 512 ||
			    d->d_nlen != strlen(d->d_nam) ||
			    d->d_nlen > 255 ||
			    d->d_rlen < sizeof(struct dirent) ||
			    d->d_rlen > &buf[512] - p) {
			    fprintf(stderr, "Not a directory\n");
			    close(dev);
			    freemem(buf, 512L);
			    return(SYSERR);
		        }
			if (aflag || d->d_nam[0] != '.') {
				strcpy(str, d->d_nam);
				strcat(str, "\n");
				write(stdout, str, strlen(str));
			}
			if (d->d_rlen == 0)
			  break;
		}
	}
	freemem(buf, 512);
	close(dev);
	return(OK);
}
Example #20
0
/**
 * Process an incoming IPv4 packet.
 * @param pkt pointer to the incoming packet
 * @return OK if packet was processed succesfully, otherwise SYSERR
 */
syscall ipv4Recv(struct packet *pkt)
{
    struct ipv4Pkt *ip;
    struct netaddr dst;
    struct netaddr src;
    ushort iplen;

    /* Error check pointers */
    if (NULL == pkt)
    {
        return SYSERR;
    }

    /* Setup pointer to IPv4 header */
    pkt->nethdr = pkt->curr;
    ip = (struct ipv4Pkt *)pkt->curr;

    /* Verify the IP packet is valid */
    if (FALSE == ipv4RecvValid(ip))
    {
        IPv4_TRACE("Invalid packet");
        netFreebuf(pkt);
        return SYSERR;
    }

    /* Obtain destination and source IP addresses */
    dst.type = NETADDR_IPv4;
    dst.len = IPv4_ADDR_LEN;
    memcpy(dst.addr, ip->dst, dst.len);
    src.type = NETADDR_IPv4;
    src.len = IPv4_ADDR_LEN;
    memcpy(src.addr, ip->src, src.len);

    /* If packet is not destined for one of our network interfaces,
     * then attempt to route the packet */
    if (FALSE == ipv4RecvDemux(&dst))
    {
        IPv4_TRACE("Packet sent to routing subsystem");

#if NETEMU
        /* Run the packet through the network emulator if enabled */
        return netemu(pkt);
#else
        return rtRecv(pkt);
#endif
    }

    /* Check if packet is fragmented */
    if ((IPv4_FLAG_MF & net2hs(ip->flags_froff))
        || (0 != (net2hs(ip->flags_froff) & IPv4_FROFF)))
    {
        // TODO: Handle fragmenting of packet
        // TODO: Should send icmp time exceeded
        // return ipRecvSendFrag(pkt, &dst);
        IPv4_TRACE("Packet fragmented");
        netFreebuf(pkt);
        return SYSERR;
    }

    /* The Ethernet driver pads packets less than 60 bytes in length.
     * If the packet length returned from the Ethernet driver (pkt->len)
     * does not agree with the packet headers, adjust the packet length 
     * to remove padding. */
    iplen = net2hs(ip->len);
    if ((pkt->len - pkt->nif->linkhdrlen) > iplen)
    {
        pkt->len = pkt->nif->linkhdrlen + iplen;
    }

    /* Move current pointer to application level header */
    pkt->curr += ((ip->ver_ihl & IPv4_IHL) << 2);

    IPv4_TRACE("IPv4 proto %d", ip->proto);
    /* Switch on packet protocol */
    switch (ip->proto)
    {
        /* ICMP Packet */
    case IPv4_PROTO_ICMP:
        icmpRecv(pkt);
        break;

        /* UDP Packet */
    case IPv4_PROTO_UDP:
#if NUDP
        udpRecv(pkt, &src, &dst);
#endif                          /* NUDP */
        break;

        /* TCP Packet */
    case IPv4_PROTO_TCP:
#if NTCP
        tcpRecv(pkt, &src, &dst);
#endif                          /* NTCP */
        break;

        /* Unknown IP packet protocol */
    default:
#if NRAW
        rawRecv(pkt, &src, &dst, ip->proto);
#endif                          /* NRAW */
        break;
    }

    return OK;
}
Example #21
0
/*------------------------------------------------------------------------
 *  gname  -  use the DNS to look up the name
 *------------------------------------------------------------------------
 */
static IPaddr
gname(char *nam)
{
    IPaddr	ip;
    char	tmpstr[64];		/* temporary string buffer	*/
    char	*buf;			/* buffer to hold domain query	*/
    int	dg, i;
    register char	*p, *p2, *p3;
    register struct	dn_mesg *dnptr;

    dnptr = (struct dn_mesg *) (buf = (char *) getmem(DN_MLEN));
    dnptr->dn_id = 0;
    dnptr->dn_opparm = hs2net(DN_RD);
    dnptr->dn_qcount = hs2net(1);
    dnptr->dn_acount = dnptr->dn_ncount = dnptr->dn_dcount = 0;
    p = dnptr->dn_qaaa;

    strcpy(tmpstr, nam);
    p2 = tmpstr;
    while (p3=index(p2, '.')) {
        *p3 = '\0';
        dn_cat(p, p2);
        p2 = p3+1;
    }
    dn_cat(p, p2);
    *p++ = NULLCH;	/* terminate name */

    /* Add query type and query class fields to name */

    ( (struct dn_qsuf *)p )->dn_type = hs2net(DN_QTHA);
    ( (struct dn_qsuf *)p )->dn_clas = hs2net(DN_QCIN);
    p += sizeof(struct dn_qsuf);

    /* send query */

    dg = open(UDP, NSERVER, ANYLPORT);
    control(dg, DG_SETMODE, DG_DMODE | DG_TMODE);
    write (dg, buf, p - buf);
    if ( (i = read(dg, buf, DN_MLEN)) == SYSERR || i == TIMEOUT) {
        close(dg);
        freemem(buf, DN_MLEN);
        return (IPaddr)SYSERR;
    }
    close(dg);
    if (net2hs(dnptr->dn_opparm) & DN_RESP ||
            net2hs(dnptr->dn_acount) <= 0) {
        freemem(buf, DN_MLEN);
        return (IPaddr)SYSERR;
    }
    /* In answer, skip name and remainder of resource record header	*/

    while (*p != NULLCH)
        if (*p & DN_CMPRS) 	/* compressed section of name	*/
            *++p = NULLCH;
        else
            p += *p + 1;
    p += DN_RLEN + 1;

    /* Copy IP to user */

    for (i=0; i < IP_ALEN; ++i)
        ((char *)&ip)[i] = *p++;
    freemem(buf, DN_MLEN);
    return ip;
}