new changelog entry preparing for upload
[debian/ipip] / ip.c
1 /* ip.c         system IP or UDP level stuff
2  *
3  * $Id: ip.c,v 1.4 1995/03/19 17:21:06 bdale Exp $
4  *
5  * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
6  * This software may be freely used, distributed, or modified, providing
7  * this header is not removed.
8  *
9  * Added support for Linux - Ron Atkinson N8FOW 
10  */
11
12 #include "ipip.h"
13
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/in_systm.h>
19 #include <netinet/ip.h>
20 #include <netdb.h>
21 #include <fcntl.h>
22 #include <memory.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <syslog.h>
27
28 #ifndef FNDELAY
29 #define FNDELAY O_NDELAY
30 #endif
31
32 extern int errno;
33
34 #define IF_NAME "ip"            /* for use with the error checking macros */
35
36 /*
37  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
38  * open and initialize the IO interface.  Return -1 for error.
39  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
40  */
41 int ip_open(ifp)
42 struct interface *ifp;
43 {
44         struct sockaddr_in ip_udpbind;
45
46         CK_IFNULL(ifp);
47         CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
48
49         if((ifp->status & IF_STAT_OPEN)) return 1;
50
51         if(ifp->type == IF_TYPE_IPUDP){
52                 ifp->fd = socket(AF_INET, SOCK_DGRAM, 0);
53         } else {
54                 ifp->fd = socket(AF_INET, SOCK_RAW, ifp->unit);
55         }
56         if (ifp->fd<0) {
57                 PERR("opening socket");
58                 return -1;
59         }
60
61         if (fcntl(ifp->fd, F_SETFL, FNDELAY) < 0) {
62                 PERR("setting non-blocking I/O on raw socket");
63                 return -1;
64         }
65
66         if(ifp->type == IF_TYPE_IPUDP){
67                 (void)memset( (char *)&ip_udpbind, 0, sizeof(struct sockaddr) );
68                 ip_udpbind.sin_addr.s_addr = INADDR_ANY;
69                 ip_udpbind.sin_family = AF_INET;
70                 ip_udpbind.sin_port = htons((unsigned short)ifp->unit);
71                 if(bind(ifp->fd,(struct sockaddr *)&ip_udpbind,sizeof ip_udpbind)<0){
72                         PERR("binding udp socket");
73                         return -1;
74                 }
75         }
76
77         ifp->status = IF_STAT_OPEN;
78         return 1;
79 }
80
81
82 /*
83  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
84  * Read data from the specified interface. Return a complete IP datagram.
85  * If the datagram is not complete, then don't return anything.
86  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
87  */
88 int ip_read(ifp, m)
89 struct interface *ifp;
90 struct message *m;
91 {
92         unsigned char buf[MAX_SIZE], *p;
93         int n, hdr_len;
94         unsigned int fromlen;
95 #ifdef LINUX
96         struct iphdr *ipptr;
97 #else
98         struct ip *ipptr;
99 #endif
100         struct sockaddr_in ip_from;
101
102         CK_IFNULL(ifp);
103         CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
104         CK_IFOPEN(ifp);
105         CK_MNULL(m);
106
107         (void)memset((char *)&ip_from, 0, sizeof(struct sockaddr));
108         ip_from.sin_family = AF_INET;
109         fromlen = sizeof ip_from;
110
111         n = recvfrom(ifp->fd, (char *)buf, MAX_SIZE, 0,(struct sockaddr *)&ip_from, &fromlen);
112         if(n<0){
113                 m->length = 0;
114                 if(errno==EINTR)return 0;
115                 if(errno==EWOULDBLOCK)return 0;
116                 PERR("recvfrom: on socket");
117                 return -1;
118         }
119
120         if(n==0)return 0;
121
122         if(ifp->type == IF_TYPE_IPUDP){
123                 p = buf;
124         } else {
125 #ifdef LINUX
126                 ipptr = (struct iphdr *)buf;
127                 hdr_len = 4 * ipptr->ihl;
128 #else
129                 ipptr = (struct ip *)buf;
130                 hdr_len = 4 * ipptr->ip_hl;
131 #endif
132                 p = buf + hdr_len;
133                 n = n - hdr_len;
134         }
135
136         (void)memcpy((char *)m->msg,(char *)p, n);
137         m->length = n;
138         (void)memcpy( (char *)&(m->fip), (char *)&ip_from.sin_addr, 4);
139         m->fport = ip_from.sin_port;
140         return n;
141 }
142
143 /*
144  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
145  * write data from to the specified interface. Return as soon as possible.
146  * The buffer provided will be a complete IP datagram.
147  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
148  */
149 int ip_send(ifp, m)
150 struct interface *ifp;
151 struct message *m;
152 {
153         int n;
154         struct sockaddr_in ip_to;
155
156         CK_IFNULL(ifp);
157         CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
158         CK_IFOPEN(ifp);
159         CK_MNULL(m);
160
161         if(m->length<=0)return 0;
162
163         if((long)m->tip==0){
164                 syslog(LOG_WARNING,"attempt to send to IP address 0.0.0.0");
165                 return 0;
166         }
167
168         if((ifp->type==IF_TYPE_IPUDP)&&(m->tport==0)){
169                 syslog(LOG_WARNING,"attempt to send to UDP port 0");
170                 return 0;
171         }
172
173         (void)memset( (char *)&ip_to, 0, sizeof(struct sockaddr) );
174         ip_to.sin_family = AF_INET;
175         ip_to.sin_port = m->tport;
176         (void)memcpy((char *)&ip_to.sin_addr, (char *)&(m->tip), 4);
177
178         n = sendto(ifp->fd, (char *)m->msg, m->length, 0,
179                         (struct sockaddr *)&ip_to, sizeof ip_to);
180         if(n<0){
181                 /* Log errors but don't die, since most errors are transient */
182                 char bugger[80];
183                 unsigned char *p = (unsigned char *)&m->tip;
184                 sprintf(bugger,
185                         "ip_send(dest:%d.%d.%d.%d) sendto(): %s",
186                         p[0], p[1], p[2], p[3], strerror (errno) ) ;
187                 PERR(bugger);
188                 return 0;               /* Who cares?  Continue. */
189         }
190
191         return n;
192 }