~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to sys/solaris/dlpi.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: dlpi.c,v 1.2 2002/01/17 06:13:02 srittau Exp $
 
2
 */
 
3
 
 
4
#include <config.h>
 
5
 
 
6
#include <sys/types.h>
 
7
#include <sys/kmem.h>
 
8
#include <sys/stream.h>
 
9
#include <sys/conf.h>
 
10
#include <sys/modctl.h>
 
11
#include <sys/cmn_err.h>
 
12
#include <sys/ddi.h>
 
13
#include <sys/socket.h>
 
14
#include <sys/sockio.h>
 
15
#include <sys/dlpi.h>
 
16
#include <sys/ethernet.h>
 
17
#include <sys/byteorder.h>
 
18
#include <sys/sunddi.h>
 
19
#include <net/if.h>
 
20
#include <errno.h>
 
21
 
 
22
#include <netatalk/phase2.h>
 
23
#include <netatalk/at.h>
 
24
 
 
25
#include "ioc.h"
 
26
#include "if.h"
 
27
 
 
28
u_char  at_multicastaddr[ ETHERADDRL ] = {
 
29
    0x09, 0x00, 0x07, 0xff, 0xff, 0xff,
 
30
};
 
31
u_char  at_org_code[ 3 ] = {
 
32
    0x08, 0x00, 0x07,
 
33
};
 
34
u_char  aarp_org_code[ 3 ] = {
 
35
    0x00, 0x00, 0x00,
 
36
};
 
37
 
 
38
    static int
 
39
dlpi_open( queue_t *q, dev_t *dev, int oflag, int sflag, cred_t *cred )
 
40
{
 
41
    struct atif_data    *aid;
 
42
    int                 err = 0;
 
43
 
 
44
    if (( err = drv_priv( cred )) != 0 ) {
 
45
        return( err );
 
46
    }
 
47
    if (( aid = if_alloc( q )) == NULL ) {
 
48
        return( ENOMEM );
 
49
    }
 
50
    q->q_ptr = (void *)aid;
 
51
 
 
52
    qprocson( q );
 
53
    return( err );
 
54
}
 
55
 
 
56
    static int
 
57
dlpi_close( queue_t *q, int oflag, cred_t *cred )
 
58
{
 
59
    struct atif_data    *aid = (struct atif_data *)q->q_ptr;
 
60
 
 
61
    qprocsoff( q );
 
62
    if_free( aid );
 
63
    return( 0 );
 
64
}
 
65
 
 
66
    static int
 
67
dl_bind_req( queue_t *q, ulong sap )
 
68
{
 
69
    union DL_primitives *dl;
 
70
    mblk_t              *m;
 
71
 
 
72
    if (( m = allocb( DL_BIND_REQ_SIZE, BPRI_HI )) == NULL ) {
 
73
        return( ENOMEM );
 
74
    }
 
75
    m->b_wptr = m->b_rptr + DL_BIND_REQ_SIZE;
 
76
    m->b_datap->db_type = M_PROTO;
 
77
 
 
78
    dl = (union DL_primitives *)m->b_rptr;
 
79
    dl->dl_primitive = DL_BIND_REQ;
 
80
    dl->bind_req.dl_sap = sap;
 
81
    dl->bind_req.dl_max_conind = 0;
 
82
    dl->bind_req.dl_service_mode = DL_CLDLS;
 
83
    dl->bind_req.dl_conn_mgmt = 0;
 
84
    dl->bind_req.dl_xidtest_flg = 0;    /* XXX */
 
85
    putnext( q, m );
 
86
    return( 0 );
 
87
}
 
88
 
 
89
    static int
 
90
dl_attach_req( queue_t *q, ulong ppa )
 
91
{
 
92
    union DL_primitives *dl;
 
93
    mblk_t              *m;
 
94
 
 
95
    if (( m = allocb( DL_ATTACH_REQ_SIZE, BPRI_HI )) == NULL ) {
 
96
        return( ENOMEM );
 
97
    }
 
98
    m->b_wptr = m->b_rptr + DL_ATTACH_REQ_SIZE;
 
99
    m->b_datap->db_type = M_PROTO;
 
100
 
 
101
    dl = (union DL_primitives *)m->b_rptr;
 
102
    dl->dl_primitive = DL_ATTACH_REQ;
 
103
    dl->attach_req.dl_ppa = ppa;
 
104
    putnext( q, m );
 
105
    return( 0 );
 
106
}
 
