~ubuntu-branches/ubuntu/warty/openafs/warty

« back to all changes in this revision

Viewing changes to src/rx/DUX/rx_knet.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2004-01-10 16:37:33 UTC
  • Revision ID: james.westby@ubuntu.com-20040110163733-jvr0n1uahshlb1uu
Tags: upstream-1.2.11
ImportĀ upstreamĀ versionĀ 1.2.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2000, International Business Machines Corporation and others.
 
3
 * All Rights Reserved.
 
4
 * 
 
5
 * This software has been released under the terms of the IBM Public
 
6
 * License.  For details, see the LICENSE file in the top-level source
 
7
 * directory or online at http://www.openafs.org/dl/license10.html
 
8
 */
 
9
 
 
10
#include <afsconfig.h>
 
11
#include "../afs/param.h"
 
12
 
 
13
RCSID("$Header: /afs/sipb.mit.edu/project/openafs/debian/cvs/openafs/src/rx/DUX/rx_knet.c,v 1.1.1.5 2001/09/11 14:34:29 hartmans Exp $");
 
14
 
 
15
#ifdef AFS_DUX40_ENV
 
16
#include "../rx/rx_kcommon.h"
 
17
 
 
18
 
 
19
static struct protosw parent_proto;     /* udp proto switch */
 
20
static void rxk_input (struct mbuf *am, int iphlen);
 
21
static void rxk_fasttimo (void);
 
22
 
 
23
/* start intercepting basic calls */
 
24
rxk_init() {
 
25
    register struct protosw *tpro, *last;
 
26
    if (rxk_initDone) return 0;
 
27
 
 
28
    last = inetdomain.dom_protoswNPROTOSW;
 
29
    for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
 
30
      if (tpro->pr_protocol == IPPROTO_UDP) {
 
31
        /* force UDP checksumming on for AFS    */
 
32
         extern int udpcksum;
 
33
         udpcksum = 1;  
 
34
          memcpy(&parent_proto, tpro, sizeof(parent_proto));
 
35
          tpro->pr_input = rxk_input;
 
36
          tpro->pr_fasttimo = rxk_fasttimo;
 
37
          /*
 
38
           * don't bother with pr_drain and pr_ctlinput
 
39
           * until we have something to do
 
40
           */
 
41
          rxk_initDone = 1;
 
42
          return 0;
 
43
      }
 
44
    osi_Panic("inet:no udp");
 
45
}
 
46
 
 
47
 
 
48
static void rxk_input (struct mbuf *am, int iphlen)
 
49
{
 
50
    void (*tproc)();
 
51
    register unsigned short *tsp;
 
52
    int hdr;
 
53
    struct udphdr *tu;
 
54
    register struct ip *ti;
 
55
    struct udpiphdr *tvu;
 
56
    register int i;
 
57
    char *phandle;
 
58
    afs_int32 code;
 
59
    struct sockaddr_in taddr;
 
60
    int tlen;
 
61
    short port;
 
62
    int data_len, comp_sum;
 
63
 
 
64
    SPLVAR;
 
65
    NETPRI;
 
66
 
 
67
    /* make sure we have base ip and udp headers in first mbuf */
 
68
    if (iphlen > sizeof (struct ip)) {
 
69
        ip_stripoptions(am, (struct mbuf *)0, (struct ipoption *)0);
 
70
        iphlen = sizeof (struct ip);
 
71
    }
 
72
 
 
73
    if (am->m_len < sizeof(struct udpiphdr)) {
 
74
        am = m_pullup(am, sizeof(struct udpiphdr));
 
75
        if (!am) {
 
76
            USERPRI;
 
77
            return;
 
78
        }
 
79
    }
 
80
 
 
81
    ti = mtod(am, struct ip *);
 
82
    /* skip basic ip hdr */
 
83
    tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip)); 
 
84
    
 
85
    /* now read the port out */
 
86
    port = tu->uh_dport;
 
