udp.c is the interace for the udp protocol.
1 /*
2 udp.c
3 Copyright 1995 Philip Homburg
4 */
5 #include "inet.h"
6 #include "type.h"
7 #include "assert.h"
8 #include "buf.h"
9 #include "clock.h"
10 #include "icmp_lib.h"
11 #include "io.h"
12 #include "ip.h"
13 #include "sr.h"
14 #include "udp.h"
15 THIS_FILE
UDP_FD_NR is the size of the udp fd table udp_fd_table.
16 #define UDP_FD_NR 32
Used to calculate hash value for the up_port_hash table in the udp_port_t structure.
17 #define UDP_PORT_HASH_NR 16 /* Must be a power of 2 */
udp_port is the data structure which holds information about the the udp interface
to the network interface. There is a 1-1 relationship between the udp_port elements
and the network interfaces.
18 typedef struct udp_port
19 {
up_flags, up_state: state of port table element.
20 int up_flags;
21 int up_state;
up_ipfd: index in to fd table of ip protocol.
22 int up_ipfd;
up_minor: corresponding minor device number.
23 int up_minor;
up_ipdev: index in to port table of ip interface.
24 int up_ipdev;
up_wr_pack: packet to write.
25 acc_t *up_wr_pack;
up_ipaddr: ip address if the ip address is set for the associated ip device/interface.
26 ipaddr_t up_ipaddr;
up_next_fd: first element in the fd table to tries to send when inet tries to send all
unsent packets in the function restart_write_port.
27 struct udp_fd *up_next_fd;
up_write_fd: current element in the fd table which inet is trying to write for udp.
28 struct udp_fd *up_write_fd;
up_port_any: head of linked list of fds which receive messages on any local port.
29 struct udp_fd *up_port_any;
udp_fd: hash table of fds which receive messages on a particular local port.
30 struct udp_fd *up_port_hash[UDP_PORT_HASH_NR];
31 } udp_port_t;
32 #define UPF_EMPTY 0x0
33 #define UPF_WRITE_IP 0x1
34 #define UPF_WRITE_SP 0x2
35 #define UPF_READ_IP 0x4
36 #define UPF_READ_SP 0x8
37 #define UPF_SUSPEND 0x10
38 #define UPF_MORE2WRITE 0x20
Used in the field up_state in udp_port.
UPS_EMPTY = before any configuration of channel.
39 #define UPS_EMPTY 0
UPS_SETPROTO = Beginning configuration of ip channel.
40 #define UPS_SETPROTO 1
UPS_GETCONF = IP Channel has been configured using the NWIOSIPOPT ioctl call for the ip device.
41 #define UPS_GETCONF 2
UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.
42 #define UPS_MAIN 3
UPS_ERROR = Error has occurred.
43 #define UPS_ERROR 4
44 typedef struct udp_fd
45 {
uf_flags: state of fd table element.
46 int uf_flags;
uf_port: points to the port table entry in udp_port_table used by fd.
2 udp channels (ie elements in the udp_fd_table) have the same uf_port if and
only if they are channels for the same network interface. This is done for
the following reason. The IP interface can only look at the ip header in
determining where else to send a particular messsage to after it has processed
it. The IP header tells what lower level protocol (ie TCP/IP, UDP/IP, etc.) the
message is using ie it can not look at the local port number. Hence the IP interface
sends the message to the interface which implements the lower level protocol. The
udp_port_t structure is the structure which the ip interface sends the message to
because it relates the udp interface to the ip interface.
47 udp_port_t *uf_port;
uf_ioreq: current ioctl request.
ioreq_t is type-defined as an int in inet/inet.h.
48 ioreq_t uf_ioreq;
uf_srfd: index to sr_fd_table in sr.c ie index for channel.
49 int uf_srfd;
struct nwio_udpopt is defined in include/net/gen/udp_io.h
nwuo_locport is the local port.
nwuo_remport is the remote port.
nwuo_locaddr is the local address.
nwuo_remaddr is the remote address.
50 nwio_udpopt_t uf_udpopt;
uf_get_userdata: pointer to sr_get_userdata in sr.c.
51 get_userdata_t uf_get_userdata;
uf_put_userdata: pointer to sr_put_userdata in sr.c.
52 put_userdata_t uf_put_userdata;
uf_rdbuf_head: head of queue of received packets which are waiting to be read.
Next pointer for queue is the acc_ext_link field for the acc_t accessor structure.
53 acc_t *uf_rdbuf_head;
uf_rdbuf_tail: tail of queue to received packets which are waiting to be read.
Next pointer for queue is the acc_ext_link field for the acc_t accessor structure.
54 acc_t *uf_rdbuf_tail;
uf_rd_count: set in the read system call. Declares how many bytes to be read to buffer.
55 size_t uf_rd_count;
uf_wr_count: set in the write system call. Declares how many bytes to be written from buffer.
56 size_t uf_wr_count;
uf_exp_tim: expiration time of packet. If the expiration time is before time that packet is read, the packet is dumped and not read.
57 time_t uf_exp_tim;
uf_port_next: next pointer in linked list or hashtable of currently used port table entries.
58 struct udp_fd *uf_port_next;
59 } udp_fd_t;
60 #define UFF_EMPTY 0x0
61 #define UFF_INUSE 0x1
62 #define UFF_IOCTL_IP 0x2
63 #define UFF_READ_IP 0x4
64 #define UFF_WRITE_IP 0x8
65 #define UFF_OPTSET 0x10
66 FORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));
67 FORWARD void udp_buffree ARGS(( int priority ));
68 #ifdef BUF_CONSISTENCY_CHECK
69 FORWARD void udp_bufcheck ARGS(( void ));
70 #endif
71 FORWARD void udp_main ARGS(( udp_port_t *udp_port ));
72 FORWARD acc_t *udp_get_data ARGS(( int fd, size_t offset, size_t count,
73 int for_ioctl ));
74 FORWARD int udp_put_data ARGS(( int fd, size_t offset, acc_t *data,
75 int for_ioctl ));
76 FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));
77 FORWARD void udp_ip_arrived ARGS(( int port, acc_t *pack, size_t pack_size ));
78 FORWARD void reply_thr_put ARGS(( udp_fd_t *udp_fd, int reply,
79 int for_ioctl ));
80 FORWARD void reply_thr_get ARGS(( udp_fd_t *udp_fd, int reply,
81 int for_ioctl ));
82 FORWARD int udp_setopt ARGS(( udp_fd_t *udp_fd ));
83 FORWARD udpport_t find_unused_port ARGS(( int fd ));
84 FORWARD int is_unused_port ARGS(( Udpport_t port ));
85 FORWARD int udp_packet2user ARGS(( udp_fd_t *udp_fd ));
86 FORWARD void restart_write_fd ARGS(( udp_fd_t *udp_fd ));
87 FORWARD u16_t pack_oneCsum ARGS(( acc_t *pack ));
88 FORWARD void udp_rd_enqueue ARGS(( udp_fd_t *udp_fd, acc_t *pack,
89 time_t exp_tim ));
90 FORWARD void hash_fd ARGS(( udp_fd_t *udp_fd ));
91 FORWARD void unhash_fd ARGS(( udp_fd_t *udp_fd ));
92 PRIVATE udp_port_t udp_port_table[UDP_PORT_NR];
93 PRIVATE udp_fd_t udp_fd_table[UDP_FD_NR];
udp_init(): does initialization. Initializes udp port tables so that uc_minor
is the appropriate minor device number and uc_port is the index to the appropriate
ip port table entry (ie network interface). It calls sr_add_minor to add itself
with the appropriate minor device number in to the sr fd table. sr_add_minor
sets the fields of the sr_fd structure to the udp specific values and functions
except for the fields srf_flags and srf_port. srf_flags is used to store the
state of the sr_fd structure. It also calls udp_main to do some intialization.
When udp_main is called in udp_init, udp_port->up_state is UPS_EMPTY.
94 PUBLIC void udp_init()
95 {
96 udp_fd_t *udp_fd;
97 udp_port_t *udp_port;
98 int i, j, result;
99 assert (BUF_S >= sizeof(struct nwio_ipopt));
100 assert (BUF_S >= sizeof(struct nwio_ipconf));
101 assert (BUF_S >= sizeof(struct nwio_udpopt));
102 assert (BUF_S >= sizeof(struct udp_io_hdr));
103 assert (UDP_HDR_SIZE == sizeof(udp_hdr_t));
104 assert (UDP_IO_HDR_SIZE == sizeof(udp_io_hdr_t));
105 #if ZERO
106 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
107 {
108 udp_fd->uf_flags= UFF_EMPTY;
109 udp_fd->uf_rdbuf_head= NULL;
110 }
111 #endif
Set udp_buffree to be the function to call when freeing accessor in buf.c.
112 #ifndef BUF_CONSISTENCY_CHECK
113 bf_logon(udp_buffree);
114 #else
115 bf_logon(udp_buffree, udp_bufcheck);
116 #endif
117 for (i= 0, udp_port= udp_port_table; i<UDP_PORT_NR; i++, udp_port++)
118 {
Set up_minor to the minor device number.
119 udp_port->up_minor= udp_conf[i].uc_minor;
Set up_ipdev to the index to the ip port table.
120 udp_port->up_ipdev= udp_conf[i].uc_port;
121 #if ZERO
122 udp_port->up_flags= UPF_EMPTY;
123 udp_port->up_state= UPS_EMPTY;
124 #endif
125 udp_port->up_next_fd= udp_fd_table;
126 #if ZERO
127 udp_port->up_write_fd= NULL;
128 udp_port->up_port_any= NULL;
129 for (j= 0; j<UDP_PORT_HASH_NR; j++)
130 udp_port->up_port_hash[j]= NULL;
131 #endif
Add to sr_fd_table.
132 result= sr_add_minor (udp_port->up_minor,
133 udp_port-udp_port_table, udp_open, udp_close, udp_read,
134 udp_write, udp_ioctl, udp_cancel);
135 assert (result >= 0);
Perform initialization with up_state = UPS_EMPTY.
136 udp_main(udp_port);
137 }
138 }
udp_main performs initialization routines depending on the state the udp is in
as determined by up_state.
139 PRIVATE void udp_main(udp_port)
140 udp_port_t *udp_port;
141 {
142 udp_fd_t *udp_fd;
143 int result, i;
144 switch (udp_port->up_state)
145 {
UPS_EMPTY = before any configuration of channel.
146 case UPS_EMPTY:
UPS_SETPROTO = Beginning configuration of ip channel.
147 udp_port->up_state= UPS_SETPROTO;
get index to ip channel array.
udp_put_data returns data specific to the udp port table (eg ip errors and ip ioctl calls).
udp_ip_arrived returns data specific to a udp fd table (eg read calls).
148 udp_port->up_ipfd= ip_open(udp_port->up_ipdev,
149 udp_port-udp_port_table, udp_get_data, udp_put_data,
150 udp_ip_arrived);
151 if (udp_port->up_ipfd < 0)
152 {
153 udp_port->up_state= UPS_ERROR;
154 DBLOCK(1, printf("%s, %d: unable to open ip port\n",
155 __FILE__, __LINE__));
156 return;
157 }
Configure ip channel by using the NWIOSIPOPT ioctl.
158 result= ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT);
Configuration could not be completed if result == NW_SUSPEND. Suspend until
the NWIOSIPOPT ioctl call can be completed.
159 if (result == NW_SUSPEND)
160 udp_port->up_flags |= UPF_SUSPEND;
161 if (result<0)
162 {
163 return;
164 }
If configuration of ip channel could be completed sucessfully udp_port->up_state
should have been changed to UPS_GETCONF.
165 if (udp_port->up_state != UPS_GETCONF)
166 return;
167 /* drops through */
UPS_GETCONF = IP Channel has been configured using the NWIOSIPOPT ioctl call for the ip device.
168 case UPS_GETCONF:
Unsuspend the udp port.
169 udp_port->up_flags &= ~UPF_SUSPEND;
Get network address of network interface
170 result= ip_ioctl(udp_port->up_ipfd, NWIOGIPCONF);
Getting network address could not be completed if result == NW_SUSPEND. Suspend until
the NWIOGIPCONF ioctl call can be completed.
171 if (result == NW_SUSPEND)
172 udp_port->up_flags |= UPF_SUSPEND;
173 if (result<0)
174 {
175 return;
176 }
If getting network address could be completed sucessfully udp_port->up_state
should have been changed to UPS_MAIN.
177 if (udp_port->up_state != UPS_MAIN)
178 return;
179 /* drops through */
UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.
180 case UPS_MAIN:
Unsuspend the udp port.
181 udp_port->up_flags &= ~UPF_SUSPEND;
Look for any fds in the udp_fd_table array which are using the network interface.
182 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
183 {
184 if (!(udp_fd->uf_flags & UFF_INUSE))
185 continue;
186 if (udp_fd->uf_port != udp_port)
187 continue;
Run any ioctl calls which have been suspended.
188 if (udp_fd->uf_flags & UFF_IOCTL_IP)
189 udp_ioctl(i, udp_fd->uf_ioreq);
190 }
Read any ip packets which have been received.
191 read_ip_packets(udp_port);
192 return;
193 default:
194 DBLOCK(1, printf("udp_port_table[%d].up_state= %d\n",
195 udp_port-udp_port_table, udp_port->up_state));
196 ip_panic(( "unknown state" ));
197 break;
198 }
199 }
Implements the open system call on a udp device.
udp_open returns an index in to the udp fd table for the udp/ip channel.
200 int udp_open (port, srfd, get_userdata, put_userdata, put_pkt)
201 int port;
202 int srfd;
203 get_userdata_t get_userdata;
204 put_userdata_t put_userdata;
205 put_pkt_t put_pkt;
206 {
207 int i;
208 udp_fd_t *udp_fd;
209 for (i= 0; i<UDP_FD_NR && (udp_fd_table[i].uf_flags & UFF_INUSE);
210 i++);
211 if (i>= UDP_FD_NR)
212 {
213 DBLOCK(1, printf("out of fds\n"));
214 return EOUTOFBUFS;
215 }
216 udp_fd= &udp_fd_table[i];
Marks a upd fd as used.
217 udp_fd->uf_flags= UFF_INUSE;
218 udp_fd->uf_port= &udp_port_table[port];
219 udp_fd->uf_srfd= srfd;
220 udp_fd->uf_udpopt.nwuo_flags= UDP_DEF_OPT;
Sets the appropriate functions to get and put messages from and to a sr channel.
221 udp_fd->uf_get_userdata= get_userdata;
222 udp_fd->uf_put_userdata= put_userdata;
223 assert(udp_fd->uf_rdbuf_head == NULL);
224 udp_fd->uf_port_next= NULL;
Returns the index to the udp_fd_table for the udp channel.
225 return i;
226 }
udp_get_data is called by the ip interface. It is called with count != 0 to get the
data (usually passed by the user eg a write system call) to the inet process. It is
called with count = 0 to return an integer result (eg the integer result in a write sytem call).
227 PRIVATE acc_t *udp_get_data (port, offset, count, for_ioctl)
228 int port;
229 size_t offset;
230 size_t count;
231 int for_ioctl;
232 {
233 udp_port_t *udp_port;
234 udp_fd_t *udp_fd;
235 int result;
236 udp_port= &udp_port_table[port];
237 switch(udp_port->up_state)
238 {
UPS_SETPROTO = Beginning configuration of ip channel.
Called by the ip interface when the udp interface calls ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT) in udp_main().
239 case UPS_SETPROTO:
240 assert (for_ioctl);
241 if (!count)
Returns integer result of NWIOSIPOPT ioctl call. If result >= 0 the ioctl call was successful.
If it was successful, then get the ip address by calling udp_main() in state UPS_GETCONF.
242 {
243 result= (int)offset;
244 if (result<0)
245 {
246 udp_port->up_state= UPS_ERROR;
247 break;
248 }
249 udp_port->up_state= UPS_GETCONF;
250 if (udp_port->up_flags & UPF_SUSPEND)
251 udp_main(udp_port);
252 return NULL;
253 }
254 else
Returns the nwio_ipopt structure which is passed to the ip interface in a NWIOSIPOPT ioctl call.
255 {
256 struct nwio_ipopt *ipopt;
257 acc_t *acc;
258 assert (!offset);
259 assert (count == sizeof(*ipopt));
260 acc= bf_memreq(sizeof(*ipopt));
261 ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
262 ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC |
263 NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC |
264 NWIO_HDR_O_ANY | NWIO_RWDATALL;
265 ipopt->nwio_proto= IPPROTO_UDP;
266 return acc;
267 }
UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.
268 case UPS_MAIN:
269 assert (!for_ioctl);
270 assert (udp_port->up_flags & UPF_WRITE_IP);
271 if (!count)
If called with count = 0 it returns an integer result (eg the integer result in a write system call).
272 {
273 result= (int)offset;
274 assert (udp_port->up_wr_pack);
275 bf_afree(udp_port->up_wr_pack);
276 udp_port->up_wr_pack= 0;
udp_get_data checks if the port is susupended on a write call.
UPF_WRITE_SP means suspended on a write system call.
udp_get_data checks if the port is susupended on a write call.
277 if (udp_port->up_flags & UPF_WRITE_SP)
278 {
If so it attempts to rewrite the message stored in up_write_fd. up_write_fd stores the first fd which has a suspended write call.
279 if (udp_port->up_write_fd)
280 {
281 udp_fd= udp_port->up_write_fd;
282 udp_port->up_write_fd= NULL;
283 udp_fd->uf_flags &= ~UFF_WRITE_IP;
284 reply_thr_get(udp_fd, result, FALSE);
285 }
286 udp_port->up_flags &= ~(UPF_WRITE_SP |
287 UPF_WRITE_IP);
If there is still a suspended write call it attempts to restart them by calling udp_restart_write_port.
288 if (udp_port->up_flags & UPF_MORE2WRITE)
289 {
290 udp_restart_write_port(udp_port);
291 }
292 }
293 else
Mark udp_port as no longer writing.
294 udp_port->up_flags &= ~UPF_WRITE_IP;
295 }
296 else
If called with count != 0 it returns data (usually passed by the user process).
297 {
298 return bf_cut (udp_port->up_wr_pack, offset, count);
299 }
300 break;
301 default:
302 #if !CRAMPED
303 printf("udp_get_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
304 port, offset, count, udp_port->up_state);
305 #endif
306 break;
307 }
308 return NULL;
309 }
udp_put_data is called by the ip protocol interface. udp_put_data returns data specific to the
udp port table (eg ip errors and ip ioctl calls). It is called with count != 0 to send the data (usually passed by
the user eg a read system call) to udp and often to the user process. It is called with count = 0 to return an
integer result (eg the integer result in a read sytem call).
310 PRIVATE int udp_put_data (fd, offset, data, for_ioctl)
311 int fd;
312 size_t offset;
313 acc_t *data;
314 int for_ioctl;
315 {
316 udp_port_t *udp_port;
317 int result;
318 udp_port= &udp_port_table[fd];
319 switch (udp_port->up_state)
320 {
UPS_GETCONF = IP Channel has been configured using the NWIOSIPOPT ioctl call for the ip device.
Next step is to get the ip address of the ip channel.
321 case UPS_GETCONF:
322 if (!data)
Returns integer result of NWIOGIPCONF ioctl call. If result >= 0 the ioctl call was successful.
If it was successful, then start reading packets by calling udp_main() in state UPF_SUSPEND.
323 {
324 result= (int)offset;
325 if (result<0)
326 {
327 udp_port->up_state= UPS_ERROR;
328 return NW_OK;
329 }
330 udp_port->up_state= UPS_MAIN;
331 if (udp_port->up_flags & UPF_SUSPEND)
332 udp_main(udp_port);
333 }
334 else
Set IP Address. Returned from the NWIOGIPCONF IOCTL system call.
335 {
336 struct nwio_ipconf *ipconf;
337 data= bf_packIffLess(data, sizeof(*ipconf));
338 ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
339 assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
340 udp_port->up_ipaddr= ipconf->nwic_ipaddr;
341 bf_afree(data);
342 }
343 break;
UPS_MAIN = IP Channel has reported the ip address of the channel to the upd interface. udp channel has been configured.
udp_put_data is called in mode UPS_MAIN after udp is configured so that ip should be performing a read/ ioctl.
344 case UPS_MAIN:
345 assert(0);
346 assert (udp_port->up_flags & UPF_READ_IP);
347 if (!data)
If called with data = NULL it returns either an integer result to a ioctl call or reports an error.
Since no ioctl calls should be made to the ip device when up_state = UPS_MAIN, the result (ie offset)
should be less than 0 to report an error.
348 {
349 result= (int)offset;
350 compare (result, >=, 0);
After the integer result is passed, udp_put_data checks if the port is suspended on a read call.
If so it attempts to restart reading the messages by calling read_ip_packets.
351 if (udp_port->up_flags & UPF_READ_SP)
352 {
353 udp_port->up_flags &= ~(UPF_READ_SP|
354 UPF_READ_IP);
355 read_ip_packets(udp_port);
356 }
357 else
358 udp_port->up_flags &= ~UPF_READ_IP;
359 }
360 else
361 {
Not a valid assertion because it is returning a data from a read system call which is not
data specific to a udp port table entry but specific to a udp fd table entry ie a udp channel.
IP interface should be using udp_ip_arrived to return the data.
362 assert (!offset); /* This isn't a valid assertion but ip sends only
363 * whole datagrams up */
364 udp_ip_arrived(fd, data, bf_bufsize(data));
365 }
366 break;
367 default:
368 ip_panic((
369 "udp_put_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
370 fd, offset, data, udp_port->up_state ));
371 }
372 return NW_OK;
373 }
Implements the ioctl system call on the UDP device.
374 int udp_ioctl (fd, req)
375 int fd;
376 ioreq_t req;
377 {
378 udp_fd_t *udp_fd;
379 udp_port_t *udp_port;
380 nwio_udpopt_t *udp_opt;
381 acc_t *opt_acc;
382 int result;
383 udp_fd= &udp_fd_table[fd];
384 assert (udp_fd->uf_flags & UFF_INUSE);
385 udp_port= udp_fd->uf_port;
Marks the udp channel as processing a IOCTL call.
386 udp_fd->uf_flags |= UFF_IOCTL_IP;
Saves the IOCTL request in case IOCTL call gets suspended.
387 udp_fd->uf_ioreq= req;
Suspend call if ip channel has not been fully configured and returned ip address.
388 if (udp_port->up_state != UPS_MAIN)
389 return NW_SUSPEND;
390 switch(req)
391 {
Implements the ioctl system call on the UDP device with parameter NWIOSUDPOPT.
Description of the ioctl system call is given in the ip(4) manual
here.
Therefore descriptions will be brief.
392 case NWIOSUDPOPT:
393 result= udp_setopt(udp_fd);
394 break;
Implements the ioctl system call on the UDP device with parameter NWIOGUDPOPT.
Description of the ioctl system call is given in the ip(4) manual
here.
Therefore descriptions will be brief.
395 case NWIOGUDPOPT:
396 opt_acc= bf_memreq(sizeof(*udp_opt));
397 assert (opt_acc->acc_length == sizeof(*udp_opt));
398 udp_opt= (nwio_udpopt_t *)ptr2acc_data(opt_acc);
399 *udp_opt= udp_fd->uf_udpopt;
Set local IP Address to nwuo_locaddr.
400 udp_opt->nwuo_locaddr= udp_fd->uf_port->up_ipaddr;
401 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, 0, opt_acc,
402 TRUE);
403 if (result == NW_OK)
404 reply_thr_put(udp_fd, NW_OK, TRUE);
405 break;
406 default:
407 reply_thr_get(udp_fd, EBADIOCTL, TRUE);
408 result= NW_OK;
409 break;
410 }
If IOCTL call was processed marked the udp channel as no longer processing the IOCTL call.
411 if (result != NW_SUSPEND)
412 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
413 return result;
414 }
Implements the ioctl system call on the UDP device with parameter NWIOGUDPOPT.
Description of the ioctl system call is given in the ip(4) manual
here.
415 PRIVATE int udp_setopt(udp_fd)
416 udp_fd_t *udp_fd;
417 {
418 udp_fd_t *fd_ptr;
419 nwio_udpopt_t oldopt, newopt;
420 acc_t *data;
421 int result;
422 udpport_t port;
423 unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags,
424 all_flags, flags;
425 unsigned long new_flags;
426 int i;
427 data= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
428 sizeof(nwio_udpopt_t), TRUE);
429 if (!data)
430 return EFAULT;
431 data= bf_packIffLess(data, sizeof(nwio_udpopt_t));
432 assert (data->acc_length == sizeof(nwio_udpopt_t));
433 newopt= *(nwio_udpopt_t *)ptr2acc_data(data);
434 bf_afree(data);
435 oldopt= udp_fd->uf_udpopt;
436 old_en_flags= oldopt.nwuo_flags & 0xffff;
437 old_di_flags= (oldopt.nwuo_flags >> 16) & 0xffff;
438 new_en_flags= newopt.nwuo_flags & 0xffff;
439 new_di_flags= (newopt.nwuo_flags >> 16) & 0xffff;
440 if (new_en_flags & new_di_flags)
441 {
442 DBLOCK(1, printf("returning EBADMODE\n"));
443 reply_thr_get(udp_fd, EBADMODE, TRUE);
444 return NW_OK;
445 }
446 /* NWUO_ACC_MASK */
447 if (new_di_flags & NWUO_ACC_MASK)
448 {
449 DBLOCK(1, printf("returning EBADMODE\n"));
450 reply_thr_get(udp_fd, EBADMODE, TRUE);
451 return NW_OK;
452 /* access modes can't be disabled */
453 }
454 if (!(new_en_flags & NWUO_ACC_MASK))
455 new_en_flags |= (old_en_flags & NWUO_ACC_MASK);
456 /* NWUO_LOCPORT_MASK */
457 if (new_di_flags & NWUO_LOCPORT_MASK)
458 {
459 DBLOCK(1, printf("returning EBADMODE\n"));
460 reply_thr_get(udp_fd, EBADMODE, TRUE);
461 return NW_OK;
462 /* the loc ports can't be disabled */
463 }
464 if (!(new_en_flags & NWUO_LOCPORT_MASK))
465 {
466 new_en_flags |= (old_en_flags & NWUO_LOCPORT_MASK);
467 newopt.nwuo_locport= oldopt.nwuo_locport;
468 }
469 else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL)
470 {
471 newopt.nwuo_locport= find_unused_port(udp_fd-udp_fd_table);
472 }
473 else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
474 {
475 if (!newopt.nwuo_locport)
476 {
477 DBLOCK(1, printf("returning EBADMODE\n"));
478 reply_thr_get(udp_fd, EBADMODE, TRUE);
479 return NW_OK;
480 }
481 }
482 /* NWUO_LOCADDR_MASK */
483 if (!((new_en_flags | new_di_flags) & NWUO_LOCADDR_MASK))
484 {
485 new_en_flags |= (old_en_flags & NWUO_LOCADDR_MASK);
486 new_di_flags |= (old_di_flags & NWUO_LOCADDR_MASK);
487 }
488 /* NWUO_BROAD_MASK */
489 if (!((new_en_flags | new_di_flags) & NWUO_BROAD_MASK))
490 {
491 new_en_flags |= (old_en_flags & NWUO_BROAD_MASK);
492 new_di_flags |= (old_di_flags & NWUO_BROAD_MASK);
493 }
494 /* NWUO_REMPORT_MASK */
495 if (!((new_en_flags | new_di_flags) & NWUO_REMPORT_MASK))
496 {
497 new_en_flags |= (old_en_flags & NWUO_REMPORT_MASK);
498 new_di_flags |= (old_di_flags & NWUO_REMPORT_MASK);
499 newopt.nwuo_remport= oldopt.nwuo_remport;
500 }
501
502 /* NWUO_REMADDR_MASK */
503 if (!((new_en_flags | new_di_flags) & NWUO_REMADDR_MASK))
504 {
505 new_en_flags |= (old_en_flags & NWUO_REMADDR_MASK);
506 new_di_flags |= (old_di_flags & NWUO_REMADDR_MASK);
507 newopt.nwuo_remaddr= oldopt.nwuo_remaddr;
508 }
509 /* NWUO_RW_MASK */
510 if (!((new_en_flags | new_di_flags) & NWUO_RW_MASK))
511 {
512 new_en_flags |= (old_en_flags & NWUO_RW_MASK);
513 new_di_flags |= (old_di_flags & NWUO_RW_MASK);
514 }
515 /* NWUO_IPOPT_MASK */
516 if (!((new_en_flags | new_di_flags) & NWUO_IPOPT_MASK))
517 {
518 new_en_flags |= (old_en_flags & NWUO_IPOPT_MASK);
519 new_di_flags |= (old_di_flags & NWUO_IPOPT_MASK);
520 }
521 new_flags= ((unsigned long)new_di_flags << 16) | new_en_flags;
522 if ((new_flags & NWUO_RWDATONLY) &&
523 ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_ANY ||
524 (new_flags & (NWUO_RP_ANY|NWUO_RA_ANY|NWUO_EN_IPOPT))))
525 {
526 DBLOCK(1, printf("returning EBADMODE\n"));
527 reply_thr_get(udp_fd, EBADMODE, TRUE);
528 return NW_OK;
529 }
530 /* Check the access modes */
531 if ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL ||
532 (new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
533 {
534 for (i= 0, fd_ptr= udp_fd_table; i<UDP_FD_NR; i++, fd_ptr++)
535 {
536 if (fd_ptr == udp_fd)
537 continue;
538 if (!(fd_ptr->uf_flags & UFF_INUSE))
539 continue;
540 if (fd_ptr->uf_port != udp_fd->uf_port)
541 continue;
542 flags= fd_ptr->uf_udpopt.nwuo_flags;
543 if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_SEL &&
544 (flags & NWUO_LOCPORT_MASK) != NWUO_LP_SET)
545 continue;
546 if (fd_ptr->uf_udpopt.nwuo_locport !=
547 newopt.nwuo_locport)
548 {
549 continue;
550 }
551 if ((flags & NWUO_ACC_MASK) !=
552 (new_flags & NWUO_ACC_MASK))
553 {
554 DBLOCK(1, printf(
555 "address inuse: new fd= %d, old_fd= %d, port= %u\n",
556 udp_fd-udp_fd_table,
557 fd_ptr-udp_fd_table,
558 newopt.nwuo_locport));
559 reply_thr_get(udp_fd, EADDRINUSE, TRUE);
560 return NW_OK;
561 }
562 }
563 }
564 if (udp_fd->uf_flags & UFF_OPTSET)
565 unhash_fd(udp_fd);
566 newopt.nwuo_flags= new_flags;
567 udp_fd->uf_udpopt= newopt;
568 all_flags= new_en_flags | new_di_flags;
569 if ((all_flags & NWUO_ACC_MASK) && (all_flags & NWUO_LOCPORT_MASK) &&
570 (all_flags & NWUO_LOCADDR_MASK) &&
571 (all_flags & NWUO_BROAD_MASK) &&
572 (all_flags & NWUO_REMPORT_MASK) &&
573 (all_flags & NWUO_REMADDR_MASK) &&
574 (all_flags & NWUO_RW_MASK) &&
575 (all_flags & NWUO_IPOPT_MASK))
576 udp_fd->uf_flags |= UFF_OPTSET;
577 else
578 {
579 udp_fd->uf_flags &= ~UFF_OPTSET;
580 }
581 if (udp_fd->uf_flags & UFF_OPTSET)
582 hash_fd(udp_fd);
583 reply_thr_get(udp_fd, NW_OK, TRUE);
584 return NW_OK;
585 }
find_unused_port() returns an unused local port.
586 PRIVATE udpport_t find_unused_port(fd)
587 int fd;
588 {
589 udpport_t port, nw_port;
590 for (port= 0x8000; port < 0xffff-UDP_FD_NR; port+= UDP_FD_NR)
591 {
592 nw_port= htons(port);
593 if (is_unused_port(nw_port))
594 return nw_port;
595 }
596 for (port= 0x8000; port < 0xffff; port++)
597 {
598 nw_port= htons(port);
599 if (is_unused_port(nw_port))
600 return nw_port;
601 }
602 ip_panic(( "unable to find unused port (shouldn't occur)" ));
603 return 0;
604 }
605 /*
606 reply_thr_put
607 */
reply_thr_put() returns an integer result to the user process processing a write or ioctl
system call.
608 PRIVATE void reply_thr_put(udp_fd, reply, for_ioctl)
609 udp_fd_t *udp_fd;
610 int reply;
611 int for_ioctl;
612 {
613 int result;
614 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, reply,
615 (acc_t *)0, for_ioctl);
616 assert(result == NW_OK);
617 }
reply_thr_get() returns an integer result to the user process processing a read or ioctl
system call.
618 /*
619 reply_thr_get
620 */
621 PRIVATE void reply_thr_get(udp_fd, reply, for_ioctl)
622 udp_fd_t *udp_fd;
623 int reply;
624 int for_ioctl;
625 {
626 acc_t *result;
627 result= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, reply,
628 (size_t)0, for_ioctl);
629 assert (!result);
630 }
is_unused_port() returns true if port is an unused port. It returns false if port is a
used port.
631 PRIVATE int is_unused_port(port)
632 udpport_t port;
633 {
634 int i;
635 udp_fd_t *udp_fd;
636 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++,
637 udp_fd++)
638 {
639 if (!(udp_fd->uf_flags & UFF_OPTSET))
640 continue;
641 if (udp_fd->uf_udpopt.nwuo_locport == port)
642 return FALSE;
643 }
644 return TRUE;
645 }
read_ip_packets reads all packets which are in the ip queue waiting to be read. read_ip_packets needs to be called
in order to ensure that packets in the queue are read at the beginning immediately after the udp interface has been
configured. If packets are in the queue, the IP interface returns those packets by calling udp_ip_arrived().
646 PRIVATE void read_ip_packets(udp_port)
647 udp_port_t *udp_port;
648 {
649 int result;
650 do
651 {
Mark that the udp interface is processing a read call on the port.
652 udp_port->up_flags |= UPF_READ_IP;
Check for packet to read.
653 result= ip_read(udp_port->up_ipfd, UDP_MAX_DATAGRAM);
If there is no such packet to read result == NW_SUSPEND.
654 if (result == NW_SUSPEND)
655 {
656 udp_port->up_flags |= UPF_READ_SP;
657 return;
658 }
659 assert(result == NW_OK);
Unmark that the udp interface is processing a read call on the port.
660 udp_port->up_flags &= ~UPF_READ_IP;
661 } while(!(udp_port->up_flags & UPF_READ_IP));
662 }
udp_read() implements read system call.
663 PUBLIC int udp_read (fd, count)
664 int fd;
665 size_t count;
666 {
667 udp_fd_t *udp_fd;
668 acc_t *tmp_acc, *next_acc;
669 udp_fd= &udp_fd_table[fd];
Check if udp channel has been configured.
670 if (!(udp_fd->uf_flags & UFF_OPTSET))
671 {
672 reply_thr_put(udp_fd, EBADMODE, FALSE);
673 return NW_OK;
674 }
Save size of data which is to be read in case read call gets suspended.
675 udp_fd->uf_rd_count= count;
Check if any data has arrived yet.
676 if (udp_fd->uf_rdbuf_head)
677 {
If packet has not expired yet, return packet to user.
678 if (get_time() <= udp_fd->uf_exp_tim)
679 return udp_packet2user (udp_fd);
If packet has expired, free all remaining packets and suspend the udp channel.
680 tmp_acc= udp_fd->uf_rdbuf_head;
681 while (tmp_acc)
682 {
683 next_acc= tmp_acc->acc_ext_link;
684 bf_afree(tmp_acc);
685 tmp_acc= next_acc;
686 }
687 udp_fd->uf_rdbuf_head= NULL;
688 }
689 udp_fd->uf_flags |= UFF_READ_IP;
690 return NW_SUSPEND;
691 }
udp_packet2user() sends packet to user.
692 PRIVATE int udp_packet2user (udp_fd)
693 udp_fd_t *udp_fd;
694 {
695 acc_t *pack, *tmp_pack;
696 udp_io_hdr_t *hdr;
697 int result, hdr_len;
698 size_t size, transf_size;
699 pack= udp_fd->uf_rdbuf_head;
700 udp_fd->uf_rdbuf_head= pack->acc_ext_link;
701 size= bf_bufsize (pack);
NWUO_RWDATONLY = only the data part of a UDP packet is sent to the server and only the data part is received from the server.
702 if (udp_fd->uf_udpopt.nwuo_flags & NWUO_RWDATONLY)
703 {
If NWUO_RWDATONLY is set then the udp_io_hdr_t header and any ip options following the header is not returned at the start of the udp packet.
704 pack= bf_packIffLess (pack, UDP_IO_HDR_SIZE);
705 assert (pack->acc_length >= UDP_IO_HDR_SIZE);
706 hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
707 #if CONF_UDP_IO_NW_BYTE_ORDER
708 hdr_len= UDP_IO_HDR_SIZE+NTOHS(hdr->uih_ip_opt_len);
709 #else
710 hdr_len= UDP_IO_HDR_SIZE+hdr->uih_ip_opt_len;
711 #endif
712 assert (size>= hdr_len);
713 size -= hdr_len;
714 tmp_pack= bf_cut(pack, hdr_len, size);
715 bf_afree(pack);
716 pack= tmp_pack;
717 }
The new packet is returned adjusting for the size as stored in uf_rd_count which was set by the read system call.
718 if (size>udp_fd->uf_rd_count)
719 {
720 tmp_pack= bf_cut (pack, 0, udp_fd->uf_rd_count);
721 bf_afree(pack);
722 pack= tmp_pack;
723 transf_size= udp_fd->uf_rd_count;
724 }
725 else
726 transf_size= size;
The packet is then sent back to the user by calling uf_put_userdata.
727 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
728 (size_t)0, pack, FALSE);
729 if (result >= 0)
If size requested in the read system call is less than the size of the packet the integer result returned is EPACKSIZE.
730 if (size > transf_size)
731 result= EPACKSIZE;
732 else
If the size requested in the read system call is greater than or equal to the size of the packet, the size of the returned packet is returned as the integer result.
733 result= transf_size;
734 udp_fd->uf_flags &= ~UFF_READ_IP;
An integer result is passed backed to the user by calling uf_put_userdata again.
735 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, result,
736 (acc_t *)0, FALSE);
737 assert (result == 0);
738 return result;
739 }
udp_ip_arrived() is called by the IP interface when a packet has arrrived.
740 PRIVATE void udp_ip_arrived(port, pack, pack_size)
741 int port;
742 acc_t *pack;
743 size_t pack_size;
744 {
745 udp_port_t *udp_port;
746 udp_fd_t *udp_fd, *share_fd;
747 acc_t *ip_hdr_acc, *udp_acc, *ipopt_pack, *no_ipopt_pack, *tmp_acc;
748 ip_hdr_t *ip_hdr;
749 udp_hdr_t *udp_hdr;
750 udp_io_hdr_t *udp_io_hdr;
751 size_t ip_hdr_size, udp_size, data_size, opt_size;
752 ipaddr_t src_addr, dst_addr;
753 udpport_t src_port, dst_port;
754 u8_t u16[2];
755 u16_t chksum;
756 unsigned long dst_type, flags;
757 time_t exp_tim;
758 int i, delivered, hash;
759 udp_port= &udp_port_table[port];
760 ip_hdr_acc= bf_cut(pack, 0, IP_MIN_HDR_SIZE);
761 ip_hdr_acc= bf_packIffLess(ip_hdr_acc, IP_MIN_HDR_SIZE);
ip_hdr = ip header.
762 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
763 ip_hdr_size= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
764 if (ip_hdr_size != IP_MIN_HDR_SIZE)
765 {
766 bf_afree(ip_hdr_acc);
767 ip_hdr_acc= bf_cut(pack, 0, ip_hdr_size);
768 ip_hdr_acc= bf_packIffLess(ip_hdr_acc, ip_hdr_size);
769 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
770 }
The ip header is automatically deleted from the return packet by calling bf_delhead().
771 udp_acc= bf_delhead(pack, ip_hdr_size);
772 pack= NULL;
773 pack_size -= ip_hdr_size;
774 if (pack_size < UDP_HDR_SIZE)
775 {
776 DBLOCK(1, printf("packet too small\n"));
777 bf_afree(ip_hdr_acc);
778 bf_afree(udp_acc);
779 return;
780 }
781 udp_acc= bf_packIffLess(udp_acc, UDP_HDR_SIZE);
udp_hdr = udp header.
782 udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_acc);
783 udp_size= ntohs(udp_hdr->uh_length);
784 if (udp_size > pack_size)
785 {
786 DBLOCK(1, printf("packet too large\n"));
787 bf_afree(ip_hdr_acc);
788 bf_afree(udp_acc);
789 return;
790 }
src_addr = source ip address.
791 src_addr= ip_hdr->ih_src;
dst_addr = destination ip address.
792 dst_addr= ip_hdr->ih_dst;
Next there is a checksum check.
793 if (udp_hdr->uh_chksum)
794 {
795 u16[0]= 0;
796 u16[1]= ip_hdr->ih_proto;
797 chksum= pack_oneCsum(udp_acc);
798 chksum= oneC_sum(chksum, (u16_t *)&src_addr, sizeof(ipaddr_t));
799 chksum= oneC_sum(chksum, (u16_t *)&dst_addr, sizeof(ipaddr_t));
800 chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
801 chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length,
802 sizeof(udp_hdr->uh_length));
803 if (~chksum & 0xffff)
804 {
805 DBLOCK(1, printf("checksum error in udp packet\n");
806 printf("src ip_addr= ");
807 writeIpAddr(src_addr);
808 printf(" dst ip_addr= ");
809 writeIpAddr(dst_addr);
810 printf("\n");
811 printf("packet chksum= 0x%x, sum= 0x%x\n",
812 udp_hdr->uh_chksum, chksum));
813 bf_afree(ip_hdr_acc);
814 bf_afree(udp_acc);
815 return;
816 }
817 }
exp_tim = expiration time.
818 exp_tim= get_time() + UDP_READ_EXP_TIME;
src_port = source port.
819 src_port= udp_hdr->uh_src_port;
dst_port = destination port.
820 dst_port= udp_hdr->uh_dst_port;
821 /* Send an ICMP port unreachable if the packet could not be
822 * delivered.
823 */
824 delivered= 0;
From Minix Manual
The locaddr flags control the reception of packets. NWUO_EN_LOC enables
the reception of packets with the local IP address as destination.
NWUO_DI_LOC disables the reception of packet for the local IP address.
The broad flags control the reception of broadcast packets.
NWUO_EN_BROAD enables the reception of broadcast packets and
NWUO_DI_BROAD disables the reception of broadcast packets.
825 if (dst_addr == udp_port->up_ipaddr)
826 dst_type= NWUO_EN_LOC;
827 else
828 {
829 dst_type= NWUO_EN_BROAD;
830 /* Don't send ICMP error packets for broadcast packets */
831 delivered= 1;
832 }
833 DBLOCK(0x20, printf("udp: got packet from ");
834 writeIpAddr(src_addr);
835 printf(".%u to ", ntohs(src_port));
836 writeIpAddr(dst_addr);
837 printf(".%u\n", ntohs(dst_port)));
838 no_ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
839 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(no_ipopt_pack);
840 udp_io_hdr->uih_src_addr= src_addr;
841 udp_io_hdr->uih_dst_addr= dst_addr;
842 udp_io_hdr->uih_src_port= src_port;
843 udp_io_hdr->uih_dst_port= dst_port;
844 data_size = udp_size-UDP_HDR_SIZE;
Next it checks over the ip options from the ip header. If there are ip options the ip options
are placed in the packet after the udp_io_hdr and the length of the ip options is stored in the
uih_ip_opt_len field of the udp_io_hdr header.
845 #if CONF_UDP_IO_NW_BYTE_ORDER
846 udp_io_hdr->uih_ip_opt_len= HTONS(0);
847 udp_io_hdr->uih_data_len= htons(data_size);
848 #else
849 udp_io_hdr->uih_ip_opt_len= 0;
850 udp_io_hdr->uih_data_len= data_size;
851 #endif
852 no_ipopt_pack->acc_next= bf_cut(udp_acc, UDP_HDR_SIZE, data_size);
853 if (ip_hdr_size == IP_MIN_HDR_SIZE)
854 {
855 ipopt_pack= no_ipopt_pack;
856 ipopt_pack->acc_linkC++;
857 }
858 else
859 {
860 ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
861 *(udp_io_hdr_t *)ptr2acc_data(ipopt_pack)= *udp_io_hdr;
862 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(ipopt_pack);
863 opt_size = ip_hdr_size-IP_MIN_HDR_SIZE;
864 #if CONF_UDP_IO_NW_BYTE_ORDER
865 udp_io_hdr->uih_ip_opt_len= htons(opt_size);
866 #else
867 udp_io_hdr->uih_ip_opt_len= opt_size;
868 #endif
869 tmp_acc= bf_cut(ip_hdr_acc, (size_t)IP_MIN_HDR_SIZE, opt_size);
870 assert(tmp_acc->acc_linkC == 1);
871 assert(tmp_acc->acc_next == NULL);
872 ipopt_pack->acc_next= tmp_acc;
873 tmp_acc->acc_next= no_ipopt_pack->acc_next;
874 if (tmp_acc->acc_next)
875 tmp_acc->acc_next->acc_linkC++;
876 }
877 hash= dst_port;
878 hash ^= (hash >> 8);
879 hash &= (UDP_PORT_HASH_NR-1);
udp_ip_arrived next chooses to which fd(s) to send the packet.
880 for (i= 0; i<2; i++)
881 {
882 share_fd= NULL;
It first looks at the linked list whose head is pointed to by the up_port_any field of the port
table entry. up_port_any is the head of a linked list of udp fds which receive messages on any local port. Then it looks at up_port_hash which is a hash table of fds which receive messages
on a specific local port.
883 udp_fd= (i == 0) ? udp_port->up_port_any :
884 udp_port->up_port_hash[hash];
885 for (; udp_fd; udp_fd= udp_fd->uf_port_next)
886 {
udp_ip_arrived() chooses which fd(s) it sends the packet to by looking if the udp channel
and packet have the same remote IP address, remote port, and local port.
887 if (i && udp_fd->uf_udpopt.nwuo_locport != dst_port)
888 continue;
889
890 assert(udp_fd->uf_flags & UFF_INUSE);
891 assert(udp_fd->uf_flags & UFF_OPTSET);
892
893 if (udp_fd->uf_port != udp_port)
894 continue;
895 flags= udp_fd->uf_udpopt.nwuo_flags;
896 if (!(flags & dst_type))
897 continue;
898 if ((flags & NWUO_RP_SET) &&
899 udp_fd->uf_udpopt.nwuo_remport != src_port)
900 {
901 continue;
902 }
903 if ((flags & NWUO_RA_SET) &&
904 udp_fd->uf_udpopt.nwuo_remaddr != src_addr)
905 {
906 continue;
907 }
908 if (i)
909 {
910 /* Packet is considdered to be delivered */
911 delivered= 1;
912 }
913 if ((flags & NWUO_ACC_MASK) == NWUO_SHARED &&
914 (!share_fd || !udp_fd->uf_rdbuf_head))
915 {
916 share_fd= udp_fd;
917 continue;
918 }
919 if (flags & NWUO_EN_IPOPT)
920 pack= ipopt_pack;
921 else
922 pack= no_ipopt_pack;
923 pack->acc_linkC++;
udp_rd_enqueue is called to put the packet in the queue of the fd.
924 udp_rd_enqueue(udp_fd, pack, exp_tim);
If the user process with the file descriptor fd is suspended on a read at the time udp_packet2user
is called to pass the packet to the user.
925 if (udp_fd->uf_flags & UFF_READ_IP)
926 udp_packet2user(udp_fd);
927 }
928 if (share_fd)
929 {
930 flags= share_fd->uf_udpopt.nwuo_flags;
931 if (flags & NWUO_EN_IPOPT)
932 pack= ipopt_pack;
933 else
934 pack= no_ipopt_pack;
935 pack->acc_linkC++;
udp_rd_enqueue is called to put the packet in the queue of the fd.
936 udp_rd_enqueue(share_fd, pack, exp_tim);
If the user process with the file descriptor fd is suspended on a read at the time udp_packet2user
is called to pass the packet to the user.
937 if (share_fd->uf_flags & UFF_READ_IP)
938 udp_packet2user(share_fd);
939 }
940 }
941 if (ipopt_pack)
942 bf_afree(ipopt_pack);
943 if (no_ipopt_pack)
944 bf_afree(no_ipopt_pack);
945 if (!delivered)
946 {
947 DBLOCK(0x2, printf("udp: could not deliver packet from ");
948 writeIpAddr(src_addr);
949 printf(".%u to ", ntohs(src_port));
950 writeIpAddr(dst_addr);
951 printf(".%u\n", ntohs(dst_port)));
952 pack= bf_append(ip_hdr_acc, udp_acc);
953 ip_hdr_acc= NULL;
954 udp_acc= NULL;
955 icmp_snd_unreachable(udp_port->up_ipdev, pack,
956 ICMP_PORT_UNRCH);
957 return;
958 }
959 assert (ip_hdr_acc);
960 bf_afree(ip_hdr_acc);
961 assert (udp_acc);
962 bf_afree(udp_acc);
963 }
udp_close() implements the close system call on a udp file descriptor fd.
964 PUBLIC void udp_close(fd)
965 int fd;
966 {
967 udp_fd_t *udp_fd;
968 acc_t *tmp_acc, *next_acc;
969 udp_fd= &udp_fd_table[fd];
970 assert (udp_fd->uf_flags & UFF_INUSE);
Calls unhash_fd() to remove the udp channel from the hash table up_port_hash
or linked list up_port_any of the port table (uf_port) which it belonged to
because the udp channel is no longer being used.
971 if (udp_fd->uf_flags & UFF_OPTSET)
972 unhash_fd(udp_fd);
973 udp_fd->uf_flags= UFF_EMPTY;
Free all of the data it is holding.
974 tmp_acc= udp_fd->uf_rdbuf_head;
975 while (tmp_acc)
976 {
977 next_acc= tmp_acc->acc_ext_link;
978 bf_afree(tmp_acc);
979 tmp_acc= next_acc;
980 }
981 udp_fd->uf_rdbuf_head= NULL;
982 }
udp_write implements the write system call on a udp channel.
983 PUBLIC int udp_write(fd, count)
984 int fd;
985 size_t count;
986 {
987 udp_fd_t *udp_fd;
988 udp_port_t *udp_port;
989 udp_fd= &udp_fd_table[fd];
990 udp_port= udp_fd->uf_port;
Checks if udp channel has been configured.
991 if (!(udp_fd->uf_flags & UFF_OPTSET))
992 {
993 reply_thr_get (udp_fd, EBADMODE, FALSE);
994 return NW_OK;
995 }
996 assert (!(udp_fd->uf_flags & UFF_WRITE_IP));
Saves count in case write call gets suspended.
997 udp_fd->uf_wr_count= count;
998 udp_fd->uf_flags |= UFF_WRITE_IP;
Calls restart_write_fd to attempt to write the packet.
999 restart_write_fd(udp_fd);
1000 if (udp_fd->uf_flags & UFF_WRITE_IP)
1001 {
1002 DBLOCK(1, printf("replying NW_SUSPEND\n"));
1003 return NW_SUSPEND;
1004 }
1005 else
1006 {
1007 return NW_OK;
1008 }
1009 }
restart_write_fd attempts to write a packet on a udp channel.
It is called from udp_write() and udp_restart_write_port().
1010 PRIVATE void restart_write_fd(udp_fd)
1011 udp_fd_t *udp_fd;
1012 {
1013 udp_port_t *udp_port;
1014 acc_t *pack, *ip_hdr_pack, *udp_hdr_pack, *ip_opt_pack, *user_data;
1015 udp_hdr_t *udp_hdr;
1016 udp_io_hdr_t *udp_io_hdr;
1017 ip_hdr_t *ip_hdr;
1018 size_t ip_opt_size, user_data_size;
1019 unsigned long flags;
1020 u16_t chksum;
1021 u8_t u16[2];
1022 int result;
Gets udp port.
1023 udp_port= udp_fd->uf_port;
If the udp port is currently busy already trying to write a packet, restart_write_fd marks
the port as having more to write (by setting the flag UPF_MORE2WRITE) and returns
1024 if (udp_port->up_flags & UPF_WRITE_IP)
1025 {
1026 udp_port->up_flags |= UPF_MORE2WRITE;
1027 return;
1028 }
1029 assert (udp_fd->uf_flags & UFF_WRITE_IP);
1030 udp_fd->uf_flags &= ~UFF_WRITE_IP;
1031 assert (!udp_port->up_wr_pack);
It gets the data it needs to write (by calling uf_get_userdata).
1032 pack= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
1033 udp_fd->uf_wr_count, FALSE);
1034 if (!pack)
1035 {
1036 udp_fd->uf_flags &= ~UFF_WRITE_IP;
1037 reply_thr_get (udp_fd, EFAULT, FALSE);
1038 return;
1039 }
1040 flags= udp_fd->uf_udpopt.nwuo_flags;
1041 ip_hdr_pack= bf_memreq(IP_MIN_HDR_SIZE);
1042 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_pack);
1043 udp_hdr_pack= bf_memreq(UDP_HDR_SIZE);
1044 udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_hdr_pack);
If NWUO_RWDATALL is set, the udp_io_hdr_t header is part of the data packet sent to the inet process.
From Minix manual:
The rw flags control the format of the data to be sent or received. With
NWUO_RWDATONLY only the data part of a UDP packet is sent to the server
and only the data part is received from the server. The NWUO_RWDATALL
mode presents the data part of a UDP packet with a header that contains
the source and destination IP address, source and destination UDP ports,
the IP options, etc. The server expects such a header in front of the
data to be transmitted.
1045 if (flags & NWUO_RWDATALL)
1046 {
1047 pack= bf_packIffLess(pack, UDP_IO_HDR_SIZE);
pack is prefaced with udp_io_hdr_t header which must be removed before being given
to IP interface.
1048 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
ip_opt_size = length of ip options.
1049 #if CONF_UDP_IO_NW_BYTE_ORDER
1050 ip_opt_size= ntohs(udp_io_hdr->uih_ip_opt_len);
1051 #else
1052 ip_opt_size= udp_io_hdr->uih_ip_opt_len;
1053 #endif
1054 if (UDP_IO_HDR_SIZE+ip_opt_size>udp_fd->uf_wr_count)
1055 {
1056 bf_afree(ip_hdr_pack);
1057 bf_afree(udp_hdr_pack);
1058 bf_afree(pack);
1059 reply_thr_get (udp_fd, EINVAL, FALSE);
1060 return;
1061 }
1062 if (ip_opt_size & 3)
1063 {
1064 bf_afree(ip_hdr_pack);
1065 bf_afree(udp_hdr_pack);
1066 bf_afree(pack);
1067 reply_thr_get (udp_fd, EFAULT, FALSE);
1068 return;
1069 }
ip_opt_pack = ip options.
1070 if (ip_opt_size)
1071 ip_opt_pack= bf_cut(pack, UDP_IO_HDR_SIZE, ip_opt_size);
1072 else
1073 ip_opt_pack= 0;
user_data = payload data.
1074 user_data_size= udp_fd->uf_wr_count-UDP_IO_HDR_SIZE-
1075 ip_opt_size;
1076 user_data= bf_cut(pack, UDP_IO_HDR_SIZE+ip_opt_size,
1077 user_data_size);
1078 bf_afree(pack);
1079 }
1080 else
1081 {
1082 udp_io_hdr= 0;
1083 ip_opt_size= 0;
1084 user_data_size= udp_fd->uf_wr_count;
1085 ip_opt_pack= 0;
1086 user_data= pack;
1087 }
ip_hdr is a ip_hdr_t structure. The ip_hdr_t structure is defined in include/net/gen/ip_hdr.h.
The contents of the IP header are defined in
RFC 791.
The fields of ip_hdr are set to the proper values.
1088 ip_hdr->ih_vers_ihl= (IP_MIN_HDR_SIZE+ip_opt_size) >> 2;
1089 ip_hdr->ih_tos= UDP_TOS;
1090 ip_hdr->ih_flags_fragoff= HTONS(UDP_IP_FLAGS);
1091 ip_hdr->ih_ttl= UDP_TTL;
1092 ip_hdr->ih_proto= IPPROTO_UDP;
If the values of the ip header were set in the NWIOSUDPOPT ioctl call we use those
values which were stored in udp_fd->uf_udpopt. From Minix Manual: NWUO_RA_SET sets the
remote IP address the value of nwuo_remaddr. Only packets from that
address will be delivered and all packets will be sent to that address.
1093 if (flags & NWUO_RA_SET)
1094 {
1095 DBLOCK(1, printf("NWUO_RA_SET\n"));
1096 ip_hdr->ih_dst= udp_fd->uf_udpopt.nwuo_remaddr;
1097 }
1098 else
1099 {
1100 assert (udp_io_hdr);
1101 ip_hdr->ih_dst= udp_io_hdr->uih_dst_addr;
1102 }
udp_hdr is a udp_hdr_t structure. The udp_hdr_t structure is defined in include/net/gen/udp_hdr.h.
The contents of the UDP header are defined in
RFC 768.
From Minix Manual.
The locport flags control the selection of the UDP port for this channel.
NWUO_LP_SEL requests the server to pick a port. This port will be in the
range from 32768 to 65535 and it will be unique. NWUO_LP_SET sets the
local port to the value of the nwuo_locport field. NWUO_LP_ANY does not
select a port. Reception of data is therefore not possible but it is
possible to send data.
1103 if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_ANY)
1104 udp_hdr->uh_src_port= udp_fd->uf_udpopt.nwuo_locport;
1105 else
1106 {
1107 assert (udp_io_hdr);
1108 udp_hdr->uh_src_port= udp_io_hdr->uih_src_port;
1109 }
1110 if (flags & NWUO_RP_SET)
1111 udp_hdr->uh_dst_port= udp_fd->uf_udpopt.nwuo_remport;
1112 else
1113 {
1114 assert (udp_io_hdr);
1115 udp_hdr->uh_dst_port= udp_io_hdr->uih_dst_port;
1116 }
1117 udp_hdr->uh_length= htons(UDP_HDR_SIZE+user_data_size);
1118 udp_hdr->uh_chksum= 0;
1119 udp_hdr_pack->acc_next= user_data;
Set the checksum field for the udp header.
1120 chksum= pack_oneCsum(udp_hdr_pack);
1121 chksum= oneC_sum(chksum, (u16_t *)&udp_fd->uf_port->up_ipaddr,
1122 sizeof(ipaddr_t));
1123 chksum= oneC_sum(chksum, (u16_t *)&ip_hdr->ih_dst, sizeof(ipaddr_t));
1124 u16[0]= 0;
1125 u16[1]= IPPROTO_UDP;
1126 chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
1127 chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length, sizeof(u16_t));
1128 if (~chksum)
1129 chksum= ~chksum;
1130 udp_hdr->uh_chksum= chksum;
1131
If IP options are being used put the ip options into the packet sent to the IP interface.
1132 if (ip_opt_pack)
1133 {
1134 ip_opt_pack= bf_packIffLess(ip_opt_pack, ip_opt_size);
1135 ip_opt_pack->acc_next= udp_hdr_pack;
1136 udp_hdr_pack= ip_opt_pack;
1137 }
1138 ip_hdr_pack->acc_next= udp_hdr_pack;
1139 assert (!udp_port->up_wr_pack);
1140 assert (!(udp_port->up_flags & UPF_WRITE_IP));
Save packet to write in case write call get suspended.
1141 udp_port->up_wr_pack= ip_hdr_pack;
1142 udp_port->up_flags |= UPF_WRITE_IP;
1143 result= ip_write(udp_port->up_ipfd, bf_bufsize(ip_hdr_pack));
1144 if (result == NW_SUSPEND)
1145 {
1146 udp_port->up_flags |= UPF_WRITE_SP;
1147 udp_fd->uf_flags |= UFF_WRITE_IP;
1148 udp_port->up_write_fd= udp_fd;
1149 }
If write call is not suspended wake up user and return an integer value to it.
1150 else if (result<0)
1151 reply_thr_get(udp_fd, result, FALSE);
1152 else
1153 reply_thr_get (udp_fd, udp_fd->uf_wr_count, FALSE);
1154 }
pack_oneCsum is used to compute the checksum in the udp header.
1155 PRIVATE u16_t pack_oneCsum(pack)
1156 acc_t *pack;
1157 {
1158 u16_t prev;
1159 int odd_byte;
1160 char *data_ptr;
1161 int length;
1162 char byte_buf[2];
1163 assert (pack);
1164 prev= 0;
1165 odd_byte= FALSE;
1166 for (; pack; pack= pack->acc_next)
1167 {
1168
1169 data_ptr= ptr2acc_data(pack);
1170 length= pack->acc_length;
1171 if (!length)
1172 continue;
1173 if (odd_byte)
1174 {
1175 byte_buf[1]= *data_ptr;
1176 prev= oneC_sum(prev, (u16_t *)byte_buf, 2);
1177 data_ptr++;
1178 length--;
1179 odd_byte= FALSE;
1180 }
1181 if (length & 1)
1182 {
1183 odd_byte= TRUE;
1184 length--;
1185 byte_buf[0]= data_ptr[length];
1186 }
1187 if (!length)
1188 continue;
1189 prev= oneC_sum (prev, (u16_t *)data_ptr, length);
1190 }
1191 if (odd_byte)
1192 {
1193 byte_buf[1]= 0;
1194 prev= oneC_sum (prev, (u16_t *)byte_buf, 1);
1195 }
1196 return prev;
1197 }
udp_restart_write_port() is called to restart writing all suspended packets on a specific udp port.
1198 PRIVATE void udp_restart_write_port(udp_port )
1199 udp_port_t *udp_port;
1200 {
1201 udp_fd_t *udp_fd;
1202 int i;
1203 assert (!udp_port->up_wr_pack);
1204 assert (!(udp_port->up_flags & (UPF_WRITE_IP|UPF_WRITE_SP)));
UPF_MORE2WRITE is set when udp attempts to write a packet but fails because the port is currently attempting to write another packet.
1205 while (udp_port->up_flags & UPF_MORE2WRITE)
1206 {
1207 udp_port->up_flags &= ~UPF_MORE2WRITE;
Look at each of the udp channels on the udp port to see if there is a packet to write. If so then try to write it
by calling restart_write_fd().
1208 for (i= 0, udp_fd= udp_port->up_next_fd; i<UDP_FD_NR;
1209 i++, udp_fd++)
1210 {
1211 if (udp_fd == &udp_fd_table[UDP_FD_NR])
1212 udp_fd= udp_fd_table;
1213 if (!(udp_fd->uf_flags & UFF_INUSE))
1214 continue;
1215 if (!(udp_fd->uf_flags & UFF_WRITE_IP))
1216 continue;
1217 if (udp_fd->uf_port != udp_port)
1218 continue;
1219 restart_write_fd(udp_fd);
Set UPF_MORE2WRITE and return if the udp port is suspended on the attempt to write a packet.
1220 if (udp_port->up_flags & UPF_WRITE_IP)
1221 {
1222 udp_port->up_next_fd= udp_fd+1;
1223 udp_port->up_flags |= UPF_MORE2WRITE;
1224 return;
1225 }
1226 }
1227 }
1228 }
udp_cancel is called to cancel a read/write/ioctl call.
1229 PUBLIC int udp_cancel(fd, which_operation)
1230 int fd;
1231 int which_operation;
1232 {
1233 udp_fd_t *udp_fd;
1234 DBLOCK(0x10, printf("udp_cancel(%d, %d)\n", fd, which_operation));
1235 udp_fd= &udp_fd_table[fd];
Unset the flag which says the udp channel is processing the read/write/ioctl call.
1236 switch (which_operation)
1237 {
1238 case SR_CANCEL_READ:
1239 assert (udp_fd->uf_flags & UFF_READ_IP);
1240 udp_fd->uf_flags &= ~UFF_READ_IP;
1241 reply_thr_put(udp_fd, EINTR, FALSE);
1242 break;
1243 case SR_CANCEL_WRITE:
1244 assert (udp_fd->uf_flags & UFF_WRITE_IP);
1245 udp_fd->uf_flags &= ~UFF_WRITE_IP;
1246 if (udp_fd->uf_port->up_write_fd == udp_fd)
1247 udp_fd->uf_port->up_write_fd= NULL;
1248 reply_thr_get(udp_fd, EINTR, FALSE);
1249 break;
1250 case SR_CANCEL_IOCTL:
1251 assert (udp_fd->uf_flags & UFF_IOCTL_IP);
1252 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
1253 reply_thr_get(udp_fd, EINTR, TRUE);
1254 break;
1255 default:
1256 ip_panic(( "got unknown cancel request" ));
1257 }
1258 return NW_OK;
1259 }
Called in buf.c to free accessors.
1260 PRIVATE void udp_buffree (priority)
1261 int priority;
1262 {
1263 int i;
1264 time_t curr_tim;
1265 udp_fd_t *udp_fd;
1266 acc_t *tmp_acc, *next_acc;
1267 if (priority == UDP_PRI_FDBUFS_EXTRA)
1268 {
1269 for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
1270 {
1271 while (udp_fd->uf_rdbuf_head &&
1272 udp_fd->uf_rdbuf_head->acc_ext_link)
1273 {
1274 tmp_acc= udp_fd->uf_rdbuf_head;
1275 udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
1276 bf_afree(tmp_acc);
1277 }
1278 }
1279 }
1280 if (priority == UDP_PRI_FDBUFS)
1281 {
1282 for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
1283 {
1284 while (udp_fd->uf_rdbuf_head)
1285 {
1286 tmp_acc= udp_fd->uf_rdbuf_head;
1287 udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
1288 bf_afree(tmp_acc);
1289 }
1290 }
1291 }
1292 }
udp_rd_enqueue is called by udp_ip_arrived to queue a received message.
1293 PRIVATE void udp_rd_enqueue(udp_fd, pack, exp_tim)
1294 udp_fd_t *udp_fd;
1295 acc_t *pack;
1296 time_t exp_tim;
1297 {
1298 acc_t *tmp_acc;
Make a copy of the packet if it is being used by already.
1299 if (pack->acc_linkC != 1)
1300 {
1301 tmp_acc= bf_dupacc(pack);
1302 bf_afree(pack);
1303 pack= tmp_acc;
1304 }
Put at end of queue.
1305 pack->acc_ext_link= NULL;
1306 if (udp_fd->uf_rdbuf_head == NULL)
1307 {
1308 udp_fd->uf_exp_tim= exp_tim;
1309 udp_fd->uf_rdbuf_head= pack;
1310 }
1311 else
1312 udp_fd->uf_rdbuf_tail->acc_ext_link= pack;
1313 udp_fd->uf_rdbuf_tail= pack;
1314 }
hash_fd() puts upd_fd in the hash table up_port_hash (if a local port has been selected) or
in the linked list up_port_any (if a local port has not been selected) of the port table (uf_port).
1315 PRIVATE void hash_fd(udp_fd)
1316 udp_fd_t *udp_fd;
1317 {
1318 udp_port_t *udp_port;
1319 int hash;
1320 udp_port= udp_fd->uf_port;
1321 if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
1322 NWUO_LP_ANY)
up_port_any points to the head of the linked list which do not have selected local ports.
1323 {
1324 udp_fd->uf_port_next= udp_port->up_port_any;
1325 udp_port->up_port_any= udp_fd;
1326 }
1327 else
1328 {
up_port_hash points to the hash table of udp channels which have selected local ports.
1329 hash= udp_fd->uf_udpopt.nwuo_locport;
1330 hash ^= (hash >> 8);
1331 hash &= (UDP_PORT_HASH_NR-1);
1332 udp_fd->uf_port_next= udp_port->up_port_hash[hash];
1333 udp_port->up_port_hash[hash]= udp_fd;
1334 }
1335 }
unhash_fd removes the upd_fd from the hash table up_port_hash or linked list up_port_any of the port table (uf_port).
1336 PRIVATE void unhash_fd(udp_fd)
1337 udp_fd_t *udp_fd;
1338 {
1339 udp_port_t *udp_port;
1340 udp_fd_t *prev, *curr, **udp_fd_p;
1341 int hash;
1342 udp_port= udp_fd->uf_port;
1343 if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
1344 NWUO_LP_ANY)
1345 {
1346 udp_fd_p= &udp_port->up_port_any;
1347 }
1348 else
1349 {
1350 hash= udp_fd->uf_udpopt.nwuo_locport;
1351 hash ^= (hash >> 8);
1352 hash &= (UDP_PORT_HASH_NR-1);
1353 udp_fd_p= &udp_port->up_port_hash[hash];
1354 }
1355 for (prev= NULL, curr= *udp_fd_p; curr;
1356 prev= curr, curr= curr->uf_port_next)
1357 {
1358 if (curr == udp_fd)
1359 break;
1360 }
1361 assert(curr);
1362 if (prev)
1363 prev->uf_port_next= curr->uf_port_next;
1364 else
1365 *udp_fd_p= curr->uf_port_next;
1366 }
1367 #ifdef BUF_CONSISTENCY_CHECK
1368 PRIVATE void udp_bufcheck()
1369 {
1370 int i;
1371 udp_port_t *udp_port;
1372 udp_fd_t *udp_fd;
1373 acc_t *tmp_acc;
1374 for (i= 0, udp_port= udp_port_table; i<UDP_PORT_NR; i++, udp_port++)
1375 {
1376 if (udp_port->up_wr_pack)
1377 bf_check_acc(udp_port->up_wr_pack);
1378 }
1379 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
1380 {
1381 for (tmp_acc= udp_fd->uf_rdbuf_head; tmp_acc;
1382 tmp_acc= tmp_acc->acc_ext_link)
1383 {
1384 bf_check_acc(tmp_acc);
1385 }
1386 }
1387 }
1388 #endif
1389 /*
1390 * $PchId: udp.c,v 1.10 1996/08/06 06:48:05 philip Exp $
1391 */
udp.c is the interace for the udp protocol.