107
 
 
108
    int
 
109
dl_enabmulti_req( queue_t *q, caddr_t addr )
 
110
{
 
111
    union DL_primitives *dl;
 
112
    mblk_t              *m;
 
113
 
 
114
    if (( m = allocb( DL_ENABMULTI_REQ_SIZE + ETHERADDRL, BPRI_HI )) == NULL ) {
 
115
        return( ENOMEM );
 
116
    }
 
117
    m->b_wptr = m->b_rptr + DL_ENABMULTI_REQ_SIZE;
 
118
    m->b_datap->db_type = M_PROTO;
 
119
 
 
120
    dl = (union DL_primitives *)m->b_rptr;
 
121
    dl->dl_primitive = DL_ENABMULTI_REQ;
 
122
    dl->enabmulti_req.dl_addr_length = ETHERADDRL;
 
123
    dl->enabmulti_req.dl_addr_offset = m->b_wptr - m->b_rptr;
 
124
    bcopy( addr, m->b_wptr, ETHERADDRL );
 
125
    m->b_wptr += ETHERADDRL;
 
126
    putnext( q, m );
 
127
    return( 0 );
 
128
}
 
129
 
 
130
    int
 
131
dl_unitdata_req( queue_t *q, mblk_t *m0, ushort type, caddr_t addr )
 
132
{
 
133
    union DL_primitives *dl;
 
134
    struct llc          *llc;
 
135
    mblk_t              *m1, *m;
 
136
    ushort              len;
 
137
 
 
138
    /* len = msgdsize( m0 ) + sizeof( struct llc ); */
 
139
 
 
140
    if (( m1 = allocb( sizeof( struct llc ), BPRI_HI )) == NULL ) {
 
141
        cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 1\n" );
 
142
        return( ENOMEM );
 
143
    }
 
144
    m1->b_wptr = m1->b_rptr + sizeof( struct llc );
 
145
    m1->b_datap->db_type = M_DATA;
 
146
    llc = (struct llc *)m1->b_rptr;
 
147
 
 
148
    llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
 
149
    llc->llc_control = LLC_UI;
 
150
    if ( type == ETHERTYPE_AARP ) {
 
151
        bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
 
152
    } else if ( type == ETHERTYPE_AT ) {
 
153
        bcopy( at_org_code, llc->llc_org_code, sizeof( aarp_org_code ));
 
154
    } else {
 
155
        cmn_err( CE_NOTE, "dl_unitdate_req type %X\n", type );
 
156
        return( EINVAL );
 
157
    }
 
158
    llc->llc_ether_type = htons( type );
 
159
    linkb( m1, m0 );
 
160
 
 
161
    if (( m = allocb( DL_UNITDATA_REQ_SIZE + ETHERADDRL + sizeof( ushort ),
 
162
                      BPRI_HI )) == NULL ) {
 
163
        cmn_err( CE_NOTE, "dl_unitdate_req NOMEM 2\n" );
 
164
        return( ENOMEM );
 
165
    }
 
166
    m->b_wptr = m->b_rptr + DL_UNITDATA_REQ_SIZE;
 
167
    m->b_datap->db_type = M_PROTO;
 
168
    linkb( m, m1 );
 
169
 
 
170
    dl = (union DL_primitives *)m->b_rptr;
 
171
    dl->dl_primitive = DL_UNITDATA_REQ;
 
172
    dl->unitdata_req.dl_dest_addr_length = ETHERADDRL + sizeof ( ushort );
 
173
    dl->unitdata_req.dl_dest_addr_offset = m->b_wptr - m->b_rptr;
 
174
 
 
175
    bcopy(addr, m->b_wptr, ETHERADDRL );
 
176
    m->b_wptr += ETHERADDRL;
 
177
    len = 0;
 
178
    bcopy( &len, m->b_wptr, sizeof( ushort ));
 
179
    m->b_wptr += sizeof( ushort );
 
180
    putnext( q, m );
 
181
    return( 0 );
 
182
}
 
183
 
 
184
    static int
 
185
dlpi_rput( queue_t *q, mblk_t *m )
 