87
 
 
88
    if (port) {
 
89
        for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
 
90
            if (*tsp++ == port) {
 
91
                /* checksum the packet */
 
92
                /*
 
93
                 * Make mbuf data length reflect UDP length.
 
94
                 * If not enough data to reflect UDP length, drop.
 
95
                 */
 
96
                tvu = (struct udpiphdr *)ti;
 
97
                tlen = ntohs((u_short)tvu->ui_ulen);
 
98
                if ((int)ti->ip_len != tlen) {
 
99
                    if (tlen > (int)ti->ip_len) {
 
100
                        m_free(am);
 
101
                        USERPRI;
 
102
                        return;
 
103
                    }
 
104
                    m_adj(am, tlen - (int)ti->ip_len);
 
105
                }
 
106
                /* deliver packet to rx */
 
107
                taddr.sin_family = AF_INET;         /* compute source address */
 
108
                taddr.sin_port = tu->uh_sport;
 
109
                taddr.sin_addr.s_addr = ti->ip_src.s_addr;
 
110
                taddr.sin_len = sizeof(taddr);
 
111
                tvu = (struct udpiphdr *) ti;   /* virtual udp structure, for cksum */
 
112
                /* handle the checksum.  Note that this code damages the actual ip
 
113
                   header (replacing it with the virtual one, which is the same size),
 
114
                   so we must ensure we get everything out we need, first */
 
115
                if ( tu->uh_sum != 0) {
 
116
                        /* if the checksum is there, always check it. It's crazy not
 
117
                         * to, unless you can really be sure that your
 
118
                         * underlying network (and interfaces and drivers and
 
119
                         * DMA hardware, etc!) is error-free. First, fill
 
120
                         * in entire virtual ip header. */
 
121
                        tvu->ui_i.fill[0] = 0;
 
122
                        tvu->ui_i.fill[1] = 0;
 
123
                        tvu->ui_x1 = 0;
 
124
                        tvu->ui_len = tvu->ui_ulen;
 
125
                        tlen = ntohs((unsigned short)(tvu->ui_ulen));
 
126
                        if (in_cksum(am, sizeof(struct ip) + tlen)) {
 
127
                            /* checksum, including cksum field, doesn't come out 0, so
 
128
                               this packet is bad */
 
129
                            m_freem(am);
 
130
                            USERPRI;
 
131
                            return;
 
132
                        }
 
133
                      }
 
134
 
 
135
                /*
 
136
                 * 28 is IP (20) + UDP (8) header.  ulen includes
 
137
                 * udp header, and we *don't* tell RX about udp
 
138
                 * header either.  So, we remove those 8 as well.
 
139
                 */
 
140
                data_len = ntohs(tu->uh_ulen);
 
141
                data_len -= 8;
 
142
                AFS_RXGLOCK();
 
143
                if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
 
144
                  if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
 
145
                    /* XXX should just increment counter here.. */
 
146
                    printf("rx: truncated UDP packet\n");
 
147
                    rxi_FreePacket(phandle);
 
148
                  }
 
149
                  else 
 
150
                    (*rxk_PacketArrivalProc)(phandle, &taddr,
 
151
                                             rxk_portRocks[i], data_len);
 
152
                }else m_freem(am);
 
153
                AFS_RXGUNLOCK();
 
154
                USERPRI;
 
155
                return;
 
156
                }
 
157
            }
 
158
        }
 
159
 
 
160
    /* if we get here, try to deliver packet to udp */
 
161
    if (tproc = parent_proto.pr_input) (*tproc)(am,iphlen);
 
162
    USERPRI;
 
163
    return;
 
164
}
 
165
 
 
166
 
 
167
/* 
 
168
 * UDP fast timer to raise events for all but Solaris and NCR. 
 
169
 * Called about 5 times per second (at unknown priority?).  Must go to
 
170
 * splnet or obtain global lock before touching anything significant.
 
171
 */
 
172
static void rxk_fasttimo (void)
 
173
{
 
174
    void (*tproc)();
 
175
    struct clock temp;
 
176
 
 
177
    /* do rx fasttimo processing here */
 
178
    rxevent_RaiseEvents(&temp);
 
179
    if (tproc = parent_proto.pr_fasttimo) (*tproc)();
 
180
}
 
181
 
 
182
 
 
183
/* rx_NetSend - send asize bytes at adata from asocket to host at addr.
 
184
 *
 
185
 * Now, why do we allocate a new buffer when we could theoretically use the one
 
186
 * pointed to by adata?  Because PRU_SEND returns after queueing the message,
 
187
 * not after sending it.  If the sender changes the data after queueing it,
 
188
 * we'd see the already-queued data change.  One attempt to fix this without
 
189
 * adding a copy would be to have this function wait until the datagram is
 
190
 * sent; however this doesn't work well.  In particular, if a host is down, and
 
191
 * an ARP fails to that host, this packet will be queued until the ARP request
 
192
 * comes back, which could be hours later.  We can't block in this routine that
 
193
 * long, since it prevents RPC timeouts from happening.
 
194
 */
 
195
/* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
 
196
 * and just queue those.  XXX
 
197
 */
 
198
 
 
199
/* set lock on sockbuf sb; can't call sblock since we're at interrupt level
 
200
 * sometimes */
 
201
static trysblock(sb)    
 
202
register struct sockbuf *sb; {
 
203
    AFS_STATCNT(trysblock);
 
204
    if (sb->sb_flags & SB_LOCK){
 
205
        return -1;  /* can't lock socket */
 
206
    }
 
207
    sb->sb_flags |= SB_LOCK;
 
208
    return 0;
 
209
}
 
210
 
 
211
int 
 
212
osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
 
213
     register struct socket *asocket;
 
214
     struct iovec *dvec;
 
215
     int nvec;
 
216
     register afs_int32 asize;
 
217
     struct sockaddr_in *addr;
 
218
     int istack;
 
