source: rtems/cpukit/libnetworking/kern/uipc_mbuf.c @ cb68253

5
Last change on this file since cb68253 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

  • Property mode set to 100644
File size: 15.3 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*
4 * Copyright (c) 1982, 1986, 1988, 1991, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/proc.h>
37#include <sys/malloc.h>
38#define MBTYPES
39#include <sys/mbuf.h>
40#include <sys/kernel.h>
41#include <sys/syslog.h>
42#include <sys/domain.h>
43#include <sys/protosw.h>
44
45#include <vm/vm.h>
46#include <vm/vm_param.h>
47#include <vm/vm_kern.h>
48#include <vm/vm_extern.h>
49
50#if !defined(__rtems__)
51static void mbinit (void *) __attribute__ ((unused));
52SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL)
53#endif
54
55struct mbuf *mbutl;
56char    *mclrefcnt;
57struct mbstat mbstat;
58struct mbuf *mmbfree;
59union mcluster *mclfree;
60int     max_linkhdr;
61int     max_protohdr;
62int     max_hdr;
63int     max_datalen;
64
65/* "number of clusters of pages" */
66#define NCL_INIT        1
67
68#define NMB_INIT        16
69
70/*
71 * When MGET failes, ask protocols to free space when short of memory,
72 * then re-attempt to allocate an mbuf.
73 */
74struct mbuf *
75m_retry(int i, int t)
76{
77        register struct mbuf *m;
78
79        m_reclaim();
80#define m_retry(i, t)   (struct mbuf *)0
81        MGET(m, i, t);
82#undef m_retry
83        if (m != NULL)
84                mbstat.m_wait++;
85        else
86                mbstat.m_drops++;
87        return (m);
88}
89
90/*
91 * As above; retry an MGETHDR.
92 */
93struct mbuf *
94m_retryhdr(int i, int t)
95{
96        register struct mbuf *m;
97
98        m_reclaim();
99#define m_retryhdr(i, t) (struct mbuf *)0
100        MGETHDR(m, i, t);
101#undef m_retryhdr
102        if (m != NULL)
103                mbstat.m_wait++;
104        else
105                mbstat.m_drops++;
106        return (m);
107}
108
109void
110m_reclaim(void)
111{
112        register struct domain *dp;
113        register struct protosw *pr;
114        int s = splimp();
115
116        for (dp = domains; dp; dp = dp->dom_next)
117                for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
118                        if (pr->pr_drain)
119                                (*pr->pr_drain)();
120        splx(s);
121        mbstat.m_drain++;
122}
123
124/*
125 * Space allocation routines.
126 * These are also available as macros
127 * for critical paths.
128 */
129struct mbuf *
130m_get(int nowait, int type)
131{
132        register struct mbuf *m;
133
134        MGET(m, nowait, type);
135        return (m);
136}
137
138struct mbuf *
139m_gethdr(int nowait, int type)
140{
141        register struct mbuf *m;
142
143        MGETHDR(m, nowait, type);
144        return (m);
145}
146
147struct mbuf *
148m_getclr(int nowait, int type)
149{
150        register struct mbuf *m;
151
152        MGET(m, nowait, type);
153        if (m == 0)
154                return (0);
155        bzero(mtod(m, caddr_t), MLEN);
156        return (m);
157}
158
159struct mbuf *
160m_free(struct mbuf *m)
161{
162        struct mbuf *n;
163
164        MFREE(m, n);
165        return (n);
166}
167
168void
169m_freem(struct mbuf *mb)
170{
171        struct mbuf *n;
172
173        if (mb == NULL)
174                return;
175        do {
176                MFREE(mb, n);
177                mb = n;
178        } while (mb);
179}
180
181/*
182 * Mbuffer utility routines.
183 */
184
185/*
186 * Lesser-used path for M_PREPEND:
187 * allocate new mbuf to prepend to chain,
188 * copy junk along.
189 */
190struct mbuf *
191m_prepend(struct mbuf *m, int len, int how)
192{
193        struct mbuf *mn;
194
195        MGET(mn, how, m->m_type);
196        if (mn == (struct mbuf *)NULL) {
197                m_freem(m);
198                return ((struct mbuf *)NULL);
199        }
200        if (m->m_flags & M_PKTHDR) {
201                M_COPY_PKTHDR(mn, m);
202                m->m_flags &= ~M_PKTHDR;
203        }
204        mn->m_next = m;
205        m = mn;
206        if (len < MHLEN)
207                MH_ALIGN(m, len);
208        m->m_len = len;
209        return (m);
210}
211
212/*
213 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
214 * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
215 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
216 */
217static int MCFail;
218
219struct mbuf *
220m_copym(struct mbuf *m, int off0, uint32_t len, int wait)
221{
222        struct mbuf *n, **np;
223        int off = off0;
224        struct mbuf *top;
225        int copyhdr = 0;
226
227        if (off < 0 || len < 0)
228                panic("m_copym");
229        if (off == 0 && m->m_flags & M_PKTHDR)
230                copyhdr = 1;
231        while (off > 0) {
232                if (m == NULL)
233                        panic("m_copym");
234                if (off < m->m_len)
235                        break;
236                off -= m->m_len;
237                m = m->m_next;
238        }
239        np = &top;
240        top = 0;
241        while (len > 0) {
242                if (m == NULL) {
243                        if (len != M_COPYALL)
244                                panic("m_copym");
245                        break;
246                }
247                MGET(n, wait, m->m_type);
248                *np = n;
249                if (n == NULL)
250                        goto nospace;
251                if (copyhdr) {
252                        M_COPY_PKTHDR(n, m);
253                        if (len == M_COPYALL)
254                                n->m_pkthdr.len -= off0;
255                        else
256                                n->m_pkthdr.len = len;
257                        copyhdr = 0;
258                }
259                n->m_len = min(len, m->m_len - off);
260                if (m->m_flags & M_EXT) {
261                        n->m_data = m->m_data + off;
262                        if(!m->m_ext.ext_ref)
263                                mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
264                        else
265                                (*(m->m_ext.ext_ref))(m->m_ext.ext_buf,
266                                                        m->m_ext.ext_size);
267                        n->m_ext = m->m_ext;
268                        n->m_flags |= M_EXT;
269                } else
270                        bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
271                            (unsigned)n->m_len);
272                if (len != M_COPYALL)
273                        len -= n->m_len;
274                off = 0;
275                m = m->m_next;
276                np = &n->m_next;
277        }
278        if (top == NULL)
279                MCFail++;
280        return (top);
281nospace:
282        m_freem(top);
283        MCFail++;
284        return (NULL);
285}
286
287/*
288 * Copy an entire packet, including header (which must be present).
289 * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'.
290 */
291struct mbuf *
292m_copypacket(struct mbuf *m, int how)
293{
294        struct mbuf *top, *n, *o;
295
296        MGET(n, how, m->m_type);
297        top = n;
298        if (!n)
299                goto nospace;
300
301        M_COPY_PKTHDR(n, m);
302        n->m_len = m->m_len;
303        if (m->m_flags & M_EXT) {
304                n->m_data = m->m_data;
305                mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
306                n->m_ext = m->m_ext;
307                n->m_flags |= M_EXT;
308        } else {
309                bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
310        }
311
312        m = m->m_next;
313        while (m) {
314                MGET(o, how, m->m_type);
315                if (!o)
316                        goto nospace;
317
318                n->m_next = o;
319                n = n->m_next;
320
321                n->m_len = m->m_len;
322                if (m->m_flags & M_EXT) {
323                        n->m_data = m->m_data;
324                        mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
325                        n->m_ext = m->m_ext;
326                        n->m_flags |= M_EXT;
327                } else {
328                        bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
329                }
330
331                m = m->m_next;
332        }
333        return top;
334nospace:
335        m_freem(top);
336        MCFail++;
337        return 0;
338}
339
340/*
341 * Copy data from an mbuf chain starting "off" bytes from the beginning,
342 * continuing for "len" bytes, into the indicated buffer. Return -1 if requested
343 * size is bigger than available
344 */
345int
346m_copydata(const struct mbuf *m, int off, int len, caddr_t cp)
347{
348        u_int count;
349
350        if (off < 0 || len < 0)
351                panic("m_copydata");
352        while (off > 0) {
353                if (m == 0) {
354                        /*printf("m_copydata: offset > mbuf length (");
355                        while(m0) {
356                            printf("[%d] ",m0->m_len);
357                            m0 = m0->m_next;
358                        }
359                        printf(")\n");*/
360                        return -1;
361                }
362                if (off < m->m_len)
363                        break;
364                off -= m->m_len;
365                m = m->m_next;
366        }
367        while (len > 0) {
368                if (m == 0) {
369                        /*printf("m_copydata: length > mbuf length (");
370                        while(m0) {
371                            printf("[%d] ",m0->m_len);
372                            m0 = m0->m_next;
373                        }
374                        printf(")\n");*/
375                       
376                        return -1;
377                    }
378                count = min(m->m_len - off, len);
379                bcopy(mtod(m, caddr_t) + off, cp, count);
380                len -= count;
381                cp += count;
382                off = 0;
383                m = m->m_next;
384        }
385    return 0;
386}
387
388/*
389 * Concatenate mbuf chain n to m.
390 * Both chains must be of the same type (e.g. MT_DATA).
391 * Any m_pkthdr is not updated.
392 */
393void
394m_cat(struct mbuf *m, struct mbuf *n)
395{
396        while (m->m_next)
397                m = m->m_next;
398        while (n) {
399                if (m->m_flags & M_EXT ||
400                    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
401                        /* just join the two chains */
402                        m->m_next = n;
403                        return;
404                }
405                /* splat the data from one into the other */
406                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
407                    (u_int)n->m_len);
408                m->m_len += n->m_len;
409                n = m_free(n);
410        }
411}
412
413void
414m_adj(struct mbuf *mp, int req_len)
415{
416        int len = req_len;
417        struct mbuf *m;
418        int count;
419
420        if ((m = mp) == NULL)
421                return;
422        if (len >= 0) {
423                /*
424                 * Trim from head.
425                 */
426                while (m != NULL && len > 0) {
427                        if (m->m_len <= len) {
428                                len -= m->m_len;
429                                m->m_len = 0;
430                                m = m->m_next;
431                        } else {
432                                m->m_len -= len;
433                                m->m_data += len;
434                                len = 0;
435                        }
436                }
437                m = mp;
438                if (mp->m_flags & M_PKTHDR)
439                        m->m_pkthdr.len -= (req_len - len);
440        } else {
441                /*
442                 * Trim from tail.  Scan the mbuf chain,
443                 * calculating its length and finding the last mbuf.
444                 * If the adjustment only affects this mbuf, then just
445                 * adjust and return.  Otherwise, rescan and truncate
446                 * after the remaining size.
447                 */
448                len = -len;
449                count = 0;
450                for (;;) {
451                        count += m->m_len;
452                        if (m->m_next == (struct mbuf *)0)
453                                break;
454                        m = m->m_next;
455                }
456                if (m->m_len >= len) {
457                        m->m_len -= len;
458                        if (mp->m_flags & M_PKTHDR)
459                                mp->m_pkthdr.len -= len;
460                        return;
461                }
462                count -= len;
463                if (count < 0)
464                        count = 0;
465                /*
466                 * Correct length for chain is "count".
467                 * Find the mbuf with last data, adjust its length,
468                 * and toss data from remaining mbufs on chain.
469                 */
470                m = mp;
471                if (m->m_flags & M_PKTHDR)
472                        m->m_pkthdr.len = count;
473                for (; m; m = m->m_next) {
474                        if (m->m_len >= count) {
475                                m->m_len = count;
476                                break;
477                        }
478                        count -= m->m_len;
479                }
480                while (m->m_next)
481                        (m = m->m_next) ->m_len = 0;
482        }
483}
484
485/*
486 * Rearange an mbuf chain so that len bytes are contiguous
487 * and in the data area of an mbuf (so that mtod and dtom
488 * will work for a structure of size len).  Returns the resulting
489 * mbuf chain on success, frees it and returns null on failure.
490 * If there is room, it will add up to max_protohdr-len extra bytes to the
491 * contiguous region in an attempt to avoid being called next time.
492 */
493static int MPFail;
494
495struct mbuf *
496m_pullup(struct mbuf *n, int len)
497{
498        struct mbuf *m;
499        int count;
500        int space;
501
502        /*
503         * If first mbuf has no cluster, and has room for len bytes
504         * without shifting current data, pullup into it,
505         * otherwise allocate a new mbuf to prepend to the chain.
506         */
507        if ((n->m_flags & M_EXT) == 0 &&
508            n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
509                if (n->m_len >= len)
510                        return (n);
511                m = n;
512                n = n->m_next;
513                len -= m->m_len;
514        } else {
515                if (len > MHLEN)
516                        goto bad;
517                MGET(m, M_DONTWAIT, n->m_type);
518                if (m == NULL)
519                        goto bad;
520                m->m_len = 0;
521                if (n->m_flags & M_PKTHDR) {
522                        M_COPY_PKTHDR(m, n);
523                        n->m_flags &= ~M_PKTHDR;
524                }
525        }
526        space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
527        do {
528                count = min(min(max(len, max_protohdr), space), n->m_len);
529                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
530                  (unsigned)count);
531                len -= count;
532                m->m_len += count;
533                n->m_len -= count;
534                space -= count;
535                if (n->m_len)
536                        n->m_data += count;
537                else
538                        n = m_free(n);
539        } while (len > 0 && n);
540        if (len > 0) {
541                (void) m_free(m);
542                goto bad;
543        }
544        m->m_next = n;
545        return (m);
546 bad:
547        m_freem(n);
548        MPFail++;
549        return (NULL);
550}
551
552/*
553 * Partition an mbuf chain in two pieces, returning the tail --
554 * all but the first len0 bytes.  In case of failure, it returns NULL and
555 * attempts to restore the chain to its original state.
556 */
557struct mbuf *
558m_split(struct mbuf *m0, int len0, int wait)
559{
560        struct mbuf *m, *n;
561        u_int len = len0, remain;
562
563        for (m = m0; m && len > m->m_len; m = m->m_next)
564                len -= m->m_len;
565        if (m == NULL)
566                return (NULL);
567        remain = m->m_len - len;
568        if (m0->m_flags & M_PKTHDR) {
569                MGETHDR(n, wait, m0->m_type);
570                if (n == NULL)
571                        return (NULL);
572                n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
573                n->m_pkthdr.len = m0->m_pkthdr.len - len0;
574                m0->m_pkthdr.len = len0;
575                if (m->m_flags & M_EXT)
576                        goto extpacket;
577                if (remain > MHLEN) {
578                        /* m can't be the lead packet */
579                        MH_ALIGN(n, 0);
580                        n->m_next = m_split(m, len, wait);
581                        if (n->m_next == 0) {
582                                (void) m_free(n);
583                                return (0);
584                        } else
585                                return (n);
586                } else
587                        MH_ALIGN(n, remain);
588        } else if (remain == 0) {
589                n = m->m_next;
590                m->m_next = NULL;
591                return (n);
592        } else {
593                MGET(n, wait, m->m_type);
594                if (n == 0)
595                        return (0);
596                M_ALIGN(n, remain);
597        }
598extpacket:
599        if (m->m_flags & M_EXT) {
600                n->m_flags |= M_EXT;
601                n->m_ext = m->m_ext;
602                if(!m->m_ext.ext_ref)
603                        mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
604                else
605                        (*(m->m_ext.ext_ref))(m->m_ext.ext_buf,
606                                                m->m_ext.ext_size);
607                m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
608                n->m_data = m->m_data + len;
609        } else {
610                bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
611        }
612        n->m_len = remain;
613        m->m_len = len;
614        n->m_next = m->m_next;
615        m->m_next = NULL;
616        return (n);
617}
618/*
619 * Routine to copy from device local memory into mbufs.
620 */
621struct mbuf *
622m_devget(char *buf, int totlen, int off0, struct ifnet *ifp,
623        void (*copy)(char *from, caddr_t to, u_int len))
624{
625        struct mbuf *m;
626        struct mbuf *top = NULL, **mp = &top;
627        int len;
628        int off = off0;
629        char *cp;
630        char *epkt;
631
632        cp = buf;
633        epkt = cp + totlen;
634        if (off) {
635                cp += off + 2 * sizeof(u_short);
636                totlen -= 2 * sizeof(u_short);
637        }
638        MGETHDR(m, M_DONTWAIT, MT_DATA);
639        if (m == 0)
640                return (0);
641        m->m_pkthdr.rcvif = ifp;
642        m->m_pkthdr.len = totlen;
643        m->m_len = MHLEN;
644
645        while (totlen > 0) {
646                if (top) {
647                        MGET(m, M_DONTWAIT, MT_DATA);
648                        if (m == 0) {
649                                m_freem(top);
650                                return (0);
651                        }
652                        m->m_len = MLEN;
653                }
654                len = min(totlen, epkt - cp);
655                if (len >= MINCLSIZE) {
656                        MCLGET(m, M_DONTWAIT);
657                        if (m->m_flags & M_EXT)
658                                m->m_len = len = min(len, MCLBYTES);
659                        else
660                                len = m->m_len;
661                } else {
662                        /*
663                         * Place initial small packet/header at end of mbuf.
664                         */
665                        if (len < m->m_len) {
666                                if (top == 0 && len + max_linkhdr <= m->m_len)
667                                        m->m_data += max_linkhdr;
668                                m->m_len = len;
669                        } else
670                                len = m->m_len;
671                }
672                if (copy)
673                        copy(cp, mtod(m, caddr_t), (u_int)len);
674                else
675                        bcopy(cp, mtod(m, caddr_t), (u_int)len);
676                cp += len;
677                *mp = m;
678                mp = &m->m_next;
679                totlen -= len;
680                if (cp == epkt)
681                        cp = buf;
682        }
683        return (top);
684}
685
686/*
687 * Copy data from a buffer back into the indicated mbuf chain,
688 * starting "off" bytes from the beginning, extending the mbuf
689 * chain if necessary.
690 */
691int
692m_copyback(struct mbuf *m0, int off, int len, caddr_t cp)
693{
694        int mlen;
695        struct mbuf *m = m0, *n;
696        int totlen = 0;
697
698        if (m0 == NULL)
699                return 0;
700        while (off > (mlen = m->m_len)) {
701                off -= mlen;
702                totlen += mlen;
703                if (m->m_next == NULL) {
704                        n = m_getclr(M_DONTWAIT, m->m_type);
705                        if (n == NULL) {
706                                /*panic("m_copyback() : malformed chain\n");*/
707                                return -1;
708                                }
709                        n->m_len = min(MLEN, len + off);
710                        m->m_next = n;
711                }
712                m = m->m_next;
713        }
714        while (len > 0) {
715                mlen = min (m->m_len - off, len);
716                bcopy(cp, off + mtod(m, caddr_t), (u_int)mlen);
717                cp += mlen;
718                len -= mlen;
719                mlen += off;
720                off = 0;
721                totlen += mlen;
722                if (len == 0) {
723                        /* m->m_len = mlen; */
724                        break;
725                }
726                if (m->m_next == NULL) {
727                        n = m_get(M_DONTWAIT, m->m_type);
728                        if (n == 0) {
729                                /*panic("m_copyback() : malformed chain 2\n");*/
730                                return -1;
731                                };
732                        n->m_len = min(MLEN, len);
733                        m->m_next = n;
734                }
735                /* m->m_len = mlen; */
736                m = m->m_next;
737        }
738/*out:*/
739        if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
740                m->m_pkthdr.len = totlen;
741        return 0;
742}
Note: See TracBrowser for help on using the repository browser.