186
{
 
187
    struct atif_data    *aid = (struct atif_data *)q->q_ptr;
 
188
    union DL_primitives *dl;
 
189
    mblk_t              *m0;
 
190
    struct llc          *llc;
 
191
 
 
192
    switch ( m->b_datap->db_type ) {
 
193
    case M_IOCNAK :
 
194
        putnext( q, m );
 
195
        return( 0 );
 
196
 
 
197
    case M_PCPROTO :
 
198
    case M_PROTO :
 
199
        if ( m->b_wptr - m->b_rptr < sizeof( dl->dl_primitive )) {
 
200
            break;
 
201
        }
 
202
        dl = (union DL_primitives *)m->b_rptr;
 
203
        switch ( dl->dl_primitive ) {
 
204
        case DL_UNITDATA_IND :
 
205
            if ( m->b_wptr - m->b_rptr < sizeof( DL_UNITDATA_IND_SIZE )) {
 
206
                break;
 
207
            }
 
208
            if (( m0 = unlinkb( m )) == NULL ) {
 
209
                break;
 
210
            }
 
211
            if ( m0->b_wptr - m0->b_rptr < sizeof( struct llc )) {
 
212
                freemsg( m0 );
 
213
                break;
 
214
            }
 
215
            llc = (struct llc *)m0->b_rptr;
 
216
            if ( llc->llc_dsap != LLC_SNAP_LSAP ||
 
217
                    llc->llc_ssap != LLC_SNAP_LSAP ||
 
218
                    llc->llc_control != LLC_UI ) {
 
219
                freemsg( m0 );
 
220
                break;
 
221
            }
 
222
 
 
223
            if ( bcmp( llc->llc_org_code, at_org_code,
 
224
                    sizeof( at_org_code )) == 0 &&
 
225
                    ntohs( llc->llc_ether_type ) == ETHERTYPE_AT ) {
 
226
                adjmsg( m0, sizeof( struct llc ));
 
227
                ddp_rput( aid, m0 );
 
228
            } else if ( bcmp( llc->llc_org_code, aarp_org_code,
 
229
                    sizeof( aarp_org_code )) == 0 &&
 
230
                    ntohs( llc->llc_ether_type ) == ETHERTYPE_AARP ) {
 
231
                adjmsg( m0, sizeof( struct llc ));
 
232
                aarp_rput( q, m0 );
 
233
            } else {
 
234
                freemsg( m0 );
 
235
            }
 
236
            break;
 
237
 
 
238
        case DL_OK_ACK :
 
239
            if ( m->b_wptr - m->b_rptr < sizeof( DL_OK_ACK_SIZE )) {
 
240
                break;
 
241
            }
 
242
            switch ( dl->ok_ack.dl_correct_primitive ) {
 
243
            case DL_ATTACH_REQ :
 
244
                if ( aid->aid_state != DL_ATTACH_PENDING ) {
 
245
                    cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach state %d\n",
 
246
                            aid->aid_state );
 
247
                    break;
 
248
                }
 
249
                if ( aid->aid_c.c_type != IF_UNITSEL ) {
 
250
                    cmn_err( CE_NOTE, "dlpi_rput DL_OK_ACK attach context %x\n",
 
251
                            aid->aid_c.c_type );
 
252
                    break;
 
253
                }
 
254
 
 
255
                if ( WR(q)->q_next == NULL || WR(q)->q_next->q_qinfo == NULL ||
 
256
                        WR(q)->q_next->q_qinfo->qi_minfo == NULL ||
 
257
                        WR(q)->q_next->q_qinfo->qi_minfo->mi_idname == NULL ) {
 
258
                    cmn_err( CE_NOTE, "dlpi_rput can't get interface name\n" );
 
259
                    break;
 
260
                }
 
261
 
 
262
                if_name( aid, WR(q)->q_next->q_qinfo->qi_minfo->mi_idname,
 
263
                        aid->aid_c.c_u.u_unit.uu_ppa );
 
264
 
 
265
                aid->aid_state = DL_BIND_PENDING;
 
266
 
 
267
#ifdef i386
 
268
                /*
 
269
                 * As of Solaris 7 (nice name), the i386 arch needs to be
 
270
                 * bound as 0 to receive 802 frames.  However, in the same
 
271
                 * OS, Sparcs must be bound as ETHERMTU (or at least not 0)
 
272
                 * to receive the same frames.  A bug?  In the Solaris 7
 
273
                 * (nice name) kernel?
 
274
                 */
 
275
                dl_bind_req( WR( q ), 0 );
 
276
#else /* i386 */
 
277
                dl_bind_req( WR( q ), ETHERMTU );
 
278
#endif /* i386 */
 
279
                break;
 
280
 
 
281
            case DL_ENABMULTI_REQ :
 
282
                if ( aid->aid_c.c_type != SIOCADDMULTI ) {
 
283
                    cmn_err( CE_NOTE,
 
284
                            "dlpi_rput DL_OK_ACK enabmulti context %x\n",
 
285
                            aid->aid_c.c_type );
 
286
                    break;
 
287
                }
 
288
 
 
289
                ioc_ok_ack( aid->aid_c.c_u.u_multi.um_q,
 
290
                        aid->aid_c.c_u.u_multi.um_m, 0 );
 
291
                aid->aid_c.c_type = 0;
 
292
                aid->aid_c.c_u.u_multi.um_q = NULL;
 
293
                aid->aid_c.c_u.u_multi.um_m = 0;
 
294
                break;
 
295
 
 
296
            default :
 
297
                cmn_err( CE_CONT, "!dlpi_rput DL_OK_ACK unhandled %d\n",
 
298
                        dl->ok_ack.dl_correct_primitive );
 
299
                break;
 
300
            }
 
301
            break;
 
302
 
 
303
        case DL_BIND_ACK :
 
304
            if ( m->b_wptr - m->b_rptr < sizeof( DL_BIND_ACK_SIZE )) {
 
305
                break;
 
306
            }
 
307
            if ( aid->aid_state != DL_BIND_PENDING ) {
 
308
                break;
 
309
            }
 
310
            if ( aid->aid_c.c_type != IF_UNITSEL ) {
 
311
                break;
 
312
            }
 
313
            bcopy( m->b_rptr + dl->bind_ack.dl_addr_offset, aid->aid_hwaddr, 
 
314
                    dl->bind_ack.dl_addr_length );
 
315
            aid->aid_state = DL_IDLE;
 
316
            ioc_ok_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, 0 );
 
317
            aid->aid_c.c_type = 0;
 
318
            aid->aid_c.c_u.u_unit.uu_m = NULL;
 
319
            aid->aid_c.c_u.u_unit.uu_ppa = 0;
 
320
            break;
 
321
 
 
322
        case DL_ERROR_ACK :
 
323
            if ( m->b_wptr - m->b_rptr < sizeof( DL_ERROR_ACK_SIZE )) {
 
324
                break;
 
325
            }
 
326
 
 
327
            switch ( aid->aid_c.c_type ) {
 
328
            case IF_UNITSEL :
 
329
                if ( dl->error_ack.dl_errno == DL_SYSERR ) {
 
330
                    ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m,
 
331
                            dl->error_ack.dl_unix_errno );
 
332
                } else {
 
333
                    cmn_err( CE_CONT, "dlpi_rput DL_ERROR_ACK 0x%x\n",
 
334
                            dl->error_ack.dl_errno );
 
335
                    ioc_error_ack( WR(q), aid->aid_c.c_u.u_unit.uu_m, EINVAL );
 
336
                }
 
337
                aid->aid_c.c_type = 0;
 
338
                aid->aid_c.c_u.u_unit.uu_m = NULL;
 
339
                aid->aid_c.c_u.u_unit.uu_ppa = 0;
 
340
                break;
 
341
 
 
342
            default :
 
343
                cmn_err( CE_NOTE, "dlpi_rput DL_ERROR_ACK unhandled %d %d %d\n",
 
344
                        dl->error_ack.dl_error_primitive,
 
345
                        dl->error_ack.dl_errno, dl->error_ack.dl_unix_errno );
 
346
                break;
 
347
            }
 
