home *** CD-ROM | disk | FTP | other *** search
- /*
- * IP.C
- * IP level routines, including ICMP
- * also includes a basic version of UDP, not generalized yet
- *
- ****************************************************************************
- * *
- * part of: *
- * TCP/IP kernel for NCSA Telnet *
- * by Tim Krauskopf *
- * *
- * National Center for Supercomputing Applications *
- * 152 Computing Applications Building *
- * 605 E. Springfield Ave. *
- * Champaign, IL 61820 *
- * *
- * Copyright (c) 1987, Board of Trustees of the University of Illinois *
- * *
- ****************************************************************************
- *
- * IP level routines ( including an ICMP handler )
- *
- ****************************************************************************
- * Revision history:
- *
- * 10/87 Initial source release, Tim Krauskopf
- * 2/88 typedefs of integer lengths, TK
- * 5/88 clean up for 2.3 release, JKM
- *
- */
-
- /*
- * Includes
- */
- #include <stdio.h>
- #ifdef MEMORY_DEBUG
- #include "memdebug.h"
- #endif
- #include "protocol.h"
- #include "data.h"
- #include "externs.h"
-
- #include <fcntl.h>
- #include <io.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- static int waiting_for_ping = FALSE;
- int (*pingfunc)(ICMPKT *p, int icmplen) = NULL;
- ICMPKT blankicmp;
- extern struct config Scon;
- extern struct config def;
-
- extern int SQwait;
- extern int OKpackets;
-
- /*
- * ipinterpret ( p )
- *
- * Called by the packet demuxer to interpret a new ip packet. Checks the
- * validity of the packet (checksum, flags) and then passes it on to the
- * appropriate protocol handler.
- *
- */
- unsigned char junk[]={0,0,0,0};
-
- int ipinterpret(p)
- IPKT *p; /* ptr to packet from network */
- {
- int iplen,i;
- /*
- * We cannot handle fragmented IP packets yet, return an error
- */
- if(p->i.frags&0x20) { /* check for a fragmented packet */
- netposterr(304);
- return(1);
- }
- /*
- * checksum verification of IP header
- */
- if (p->i.check) { /* no IP checksumming if check=0 */
- if(ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen&0x0f) << 1)) {
- netposterr(300); /* bad IP checksum */
- return(1); /* drop packet */
- }
- }
- /*
- * Extract total length of packet
- */
- iplen=intswap(p->i.tlen);
- /*
- * check to make sure that the packet is for me.
- * Throws out all packets which are not directed to my IP address.
- *
- * This code is incomplete. It does not pass broadcast IP addresses up
- * to higher layers. It used to report packets which were incorrectly
- * addressed, but no longer does. Needs proper check for broadcast
- * addresses.
- */
- if(!comparen(nnipnum,p->i.ipdest,4)) { /* potential non-match */
- if(comparen(nnipnum,junk,4) && p->i.protocol==PROTUDP) {
- i=(p->i.versionandhdrlen & 0x0f)<<2;
- return(udpinterpret((struct udp *)p,iplen-i));
- } /* end if */
- return(1); /* drop packet */
- }
- /*
- * See if there are any IP options to be handled.
- * We don't understand IP options, post a warning to the user and drop
- * the packet.
- */
- i=(p->i.versionandhdrlen&0x0f)<<2;
- if(i>20) { /* check for options in packet */
- netposterr(302);
- return(1);
- }
- switch (p->i.protocol) { /* which protocol to handle this packet? */
- case PROTUDP:
- return(udpinterpret((UDPKT *)p,iplen-i));
-
- case PROTTCP:
- return(tcpinterpret((TCPKT *)p,iplen-i)); /* pass tcplen on to TCP */
-
- case PROTICMP:
- return(icmpinterpret((ICMPKT *)p,iplen-i));
-
- default:
- netposterr(303);
- return(1);
- }
- return(0);
- }
-
- #ifdef NNDEBUG
- /*
- * ipdump ( p )
- *
- * Routine to dump an IP packet -- only compiled if the debug option is
- * enabled.
- */
- ipdump(p)
- IPKT *p;
- {
- uint16 iplen,iid;
-
- iid=intswap(p->i.ident);
- iplen=intswap(p->i.tlen);
-
- puts("found IP packet:");
- printf("Version+hdr: %x service %d tlen %u \n",
- p->i.versionandhdrlen,p->i.service,iplen);
- printf("Ident: %u frags: %4x ttl: %d prot: %d \n",
- iid,p->i.frags,p->i.ttl,p->i.protocol);
- printf("addresses: s: %d.%d.%d.%d t: %d.%d.%d.%d \n",
- p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
- p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
- puts("\n");
- }
-
- /***************************************************************************/
- /* ipsend THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
- *
- * generic send of an IP packet according to parameters. Use of this
- * procedure is discouraged. Terribly inefficient, but may be useful for
- * tricky or diagnostic situations. Unused for TCP.
- *
- * usage: ipsend(data,ident,prot,options,hdrlen)
- * data is a pointer to the data to be sent
- * ident is the 16 bit identifier
- * prot is the protocol type, PROTUDP or PROTTCP or other
- * hlen is in bytes, total header length, 20 is minimum
- * dlen is the length of the data field, in bytes
- * who is ip address of recipient
- * options must be included in hlen and hidden in the data stream
- */
- ipsend(data,dlen,iid,iprot,who,hlen)
- unsigned char *data,iprot,*who;
- int iid,dlen,hlen;
- {
- int iplen;
-
- if(dlen>512)
- dlen=512;
- iplen=hlen+dlen; /* total length of packet */
- blankip.i.tlen=intswap(iplen); /* byte swap */
- blankip.i.versionandhdrlen=0x40|(hlen>>2);
- blankip.i.ident=intswap(iid); /* byte swap */
- blankip.i.protocol=iprot;
- blankip.i.check=0; /* set to 0 before calculating */
- movebytes(blankip.i.ipdest,who,4);
- movebytes(blankip.d.me,myaddr,DADDLEN);
- movenbytes(blankip.x.data,data,dlen); /* might be header options data */
- blankip.i.check=ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
- /* checks based on words */
- /* resolve knowledge of Ethernet hardware addresses */
- /*
- * This is commented out because I know that this procedure is broken!
- * If you use it, debug it first.
-
- dlayersend(&blankip,iplen+14);
- */
- return(0);
- }
- #endif
-
- /****************************************************************************/
- /*
- * icmpinterpret ( p, icmplen )
- *
- * Interpret the icmp message that just came off the wire
- *
- */
- int icmpinterpret(p,icmplen)
- ICMPKT *p;
- int icmplen;
- {
- uint i;
- IPLAYER *iptr;
-
- i=p->c.type;
- netposterr(600+i); /* provide info for higher layer user */
- if(p->c.check) { /* ignore if chksum=0 */
- if(ipcheck((char *)&p->c,icmplen>>1)) {
- netposterr(699);
- return(-1);
- }
- }
- switch (i) {
- case 8: /* ping request sent to me */
- p->c.type=0; /* echo reply type */
- neticmpturn(p,icmplen); /* send back */
- break;
-
- case 5: /* ICMP redirect */
- iptr=(IPLAYER *)p->data;
- netputuev(ICMPCLASS,IREDIR,0); /* event to be picked up */
- movebytes(nnicmpsave,iptr->ipdest,4); /* dest address */
- movebytes(nnicmpnew,&p->c.part1,4); /* new gateway */
- break;
-
- case 4: /* ICMP source quench */
- vprint(console->vs,"ICMP: source quench received");
- OKpackets=0;
- SQwait += 100;
- break;
-
- case 0: /* ping reply ? */
- if (waiting_for_ping) {
- if (!pingfunc)
- waiting_for_ping = FALSE;
- else {
- if ((*pingfunc)(p, icmplen)) {
- waiting_for_ping = FALSE;
- pingfunc = NULL;
- }
- }
- }
- break;
-
- default:
- #ifdef ASK_JEFF
- printf("ICMP\n");
- #endif
- break;
- }
- return(0);
- }
-
- #ifdef OLDPC
- /****************************************************************************/
- /* udpinterpret
- * take incoming UDP packets and make them available to the user level
- * routines. Currently keeps the last packet coming in to a port.
- *
- * Limitations:
- * Can only listen to one UDP port at a time. Only saves the last packet
- * received on that port.
- * Port numbers should be assigned like TCP ports are (future).
- */
- udpinterpret(p,ulen)
- UDPKT *p;
- int ulen;
- {
- uint hischeck,mycheck;
- /*
- * did we want this data ? If not, then let it go, no comment
- * If we want it, copy the relevent information into our structure
- */
- if(intswap(p->u.dest)!=ulist.listen)
- return(1);
- /*
- * first compute the checksum to see if it is a valid packet
- */
- hischeck=p->u.check;
- p->u.check=0;
- if (hischeck) {
- movebytes(tcps.source,p->i.ipsource,8);
- tcps.z=0;
- tcps.proto=p->i.protocol;
- tcps.tcplen=intswap(ulen);
- mycheck=tcpcheck(&tcps,&p->u,ulen);
- if (hischeck != mycheck) {
- netposterr(700);
- return(2);
- }
- p->u.check=hischeck; /* put it back */
- }
- ulen-=8; /* account for header */
- if(ulen>UMAXLEN) /* most data that we can accept */
- ulen=UMAXLEN;
- movebytes(ulist.who,p->i.ipsource,4);
- movebytes(ulist.data,p->data,ulen);
- ulist.length=ulen;
- ulist.stale=0;
- netputuev(USERCLASS,UDPDATA,ulist.listen); /* post that it is here */
- return(0);
- }
-
- /****************************************************************************/
- /* neturead
- * get the data from the UDP buffer
- * Returns the number of bytes transferred into your buffer, -1 if none here
- * This needs work.
- */
- neturead(buffer)
- char *buffer;
- {
- if (ulist.stale)
- return(-1);
- movebytes(buffer,ulist.data,ulist.length);
- ulist.stale=1;
- return((int)ulist.length);
- }
-
- /***************************************************************************/
- /* netulisten
- * Specify which UDP port number to listen to.
- * Can only listen to one at a time.
- */
- void netulisten(port)
- int port;
- {
- ulist.listen=port;
- }
-
- /***************************************************************************/
- /* netusend
- * Send out an icmp packet -- probably in response to a ping operation.
- * Assumes that the packet is already setup and just interchanges the source
- * and destination address of the packet and inserts my address for the
- * source and sends it.
- */
- netusend(machine,port,retport,buffer,n)
- unsigned char *machine,*buffer;
- unsigned int port,retport;
- int n;
- {
- unsigned char *pc;
-
- if (n>UMAXLEN)
- n=UMAXLEN;
- /*
- * make sure that we have the right dlayer address
- */
- if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
- pc=netdlayer(machine);
- if(comparen(machine,broadip,4))
- pc=broadaddr;
- if (pc==NULL)
- return(-2);
- movebytes(ulist.udpout.d.dest,pc,DADDLEN);
- movebytes(ulist.udpout.i.ipdest,machine,4);
- movebytes(ulist.tcps.dest,machine,4);
- }
- ulist.udpout.u.dest=intswap(port);
- ulist.udpout.u.source=intswap(retport);
- ulist.tcps.tcplen=ulist.udpout.u.length=intswap(n+sizeof(UDPLAYER));
- movenbytes(ulist.udpout.data,buffer,n);
- /*
- * put in checksum
- */
- ulist.udpout.u.check=0;
- ulist.udpout.u.check=tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
- /*
- * iplayer for send
- */
- ulist.udpout.i.tlen=intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
- ulist.udpout.i.ident=intswap(nnipident++);
- ulist.udpout.i.check=0;
- ulist.udpout.i.check=ipcheck(&ulist.udpout.i,10);
- /*
- * send it
- */
- return(dlayersend(&ulist.udpout,
- sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n));
- }
- #endif
-
- /***************************************************************************/
- /* neticmpturn
- *
- * send out an icmp packet, probably in response to a ping operation
- * interchanges the source and destination addresses of the packet,
- * puts in my addresses for the source and sends it
- *
- * does not change any of the ICMP fields, just the IP and dlayers
- * returns 0 on okay send, nonzero on error
- */
- int neticmpturn(p,ilen)
- ICMPKT *p;
- int ilen;
- {
- unsigned char *pc;
-
- /*
- * reverse the addresses, dlayer and IP layer
- */
- if (comparen(p->d.me,broadaddr,DADDLEN))
- return(0);
- movebytes(p->d.dest,p->d.me,DADDLEN);
- /*
- * look up address in the arp cache if we are using AppleTalk
- * encapsulation.
- */
- if(!nnemac) {
- pc=getdlayer(p->i.ipsource);
- if(pc!=NULL)
- movebytes(p->d.dest,pc,DADDLEN);
- else
- return(0); /* no hope this time */
- }
- movebytes(p->i.ipdest,p->i.ipsource,4);
- movebytes(p->d.me,nnmyaddr,DADDLEN);
- movebytes(p->i.ipsource,nnipnum,4);
- /*
- * prepare ICMP checksum
- */
- p->c.check=0;
- p->c.check=ipcheck((char *)&p->c,ilen>>1);
- /*
- * iplayer for send
- */
- p->i.ident=intswap(nnipident++);
- p->i.check=0;
- p->i.check=ipcheck((char *)&p->i,10);
- /*
- * send it
- */
- return((int)dlayersend((DLAYER *)p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen));
- }
-