ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/udp.c
Revision: 1.5
Committed: 2007-11-03T11:11:42Z (17 years ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.4: +5 -2 lines
Log Message:
Update to slirp sources from QEMU 0.8.2:
- set slirp client hostname
- fix slirp redirection on systems without a useful host IP address
- separate alias_addr (10.0.2.2) from our_addr (Ed Swierk)
- fix 32+ KB packets handling (Ed Swierk)
- fix UDP broadcast translation error
- solaris port (Ben Taylor)

File Contents

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