348
            break;
 
349
 
 
350
        default :
 
351
            cmn_err( CE_NOTE, "dlpi_rput M_PCPROTO 0x%x\n", dl->dl_primitive );
 
352
            break;
 
353
        }
 
354
        break;
 
355
 
 
356
    default :
 
357
        cmn_err( CE_NOTE, "dlpi_rput 0x%X\n", m->b_datap->db_type );
 
358
        break;
 
359
    }
 
360
 
 
361
    freemsg( m );
 
362
    return( 0 );
 
363
}
 
364
 
 
365
    static int
 
366
dlpi_wput( queue_t *q, mblk_t *m )
 
367
{
 
368
    struct atif_data            *aid = (struct atif_data *)RD(q)->q_ptr;
 
369
    struct iocblk               *ioc;
 
370
    int                         rc;
 
371
 
 
372
    switch ( m->b_datap->db_type ) {
 
373
    case M_IOCTL :
 
374
        if ( m->b_wptr - m->b_rptr < sizeof( struct iocblk )) {
 
375
            freemsg( m );
 
376
            break;
 
377
        }
 
378
        ioc = (struct iocblk *)m->b_rptr;
 
379
        switch ( ioc->ioc_cmd ) {
 
380
        case IF_UNITSEL :
 
381
            if ( ioc->ioc_count != TRANSPARENT ) {
 
382
                cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL non-TRANSPARENT\n" );
 
383
                ioc_error_ack( q, m, EINVAL );
 
384
                break;
 
385
            }
 
386
            if ( m->b_cont == NULL ) {
 
387
                cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL no arg\n" );
 
388
                ioc_error_ack( q, m, EINVAL );
 
389
                break;
 
390
            }
 
391
            if ( aid->aid_state != DL_UNATTACHED ) {
 
392
                cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL already attached\n" );
 
393
                ioc_error_ack( q, m, EINVAL );
 
394
                break;
 
395
            }
 
396
            if ( aid->aid_c.c_type != 0 ) {
 
397
                cmn_err( CE_NOTE, "dlpi_wput IF_UNITSEL context %x\n",
 
398
                        aid->aid_c.c_type );
 
399
                ioc_error_ack( q, m, EINVAL );
 
400
                break;
 
401
            }
 
402
 
 
403
            aid->aid_state = DL_ATTACH_PENDING;
 
404
            aid->aid_c.c_type = IF_UNITSEL;
 
405
            aid->aid_c.c_u.u_unit.uu_m = m;
 
406
            aid->aid_c.c_u.u_unit.uu_ppa = *(ulong *)m->b_cont->b_rptr;
 
407
            if (( rc = dl_attach_req( q, aid->aid_c.c_u.u_unit.uu_ppa )) < 0 ) {
 
408
                ioc_error_ack( q, m, rc );
 
409
                break;
 
410
            }
 
411
            break;
 
412
 
 
413
        default :
 
414
            cmn_err( CE_NOTE, "dlpi_wput M_IOCTL 0x%X\n", ioc->ioc_cmd );
 
415
            putnext( q, m );
 
416
            break;
 
417
        }
 
418
        break;
 
419
 
 
420
    default :
 
421
        cmn_err( CE_NOTE, "dlpi_wput 0x%X\n", m->b_datap->db_type );
 
422
        freemsg( m );
 
423
        break;
 
424
    }
 
425
 
 
426
    return( 0 );
 
427
}
 
