1/* $Id: sock.c,v 1.2 2002-01-17 07:11:13 srittau Exp $
2 */
3
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif /* HAVE_CONFIG_H */
7
8#include <sys/types.h>
9#include <sys/stream.h>
10#include <sys/socket.h>
11#include <sys/errno.h>
12#include <sys/kmem.h>
13#include <sys/cmn_err.h>
14#include <sys/tihdr.h>
15#include <sys/ethernet.h>
16#include <net/if.h>
17
18#ifdef STDC_HEADERS
19#include <strings.h>
20#else
21#include <string.h>
22#endif
23
24#include <netatalk/at.h>
25
26#include "if.h"
27#include "sock.h"
28
29static struct sock_data	*sockets = NULL;
30
31    struct sock_data *
32sock_alloc( queue_t *q )
33{
34    struct sock_data	*sd;
35
36    if (( sd = kmem_alloc( sizeof( struct sock_data ), KM_SLEEP )) == NULL ) {
37	return( NULL );
38    }
39    sd->sd_state = TS_UNBND;
40    sd->sd_q = q;
41    sd->sd_next = sd->sd_prev = NULL;
42    bzero( (caddr_t)&sd->sd_sat, sizeof( struct sockaddr_at ));
43
44    sd->sd_next = sockets;
45    if ( sockets != NULL ) {
46	sockets->sd_prev = sd;
47    }
48    sockets = sd;
49
50    return( sd );
51}
52
53    void
54sock_free( struct sock_data *sd )
55{
56    if ( sd == sockets ) {
57	sockets = sd->sd_next;
58    }
59    if ( sd->sd_next != NULL ) {
60	sd->sd_next->sd_prev = sd->sd_prev;
61    }
62    if ( sd->sd_prev != NULL ) {
63	sd->sd_prev->sd_next = sd->sd_next;
64    }
65    kmem_free( sd, sizeof( struct sock_data ));
66    return;
67}
68
69    struct sock_data *
70sock_dest( struct atif_data *aid, struct sockaddr_at *sat )
71{
72    struct sock_data	*sd;
73
74    for ( sd = sockets; sd != NULL; sd = sd->sd_next ) {
75	if ( sat->sat_port == sd->sd_sat.sat_port &&
76		/* huh? */
77		aid->aid_sat.sat_addr.s_net == sd->sd_sat.sat_addr.s_net &&
78		( sat->sat_addr.s_node == sd->sd_sat.sat_addr.s_node ||
79		sat->sat_addr.s_node == ATADDR_BCAST )) {
80	    break;
81	}
82    }
83    return( sd );
84}
85
86/*
87 * This is a change in semantics.  The port must be ATADDR_ANYPORT for
88 * ATADDR_ANYNET/NODE to not mean the loopback.
89 */
90    int
91sock_bind( struct sock_data *sd, struct sockaddr_at *sat )
92{
93    struct atif_data	*paid;
94    struct sock_data	*psd;
95    struct sockaddr_at	psat;
96    u_short		port;
97
98    psat = *sat;
99    if ( psat.sat_family != AF_APPLETALK ) {
100	cmn_err( CE_CONT, "sock_bind non-AppleTalk\n" );
101	return( EPROTOTYPE );
102    }
103
104    if ( psat.sat_port == ATADDR_ANYPORT ) {
105	if ( psat.sat_addr.s_net == ATADDR_ANYNET &&
106		psat.sat_addr.s_node == ATADDR_ANYNODE ) {
107	    /* chose primary interface */
108	    if (( paid = if_primary()) == NULL ) {
109		return( EADDRNOTAVAIL );
110	    }
111	    psat.sat_addr.s_net = paid->aid_sat.sat_addr.s_net;
112	    psat.sat_addr.s_node = paid->aid_sat.sat_addr.s_node;
113	}
114
115	/* pick unused port */
116	for ( port = ATPORT_RESERVED; port < ATPORT_LAST; port++ ) {
117	    for ( psd = sockets; psd != NULL; psd = psd->sd_next ) {
118		if ( port == psd->sd_sat.sat_port &&
119			psat.sat_addr.s_net == psd->sd_sat.sat_addr.s_net &&
120			psat.sat_addr.s_node == psd->sd_sat.sat_addr.s_node ) {
121		    break;
122		}
123	    }
124	    if ( psd == NULL ) {
125		break;
126	    }
127	}
128	if ( psd != NULL ) {
129	    return( EADDRINUSE );
130	}
131	psat.sat_port = port;
132    }
133
134    sd->sd_sat = psat;
135    sd->sd_state = TS_IDLE;
136    return( 0 );
137}
138