|
1 /* |
|
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993 |
|
3 * The Regents of the University of California. All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. All advertising materials mentioning features or use of this software |
|
14 * must display the following acknowledgement: |
|
15 * This product includes software developed by the University of |
|
16 * California, Berkeley and its contributors. |
|
17 * 4. Neither the name of the University nor the names of its contributors |
|
18 * may be used to endorse or promote products derived from this software |
|
19 * without specific prior written permission. |
|
20 * |
|
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
31 * SUCH DAMAGE. |
|
32 * |
|
33 * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 |
|
34 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp |
|
35 */ |
|
36 |
|
37 /* |
|
38 * Changes and additions relating to SLiRP |
|
39 * Copyright (c) 1995 Danny Gasparovski. |
|
40 * |
|
41 * Please read the file COPYRIGHT for the |
|
42 * terms and conditions of the copyright. |
|
43 */ |
|
44 |
|
45 #include <slirp.h> |
|
46 #include "ip_icmp.h" |
|
47 |
|
48 #ifdef LOG_ENABLED |
|
49 struct udpstat udpstat; |
|
50 #endif |
|
51 |
|
52 struct socket udb; |
|
53 |
|
54 static u_int8_t udp_tos(struct socket *so); |
|
55 static void udp_emu(struct socket *so, struct mbuf *m); |
|
56 |
|
57 /* |
|
58 * UDP protocol implementation. |
|
59 * Per RFC 768, August, 1980. |
|
60 */ |
|
61 #ifndef COMPAT_42 |
|
62 #define UDPCKSUM 1 |
|
63 #else |
|
64 #define UDPCKSUM 0 /* XXX */ |
|
65 #endif |
|
66 |
|
67 struct socket *udp_last_so = &udb; |
|
68 |
|
69 void |
|
70 udp_init() |
|
71 { |
|
72 udb.so_next = udb.so_prev = &udb; |
|
73 } |
|
74 /* m->m_data points at ip packet header |
|
75 * m->m_len length ip packet |
|
76 * ip->ip_len length data (IPDU) |
|
77 */ |
|
78 void |
|
79 udp_input(m, iphlen) |
|
80 register struct mbuf *m; |
|
81 int iphlen; |
|
82 { |
|
83 register struct ip *ip; |
|
84 register struct udphdr *uh; |
|
85 /* struct mbuf *opts = 0;*/ |
|
86 int len; |
|
87 struct ip save_ip; |
|
88 struct socket *so; |
|
89 |
|
90 DEBUG_CALL("udp_input"); |
|
91 DEBUG_ARG("m = %lx", (long)m); |
|
92 DEBUG_ARG("iphlen = %d", iphlen); |
|
93 |
|
94 STAT(udpstat.udps_ipackets++); |
|
95 |
|
96 /* |
|
97 * Strip IP options, if any; should skip this, |
|
98 * make available to user, and use on returned packets, |
|
99 * but we don't yet have a way to check the checksum |
|
100 * with options still present. |
|
101 */ |
|
102 if(iphlen > sizeof(struct ip)) { |
|
103 ip_stripoptions(m, (struct mbuf *)0); |
|
104 iphlen = sizeof(struct ip); |
|
105 } |
|
106 |
|
107 /* |
|
108 * Get IP and UDP header together in first mbuf. |
|
109 */ |
|
110 ip = mtod(m, struct ip *); |
|
111 uh = (struct udphdr *)((caddr_t)ip + iphlen); |
|
112 |
|
113 /* |
|
114 * Make mbuf data length reflect UDP length. |
|
115 * If not enough data to reflect UDP length, drop. |
|
116 */ |
|
117 len = ntohs((u_int16_t)uh->uh_ulen); |
|
118 |
|
119 if (ip->ip_len != len) { |
|
120 if (len > ip->ip_len) { |
|
121 STAT(udpstat.udps_badlen++); |
|
122 goto bad; |
|
123 } |
|
124 m_adj(m, len - ip->ip_len); |
|
125 ip->ip_len = len; |
|
126 } |
|
127 |
|
128 /* |
|
129 * Save a copy of the IP header in case we want restore it |
|
130 * for sending an ICMP error message in response. |
|
131 */ |
|
132 save_ip = *ip; |
|
133 save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ |
|
134 |
|
135 /* |
|
136 * Checksum extended UDP header and data. |
|
137 */ |
|
138 if (UDPCKSUM && uh->uh_sum) { |
|
139 ((struct ipovly *)ip)->ih_next = 0; |
|
140 ((struct ipovly *)ip)->ih_prev = 0; |
|
141 ((struct ipovly *)ip)->ih_x1 = 0; |
|
142 ((struct ipovly *)ip)->ih_len = uh->uh_ulen; |
|
143 /* keep uh_sum for ICMP reply |
|
144 * uh->uh_sum = cksum(m, len + sizeof (struct ip)); |
|
145 * if (uh->uh_sum) { |
|
146 */ |
|
147 if(cksum(m, len + sizeof(struct ip))) { |
|
148 STAT(udpstat.udps_badsum++); |
|
149 goto bad; |
|
150 } |
|
151 } |
|
152 |
|
153 /* |
|
154 * handle DHCP/BOOTP |
|
155 */ |
|
156 if (ntohs(uh->uh_dport) == BOOTP_SERVER) { |
|
157 bootp_input(m); |
|
158 goto bad; |
|
159 } |
|
160 |
|
161 /* |
|
162 * handle TFTP |
|
163 */ |
|
164 if (ntohs(uh->uh_dport) == TFTP_SERVER) { |
|
165 tftp_input(m); |
|
166 goto bad; |
|
167 } |
|
168 |
|
169 /* |
|
170 * Locate pcb for datagram. |
|
171 */ |
|
172 so = udp_last_so; |
|
173 if (so->so_lport != uh->uh_sport || |
|
174 so->so_laddr.s_addr != ip->ip_src.s_addr) { |
|
175 struct socket *tmp; |
|
176 |
|
177 for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { |
|
178 if (tmp->so_lport == uh->uh_sport && |
|
179 tmp->so_laddr.s_addr == ip->ip_src.s_addr) { |
|
180 tmp->so_faddr.s_addr = ip->ip_dst.s_addr; |
|
181 tmp->so_fport = uh->uh_dport; |
|
182 so = tmp; |
|
183 break; |
|
184 } |
|
185 } |
|
186 if (tmp == &udb) { |
|
187 so = NULL; |
|
188 } else { |
|
189 STAT(udpstat.udpps_pcbcachemiss++); |
|
190 udp_last_so = so; |
|
191 } |
|
192 } |
|
193 |
|
194 if (so == NULL) { |
|
195 /* |
|
196 * If there's no socket for this packet, |
|
197 * create one |
|
198 */ |
|
199 if ((so = socreate()) == NULL) goto bad; |
|
200 if(udp_attach(so) == -1) { |
|
201 DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", |
|
202 errno,strerror(errno))); |
|
203 sofree(so); |
|
204 goto bad; |
|
205 } |
|
206 |
|
207 /* |
|
208 * Setup fields |
|
209 */ |
|
210 /* udp_last_so = so; */ |
|
211 so->so_laddr = ip->ip_src; |
|
212 so->so_lport = uh->uh_sport; |
|
213 |
|
214 if ((so->so_iptos = udp_tos(so)) == 0) |
|
215 so->so_iptos = ip->ip_tos; |
|
216 |
|
217 /* |
|
218 * XXXXX Here, check if it's in udpexec_list, |
|
219 * and if it is, do the fork_exec() etc. |
|
220 */ |
|
221 } |
|
222 |
|
223 so->so_faddr = ip->ip_dst; /* XXX */ |
|
224 so->so_fport = uh->uh_dport; /* XXX */ |
|
225 |
|
226 iphlen += sizeof(struct udphdr); |
|
227 m->m_len -= iphlen; |
|
228 m->m_data += iphlen; |
|
229 |
|
230 /* |
|
231 * Now we sendto() the packet. |
|
232 */ |
|
233 if (so->so_emu) |
|
234 udp_emu(so, m); |
|
235 |
|
236 if(sosendto(so,m) == -1) { |
|
237 m->m_len += iphlen; |
|
238 m->m_data -= iphlen; |
|
239 *ip=save_ip; |
|
240 DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); |
|
241 icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); |
|
242 } |
|
243 |
|
244 m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ |
|
245 |
|
246 /* restore the orig mbuf packet */ |
|
247 m->m_len += iphlen; |
|
248 m->m_data -= iphlen; |
|
249 *ip=save_ip; |
|
250 so->so_m=m; /* ICMP backup */ |
|
251 |
|
252 return; |
|
253 bad: |
|
254 m_freem(m); |
|
255 /* if (opts) m_freem(opts); */ |
|
256 return; |
|
257 } |
|
258 |
|
259 int udp_output2(struct socket *so, struct mbuf *m, |
|
260 struct sockaddr_in *saddr, struct sockaddr_in *daddr, |
|
261 int iptos) |
|
262 { |
|
263 register struct udpiphdr *ui; |
|
264 int error = 0; |
|
265 |
|
266 DEBUG_CALL("udp_output"); |
|
267 DEBUG_ARG("so = %lx", (long)so); |
|
268 DEBUG_ARG("m = %lx", (long)m); |
|
269 DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); |
|
270 DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); |
|
271 |
|
272 /* |
|
273 * Adjust for header |
|
274 */ |
|
275 m->m_data -= sizeof(struct udpiphdr); |
|
276 m->m_len += sizeof(struct udpiphdr); |
|
277 |
|
278 /* |
|
279 * Fill in mbuf with extended UDP header |
|
280 * and addresses and length put into network format. |
|
281 */ |
|
282 ui = mtod(m, struct udpiphdr *); |
|
283 ui->ui_next = ui->ui_prev = 0; |
|
284 ui->ui_x1 = 0; |
|
285 ui->ui_pr = IPPROTO_UDP; |
|
286 ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ |
|
287 /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ |
|
288 ui->ui_src = saddr->sin_addr; |
|
289 ui->ui_dst = daddr->sin_addr; |
|
290 ui->ui_sport = saddr->sin_port; |
|
291 ui->ui_dport = daddr->sin_port; |
|
292 ui->ui_ulen = ui->ui_len; |
|
293 |
|
294 /* |
|
295 * Stuff checksum and output datagram. |
|
296 */ |
|
297 ui->ui_sum = 0; |
|
298 if (UDPCKSUM) { |
|
299 if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) |
|
300 ui->ui_sum = 0xffff; |
|
301 } |
|
302 ((struct ip *)ui)->ip_len = m->m_len; |
|
303 |
|
304 ((struct ip *)ui)->ip_ttl = IPDEFTTL; |
|
305 ((struct ip *)ui)->ip_tos = iptos; |
|
306 |
|
307 STAT(udpstat.udps_opackets++); |
|
308 |
|
309 error = ip_output(so, m); |
|
310 |
|
311 return (error); |
|
312 } |
|
313 |
|
314 int udp_output(struct socket *so, struct mbuf *m, |
|
315 struct sockaddr_in *addr) |
|
316 |
|
317 { |
|
318 struct sockaddr_in saddr, daddr; |
|
319 |
|
320 saddr = *addr; |
|
321 if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { |
|
322 if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) |
|
323 saddr.sin_addr.s_addr = alias_addr.s_addr; |
|
324 else if (addr->sin_addr.s_addr == loopback_addr.s_addr || |
|
325 (ntohl(so->so_faddr.s_addr) & 0xff) != CTL_ALIAS) |
|
326 saddr.sin_addr.s_addr = so->so_faddr.s_addr; |
|
327 } |
|
328 daddr.sin_addr = so->so_laddr; |
|
329 daddr.sin_port = so->so_lport; |
|
330 |
|
331 return udp_output2(so, m, &saddr, &daddr, so->so_iptos); |
|
332 } |
|
333 |
|
334 int |
|
335 udp_attach(so) |
|
336 struct socket *so; |
|
337 { |
|
338 struct sockaddr_in addr; |
|
339 |
|
340 if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { |
|
341 /* |
|
342 * Here, we bind() the socket. Although not really needed |
|
343 * (sendto() on an unbound socket will bind it), it's done |
|
344 * here so that emulation of ytalk etc. don't have to do it |
|
345 */ |
|
346 addr.sin_family = AF_INET; |
|
347 addr.sin_port = 0; |
|
348 addr.sin_addr.s_addr = INADDR_ANY; |
|
349 if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { |
|
350 int lasterrno=errno; |
|
351 closesocket(so->s); |
|
352 so->s=-1; |
|
353 #ifdef _WIN32 |
|
354 WSASetLastError(lasterrno); |
|
355 #else |
|
356 errno=lasterrno; |
|
357 #endif |
|
358 } else { |
|
359 /* success, insert in queue */ |
|
360 so->so_expire = curtime + SO_EXPIRE; |
|
361 insque(so,&udb); |
|
362 } |
|
363 } |
|
364 return(so->s); |
|
365 } |
|
366 |
|
367 void |
|
368 udp_detach(so) |
|
369 struct socket *so; |
|
370 { |
|
371 closesocket(so->s); |
|
372 /* if (so->so_m) m_free(so->so_m); done by sofree */ |
|
373 |
|
374 sofree(so); |
|
375 } |
|
376 |
|
377 static const struct tos_t udptos[] = { |
|
378 {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ |
|
379 {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ |
|
380 {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ |
|
381 {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ |
|
382 {0, 0, 0, 0} |
|
383 }; |
|
384 |
|
385 static u_int8_t |
|
386 udp_tos(struct socket *so) |
|
387 { |
|
388 int i = 0; |
|
389 |
|
390 while(udptos[i].tos) { |
|
391 if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || |
|
392 (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { |
|
393 so->so_emu = udptos[i].emu; |
|
394 return udptos[i].tos; |
|
395 } |
|
396 i++; |
|
397 } |
|
398 |
|
399 return 0; |
|
400 } |
|
401 |
|
402 #ifdef EMULATE_TALK |
|
403 #include "talkd.h" |
|
404 #endif |
|
405 |
|
406 /* |
|
407 * Here, talk/ytalk/ntalk requests must be emulated |
|
408 */ |
|
409 static void |
|
410 udp_emu(struct socket *so, struct mbuf *m) |
|
411 { |
|
412 struct sockaddr_in addr; |
|
413 socklen_t addrlen = sizeof(addr); |
|
414 #ifdef EMULATE_TALK |
|
415 CTL_MSG_OLD *omsg; |
|
416 CTL_MSG *nmsg; |
|
417 char buff[sizeof(CTL_MSG)]; |
|
418 u_char type; |
|
419 |
|
420 struct talk_request { |
|
421 struct talk_request *next; |
|
422 struct socket *udp_so; |
|
423 struct socket *tcp_so; |
|
424 } *req; |
|
425 |
|
426 static struct talk_request *req_tbl = 0; |
|
427 |
|
428 #endif |
|
429 |
|
430 struct cu_header { |
|
431 uint16_t d_family; // destination family |
|
432 uint16_t d_port; // destination port |
|
433 uint32_t d_addr; // destination address |
|
434 uint16_t s_family; // source family |
|
435 uint16_t s_port; // source port |
|
436 uint32_t so_addr; // source address |
|
437 uint32_t seqn; // sequence number |
|
438 uint16_t message; // message |
|
439 uint16_t data_type; // data type |
|
440 uint16_t pkt_len; // packet length |
|
441 } *cu_head; |
|
442 |
|
443 switch(so->so_emu) { |
|
444 |
|
445 #ifdef EMULATE_TALK |
|
446 case EMU_TALK: |
|
447 case EMU_NTALK: |
|
448 /* |
|
449 * Talk emulation. We always change the ctl_addr to get |
|
450 * some answers from the daemon. When an ANNOUNCE comes, |
|
451 * we send LEAVE_INVITE to the local daemons. Also when a |
|
452 * DELETE comes, we send copies to the local daemons. |
|
453 */ |
|
454 if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) |
|
455 return; |
|
456 |
|
457 #define IS_OLD (so->so_emu == EMU_TALK) |
|
458 |
|
459 #define COPY_MSG(dest, src) { dest->type = src->type; \ |
|
460 dest->id_num = src->id_num; \ |
|
461 dest->pid = src->pid; \ |
|
462 dest->addr = src->addr; \ |
|
463 dest->ctl_addr = src->ctl_addr; \ |
|
464 memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ |
|
465 memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ |
|
466 memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } |
|
467 |
|
468 #define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) |
|
469 /* old_sockaddr to sockaddr_in */ |
|
470 |
|
471 |
|
472 if (IS_OLD) { /* old talk */ |
|
473 omsg = mtod(m, CTL_MSG_OLD*); |
|
474 nmsg = (CTL_MSG *) buff; |
|
475 type = omsg->type; |
|
476 OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; |
|
477 OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; |
|
478 pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin()); |
|
479 } else { /* new talk */ |
|
480 omsg = (CTL_MSG_OLD *) buff; |
|
481 nmsg = mtod(m, CTL_MSG *); |
|
482 type = nmsg->type; |
|
483 OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; |
|
484 OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; |
|
485 pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin()); |
|
486 } |
|
487 |
|
488 if (type == LOOK_UP) |
|
489 return; /* for LOOK_UP this is enough */ |
|
490 |
|
491 if (IS_OLD) { /* make a copy of the message */ |
|
492 COPY_MSG(nmsg, omsg); |
|
493 nmsg->vers = 1; |
|
494 nmsg->answer = 0; |
|
495 } else |
|
496 COPY_MSG(omsg, nmsg); |
|
497 |
|
498 /* |
|
499 * If if is an ANNOUNCE message, we go through the |
|
500 * request table to see if a tcp port has already |
|
501 * been redirected for this socket. If not, we solisten() |
|
502 * a new socket and add this entry to the table. |
|
503 * The port number of the tcp socket and our IP |
|
504 * are put to the addr field of the message structures. |
|
505 * Then a LEAVE_INVITE is sent to both local daemon |
|
506 * ports, 517 and 518. This is why we have two copies |
|
507 * of the message, one in old talk and one in new talk |
|
508 * format. |
|
509 */ |
|
510 |
|
511 if (type == ANNOUNCE) { |
|
512 int s; |
|
513 u_short temp_port; |
|
514 |
|
515 for(req = req_tbl; req; req = req->next) |
|
516 if (so == req->udp_so) |
|
517 break; /* found it */ |
|
518 |
|
519 if (!req) { /* no entry for so, create new */ |
|
520 req = (struct talk_request *) |
|
521 malloc(sizeof(struct talk_request)); |
|
522 req->udp_so = so; |
|
523 req->tcp_so = solisten(0, |
|
524 OTOSIN(omsg, addr)->sin_addr.s_addr, |
|
525 OTOSIN(omsg, addr)->sin_port, |
|
526 SS_FACCEPTONCE); |
|
527 req->next = req_tbl; |
|
528 req_tbl = req; |
|
529 } |
|
530 |
|
531 /* replace port number in addr field */ |
|
532 addrlen = sizeof(addr); |
|
533 getsockname(req->tcp_so->s, |
|
534 (struct sockaddr *) &addr, |
|
535 &addrlen); |
|
536 OTOSIN(omsg, addr)->sin_port = addr.sin_port; |
|
537 OTOSIN(omsg, addr)->sin_addr = our_addr; |
|
538 OTOSIN(nmsg, addr)->sin_port = addr.sin_port; |
|
539 OTOSIN(nmsg, addr)->sin_addr = our_addr; |
|
540 |
|
541 /* send LEAVE_INVITEs */ |
|
542 temp_port = OTOSIN(omsg, ctl_addr)->sin_port; |
|
543 OTOSIN(omsg, ctl_addr)->sin_port = 0; |
|
544 OTOSIN(nmsg, ctl_addr)->sin_port = 0; |
|
545 omsg->type = nmsg->type = LEAVE_INVITE; |
|
546 |
|
547 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
|
548 addr.sin_addr = our_addr; |
|
549 addr.sin_family = AF_INET; |
|
550 addr.sin_port = htons(517); |
|
551 sendto(s, (char *)omsg, sizeof(*omsg), 0, |
|
552 (struct sockaddr *)&addr, sizeof(addr)); |
|
553 addr.sin_port = htons(518); |
|
554 sendto(s, (char *)nmsg, sizeof(*nmsg), 0, |
|
555 (struct sockaddr *) &addr, sizeof(addr)); |
|
556 closesocket(s) ; |
|
557 |
|
558 omsg->type = nmsg->type = ANNOUNCE; |
|
559 OTOSIN(omsg, ctl_addr)->sin_port = temp_port; |
|
560 OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; |
|
561 } |
|
562 |
|
563 /* |
|
564 * If it is a DELETE message, we send a copy to the |
|
565 * local daemons. Then we delete the entry corresponding |
|
566 * to our socket from the request table. |
|
567 */ |
|
568 |
|
569 if (type == DELETE) { |
|
570 struct talk_request *temp_req, *req_next; |
|
571 int s; |
|
572 u_short temp_port; |
|
573 |
|
574 temp_port = OTOSIN(omsg, ctl_addr)->sin_port; |
|
575 OTOSIN(omsg, ctl_addr)->sin_port = 0; |
|
576 OTOSIN(nmsg, ctl_addr)->sin_port = 0; |
|
577 |
|
578 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); |
|
579 addr.sin_addr = our_addr; |
|
580 addr.sin_family = AF_INET; |
|
581 addr.sin_port = htons(517); |
|
582 sendto(s, (char *)omsg, sizeof(*omsg), 0, |
|
583 (struct sockaddr *)&addr, sizeof(addr)); |
|
584 addr.sin_port = htons(518); |
|
585 sendto(s, (char *)nmsg, sizeof(*nmsg), 0, |
|
586 (struct sockaddr *)&addr, sizeof(addr)); |
|
587 closesocket(s); |
|
588 |
|
589 OTOSIN(omsg, ctl_addr)->sin_port = temp_port; |
|
590 OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; |
|
591 |
|
592 /* delete table entry */ |
|
593 if (so == req_tbl->udp_so) { |
|
594 temp_req = req_tbl; |
|
595 req_tbl = req_tbl->next; |
|
596 free(temp_req); |
|
597 } else { |
|
598 temp_req = req_tbl; |
|
599 for(req = req_tbl->next; req; req = req_next) { |
|
600 req_next = req->next; |
|
601 if (so == req->udp_so) { |
|
602 temp_req->next = req_next; |
|
603 free(req); |
|
604 break; |
|
605 } else { |
|
606 temp_req = req; |
|
607 } |
|
608 } |
|
609 } |
|
610 } |
|
611 |
|
612 return; |
|
613 #endif |
|
614 |
|
615 case EMU_CUSEEME: |
|
616 |
|
617 /* |
|
618 * Cu-SeeMe emulation. |
|
619 * Hopefully the packet is more that 16 bytes long. We don't |
|
620 * do any other tests, just replace the address and port |
|
621 * fields. |
|
622 */ |
|
623 if (m->m_len >= sizeof (*cu_head)) { |
|
624 if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) |
|
625 return; |
|
626 cu_head = mtod(m, struct cu_header *); |
|
627 cu_head->s_port = addr.sin_port; |
|
628 cu_head->so_addr = our_addr.s_addr; |
|
629 } |
|
630 |
|
631 return; |
|
632 } |
|
633 } |
|
634 |
|
635 struct socket * |
|
636 udp_listen(port, laddr, lport, flags) |
|
637 u_int port; |
|
638 u_int32_t laddr; |
|
639 u_int lport; |
|
640 int flags; |
|
641 { |
|
642 struct sockaddr_in addr; |
|
643 struct socket *so; |
|
644 socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1; |
|
645 |
|
646 if ((so = socreate()) == NULL) { |
|
647 free(so); |
|
648 return NULL; |
|
649 } |
|
650 so->s = socket(AF_INET,SOCK_DGRAM,0); |
|
651 so->so_expire = curtime + SO_EXPIRE; |
|
652 insque(so,&udb); |
|
653 |
|
654 addr.sin_family = AF_INET; |
|
655 addr.sin_addr.s_addr = INADDR_ANY; |
|
656 addr.sin_port = port; |
|
657 |
|
658 if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { |
|
659 udp_detach(so); |
|
660 return NULL; |
|
661 } |
|
662 setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); |
|
663 /* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ |
|
664 |
|
665 getsockname(so->s,(struct sockaddr *)&addr,&addrlen); |
|
666 so->so_fport = addr.sin_port; |
|
667 if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) |
|
668 so->so_faddr = alias_addr; |
|
669 else |
|
670 so->so_faddr = addr.sin_addr; |
|
671 |
|
672 so->so_lport = lport; |
|
673 so->so_laddr.s_addr = laddr; |
|
674 if (flags != SS_FACCEPTONCE) |
|
675 so->so_expire = 0; |
|
676 |
|
677 so->so_state = SS_ISFCONNECTED; |
|
678 |
|
679 return so; |
|
680 } |