428
 
 
429
static struct module_info       dlpi_info = {
 
430
    0,
 
431
    "ddp",
 
432
    0,
 
433
    1500,
 
434
    3000,
 
435
    64
 
436
};
 
437
 
 
438
static struct qinit             dlpi_rinit = {
 
439
    dlpi_rput,          /* qi_putp */
 
440
    NULL,               /* qi_srvp */
 
441
    dlpi_open,          /* qi_qopen */
 
442
    dlpi_close,         /* qi_qclose */
 
443
    NULL,
 
444
    &dlpi_info,         /* qi_minfo */
 
445
    NULL,
 
446
};
 
447
 
 
448
static struct qinit             dlpi_winit = {
 
449
    dlpi_wput,          /* qi_putp */
 
450
    NULL,               /* qi_srvp */
 
451
    NULL,               /* qi_qopen */
 
452
    NULL,               /* qi_qclose */
 
453
    NULL,
 
454
    &dlpi_info,         /* qi_minfo */
 
455
    NULL,
 
456
};
 
457
 
 
458
static struct streamtab         dlpi_stream = {
 
459
    &dlpi_rinit,
 
460
    &dlpi_winit,
 
461
    NULL,
 
462
    NULL
 
463
};
 
464
 
 
465
static struct fmodsw            dlpi_fmodsw = {
 
466
    "ddp",
 
467
    &dlpi_stream,
 
468
    D_NEW | D_MP | D_MTPERMOD
 
469
};
 
470
 
 
471
/*
 
472
 * DDP Streams module.  This module is pushed on DLPI drivers by atalkd.
 
473
 */
 
474
struct modlstrmod               dlpi_lstrmod = {
 
475
    &mod_strmodops,
 
476
    "DDP Streams module",
 
477
    &dlpi_fmodsw,
 
478
};