Imported Debian version 1.1.6
[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, fromlen;
94 #ifdef LINUX
95         struct iphdr *ipptr;
96 #else
97         struct ip *ipptr;
98 #endif
99         struct sockaddr_in ip_from;
100
101         CK_IFNULL(ifp);
102         CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
103         CK_IFOPEN(ifp);
104         CK_MNULL(m);
105
106         (void)memset((char *)&ip_from, 0, sizeof(struct sockaddr));
107         ip_from.sin_family = AF_INET;
108         fromlen = sizeof ip_from;
109
110         n = recvfrom(ifp->fd, (char *)buf, MAX_SIZE, 0,(struct sockaddr *)&ip_from, &fromlen);
111         if(n<0){
112                 m->length = 0;
113                 if(errno==EINTR)return 0;
114                 if(errno==EWOULDBLOCK)return 0;
115                 PERR("recvfrom: on socket");
116                 return -1;
117         }
118
119         if(n==0)return 0;
120
121         if(ifp->type == IF_TYPE_IPUDP){
122                 p = buf;
123         } else {
124 #ifdef LINUX
125                 ipptr = (struct iphdr *)buf;
126                 hdr_len = 4 * ipptr->ihl;
127 #else
128                 ipptr = (struct ip *)buf;
129                 hdr_len = 4 * ipptr->ip_hl;
130 #endif
131                 p = buf + hdr_len;
132                 n = n - hdr_len;
133         }
134
135         (void)memcpy((char *)m->msg,(char *)p, n);
136         m->length = n;
137         (void)memcpy( (char *)&(m->fip), (char *)&ip_from.sin_addr, 4);
138         m->fport = ip_from.sin_port;
139         return n;
140 }
141
142 /*
143  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
144  * write data from to the specified interface. Return as soon as possible.
145  * The buffer provided will be a complete IP datagram.
146  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
147  */
148 int ip_send(ifp, m)
149 struct interface *ifp;
150 struct message *m;
151 {
152         int n;
153         struct sockaddr_in ip_to;
154
155         CK_IFNULL(ifp);
156         CK_IFTYPE2(ifp,IF_TYPE_IPIP,IF_TYPE_IPUDP);
157         CK_IFOPEN(ifp);
158         CK_MNULL(m);
159
160         if(m->length<=0)return 0;
161
162         if((long)m->tip==0){
163                 syslog(LOG_WARNING,"attempt to send to IP address 0.0.0.0");
164                 return 0;
165         }
166
167         if((ifp->type==IF_TYPE_IPUDP)&&(m->tport==0)){
168                 syslog(LOG_WARNING,"attempt to send to UDP port 0");
169                 return 0;
170         }
171
172         (void)memset( (char *)&ip_to, 0, sizeof(struct sockaddr) );
173         ip_to.sin_family = AF_INET;
174         ip_to.sin_port = m->tport;
175         (void)memcpy((char *)&ip_to.sin_addr, (char *)&(m->tip), 4);
176
177         n = sendto(ifp->fd, (char *)m->msg, m->length, 0,
178                         (struct sockaddr *)&ip_to, sizeof ip_to);
179         if(n<0){
180                 /* Log errors but don't die, since most errors are transient */
181                 char bugger[80];
182                 unsigned char *p = (unsigned char *)&m->tip;
183                 sprintf(bugger,
184                         "ip_send(dest:%d.%d.%d.%d) sendto(): %s",
185                         p[0], p[1], p[2], p[3], strerror (errno) ) ;
186                 PERR(bugger);
187                 return 0;               /* Who cares?  Continue. */
188         }
189
190         return n;
191 }