219
{
 
220
    register struct mbuf *tm, *um;
 
221
    register afs_int32 code;
 
222
    int s;
 
223
    struct mbuf *top = 0;
 
224
    register struct mbuf *m, **mp;
 
225
    int len;
 
226
    char *tdata;
 
227
    caddr_t tpa;
 
228
    int i,tl,rlen;
 
229
    int mlen;
 
230
    int haveGlock;
 
231
 
 
232
    AFS_STATCNT(osi_NetSend);
 
233
 
 
234
/* Actually, the Ultrix way is as good as any for us, so we don't bother with
 
235
 * special mbufs any more.  Used to think we could get away with not copying
 
236
 * the data to the interface, but there's no way to tell the caller not to
 
237
 * reuse the buffers after sending, so we lost out on that trick anyway */
 
238
 
 
239
    s = splnet();
 
240
    mp = &top;
 
241
    i = 0;
 
242
    tdata = dvec[i].iov_base;
 
243
    tl = dvec[i].iov_len;
 
244
    while (1) {
 
245
        mlen = MLEN;
 
246
        if (top == 0) {
 
247
            MGETHDR(m, M_DONTWAIT, MT_DATA);
 
248
            if (!m) {
 
249
                splx(s);
 
250
                return 1;
 
251
            }
 
252
            mlen = MHLEN;
 
253
            m->m_pkthdr.len = 0;
 
254
            m->m_pkthdr.rcvif = (struct ifnet *)0;
 
255
        } else
 
256
        MGET(m, M_DONTWAIT, MT_DATA);
 
257
        if (!m) {
 
258
            /* can't get an mbuf, give up */
 
259
            if (top) m_freem(top);      /* free mbuf list we're building */
 
260
            splx(s);
 
261
            return 1;
 
262
        }
 
263
        /*
 
264
         * WARNING: the `4 * MLEN' is somewhat dubious.  It is better than
 
265
         * `NBPG', which may have no relation to `CLBYTES'.  Also, `CLBYTES'
 
266
         * may be so large that we never use clusters, resulting in far
 
267
         * too many mbufs being used.  It is often better to briefly use
 
268
         * a cluster, even if we are only using a portion of it.  Since
 
269
         * we are on the xmit side, it shouldn't end up sitting on a queue
 
270
         * for a potentially unbounded time (except perhaps if we are talking
 
271
         * to ourself).
 
272
         */
 
273
        if (asize >= 4 * MLEN) {        /* try to get cluster mbuf */
 
274
            register struct mbuf *p;
 
275
 
 
276
            /* different algorithms for getting cluster mbuf */
 
277
            MCLGET(m, M_DONTWAIT);
 
278
            if ((m->m_flags & M_EXT) == 0)
 
279
                goto nopages;
 
280
            mlen = MCLBYTES;
 
281
 
 
282
            /* now compute usable size */
 
283
            len = MIN(mlen, asize);
 
284
/* Should I look at MAPPED_MBUFS??? */
 
285
        } else {
 
286
nopages:
 
287
            len = MIN(mlen, asize);
 
288
        }
 
289
        m->m_len = 0;
 
290
        *mp = m;        /* XXXX */
 
291
        top->m_pkthdr.len += len;
 
292
        tpa = mtod(m, caddr_t);
 
293
        while (len) {
 
294
          rlen = MIN(len, tl);
 
295
          memcpy(tpa, tdata, rlen);
 
296
          asize -= rlen;
 
297
          len -= rlen;
 
298
          tpa += rlen;
 
299
          m->m_len += rlen;
 
300
          tdata += rlen;
 
301
          tl -= rlen;
 
302
          if (tl <= 0) {
 
303
            i++;
 
304
            if (i > nvec) {
 
305
              /* shouldn't come here! */
 
306
              asize = 0;   /* so we make progress toward completion */
 
307
              break;
 
308
            }
 
309
            tdata = dvec[i].iov_base;
 
310
            tl = dvec[i].iov_len;
 
311
          }
 
312
        }
 
313
        *mp = m;
 
314
        mp = &m->m_next;
 
315
        if (asize <= 0)
 
316
          break;
 
317
    }
 
318
    tm = top;
 
319
 
 
320
    tm->m_act = (struct mbuf *) 0;
 
321
 
 
322
    /* setup mbuf corresponding to destination address */
 
323
    um = m_get(M_DONTWAIT, MT_SONAME);
 
324
    if (!um) {
 
325
        if (top) m_freem(top);  /* free mbuf chain */
 
326
        /* if this were vfs40, we'd do sbunlock(asocket, &asocket->so_snd), but
 
327
           we don't do the locking at all for vfs40 systems */
 
328
        splx(s);
 
329
        return 1;
 
330
    }
 
331
    memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
 
332
    um->m_len = sizeof(*addr);
 
333
    /* note that udp_usrreq frees funny mbuf.  We hold onto data, but mbuf
 
334
     * around it is gone.  we free address ourselves.  */
 
335
    haveGlock = ISAFS_GLOCK();
 
336
    if (haveGlock) {
 
337
        AFS_GUNLOCK();
 
338
    }
 
339
    SOCKET_LOCK(asocket);
 
340
    code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0);
 
341
    SOCKET_UNLOCK(asocket);
 
342
    if (haveGlock) {
 
343
        AFS_GLOCK();
 
344
    }
 
345
    splx(s);
 
346
    m_free(um);
 
347
 
 
348
    return code;
 
349
}
 
350
 
 
351
#endif /* AFS_DUX40_ENV */