|
|
1.1 root 1: /*
2: * Copyright (c) 1990 Regents of the University of California.
3: * 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: * @(#)if_dp.c 7.9 (Berkeley) 6/27/91
34: */
35:
36: #include "dp.h"
37: #if NDP > 0
38:
39: /*
40: * DPV-11 device driver, X.25 version
41: *
42: * Derived from dmc-11 driver:
43: *
44: * Bill Nesheim
45: * Cornell University
46: *
47: * Lou Salkind
48: * New York University
49: */
50:
51: /* #define DEBUG /* for base table dump on fatal error */
52:
53: #include "../include/pte.h"
54:
55: #include "sys/param.h"
56: #include "sys/systm.h"
57: #include "sys/mbuf.h"
58: #include "sys/buf.h"
59: #include "sys/ioctl.h" /* must precede tty.h */
60: #include "sys/protosw.h"
61: #include "sys/socket.h"
62: #include "sys/socketvar.h"
63: #include "sys/syslog.h"
64: #include "sys/vmmac.h"
65: #include "sys/errno.h"
66: #include "sys/time.h"
67: #include "sys/kernel.h"
68:
69: #include "net/if.h"
70: #include "net/if_types.h"
71: #include "net/netisr.h"
72: #include "net/route.h"
73:
74: #include "../include/cpu.h"
75: #include "../include/mtpr.h"
76:
77: #define dzdevice dpdevice
78: #include "../uba/pdma.h"
79: #include "../uba/ubavar.h"
80:
81: #include "netccitt/x25.h"
82: #include "netccitt/pk.h"
83: #include "netccitt/pk_var.h"
84:
85: #include "if_dpreg.h"
86:
87: /*
88: * Driver information for auto-configuration stuff.
89: */
90: int dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
91: int dpoutput(), dpreset(), dptimeout(), dpstart(), dptestoutput();
92: int x25_ifoutput(), x25_rtrequest();
93:
94: struct uba_device *dpinfo[NDP];
95:
96: u_short dpstd[] = { 0 };
97: struct uba_driver dpdriver =
98: { dpprobe, 0, dpattach, 0, dpstd, "dp", dpinfo };
99:
100: /*
101: * Pdma structures for fast interrupts.
102: */
103: struct pdma dppdma[2*NDP];
104:
105: /*
106: * DP software status per interface.
107: *
108: * Each interface is referenced by a network interface structure,
109: * dp_if, which the routing code uses to locate the interface.
110: * This structure contains the output queue for the interface, its address, ...
111: */
112: struct dp_softc {
113: struct ifnet dp_if; /* network-visible interface */
114: int dp_ipl;
115: struct dpdevice *dp_addr; /* dpcsr address */
116: short dp_iused; /* input buffers given to DP */
117: short dp_flags; /* flags */
118: #define DPF_RUNNING 0x01 /* device initialized */
119: #define DPF_ONLINE 0x02 /* device running (had a RDYO) */
120: #define DPF_RESTART 0x04 /* software restart in progress */
121: #define DPF_FLUSH 0x08 /* had a ROVR, flush ipkt when done */
122: #define DPF_X25UP 0x10 /* XXX -- someday we'll do PPP also */
123: short dp_ostate; /* restarting, etc. */
124: short dp_istate; /* not sure this is necessary */
125: #define DPS_IDLE 0
126: #define DPS_RESTART 1
127: #define DPS_ACTIVE 2
128: #define DPS_XEM 3 /* transmitting CRC, etc. */
129: short dp_olen; /* length of last packet sent */
130: short dp_ilen; /* length of last packet recvd */
131: char dp_obuf[DP_MTU+8];
132: char dp_ibuf[DP_MTU+8];
133: } dp_softc[NDP];
134:
135: /*
136: * Debug info
137: */
138: struct dpstat {
139: long start;
140: long nohdr;
141: long init;
142: long rint;
143: long xint;
144: long reset;
145: long ioctl;
146: long down;
147: long mchange;
148: long timeout;
149: long rsm;
150: long rem;
151: long remchr;
152: long rga;
153: long xem;
154: long rovr;
155: } dpstat;
156:
157: short dp_ilb = 0;
158: short dp_log = 0;
159:
160: #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
161: int dp_sizes[] = {
162: sizeof(dp_softc[0]), sizeof(struct ifnet),
163: _offsetof(struct dp_softc, dp_obuf[0]),
164: _offsetof(struct dp_softc, dp_ibuf[0]),
165: };
166:
167: dpprobe(reg, ui)
168: caddr_t reg;
169: struct uba_device *ui;
170: {
171: register int br, cvec;
172: register struct dpdevice *addr = (struct dpdevice *)reg;
173: register int unit = ui->ui_unit;
174:
175: #ifdef lint
176: br = 0; cvec = br; br = cvec;
177: dprint(0); dpxint(0);
178: #endif
179: (void) spl6();
180: addr->dpclr = DP_CLR;
181: addr->dpclr = DP_XIE|DP_XE;
182: DELAY(100000);
183: dp_softc[unit].dp_ipl = br = qbgetpri();
184: dp_softc[unit].dp_addr = addr;
185: addr->dpclr = 0;
186: if (cvec && cvec != 0x200){
187: cvec -= 4;
188: }
189: return (1);
190: }
191:
192: /*
193: * Interface exists: make available by filling in network interface
194: * record. System will initialize the interface when it is ready
195: * to accept packets.
196: */
197: dpattach(ui)
198: register struct uba_device *ui;
199: {
200: register struct dp_softc *dp = &dp_softc[ui->ui_unit];
201:
202: dp->dp_if.if_unit = ui->ui_unit;
203: dp->dp_if.if_name = "dp";
204: dp->dp_if.if_mtu = DP_MTU;
205: dp->dp_if.if_init = dpinit;
206: dp->dp_if.if_output = x25_ifoutput;
207: dp->dp_if.if_type = IFT_X25;
208: dp->dp_if.if_hdrlen = 5;
209: dp->dp_if.if_addrlen = 8;
210: dp->dp_if.if_start = dpstart;
211: dp->dp_if.if_ioctl = dpioctl;
212: dp->dp_if.if_reset = dpreset;
213: dp->dp_if.if_watchdog = dptimeout;
214: dp->dp_if.if_flags = 0;
215: if_attach(&dp->dp_if);
216: }
217:
218: /*
219: * Reset of interface after UNIBUS reset.
220: * If interface is on specified UBA, reset its state.
221: */
222: dpreset(unit, uban)
223: int unit, uban;
224: {
225: register struct uba_device *ui;
226: register struct dp_softc *dp = &dp_softc[unit];
227: register struct dpdevice *addr;
228:
229: dpstat.reset++;
230: if (unit >= NDP || (ui = dpinfo[unit]) == 0 || ui->ui_alive == 0 ||
231: ui->ui_ubanum != uban)
232: return;
233: dpdown(unit);
234: dpinit(unit);
235: printf(" dp%d", unit);
236: }
237:
238: /*
239: * Initialization of interface.
240: */
241: dpinit(unit)
242: int unit;
243: {
244: register struct dp_softc *dp = &dp_softc[unit];
245: register struct dpdevice *addr;
246: register struct ifaddr *ifa;
247: register struct pdma *pdp = &dppdma[unit*2];
248: int base, s;
249:
250: dpstat.init++;
251: /*
252: * Check to see that an address has been set.
253: */
254: for (ifa = dp->dp_if.if_addrlist; ifa; ifa = ifa->ifa_next)
255: if (ifa->ifa_addr->sa_family != AF_LINK)
256: break;
257: if (ifa == (struct ifaddr *) 0)
258: return;
259:
260: addr = dp->dp_addr;
261: s = splimp();
262: dp->dp_iused = 0;
263: dp->dp_istate = dp->dp_ostate = DPS_IDLE;
264: dp->dp_if.if_flags |= IFF_RUNNING;
265: dp->dp_if.if_flags &= ~IFF_OACTIVE;
266:
267: pdp->p_addr = addr;
268: pdp->p_fcn = dpxint;
269: pdp->p_mem = pdp->p_end = dp->dp_obuf;
270: pdp++;
271: pdp->p_addr = addr;
272: pdp->p_fcn = dprint;
273: /* force initial interrupt to come to dprint */
274: pdp->p_mem = pdp->p_end = dp->dp_ibuf + DP_MTU + 8;
275:
276: addr->dpclr = DP_CLR;
277: DELAY(5000);
278: /* DP_ATA = 0, DP_CHRM = 0, DP_SSLM = 1, (enable aborts),
279: CRC = CCIIT, initially all ones, 2nd addr = 0 */
280: addr->dpsar = DP_SSLM | DP_IDLE;
281: addr->dpclr = DP_XE | dp_ilb;
282: addr->dptdsr = DP_XSM;
283: /* enable receiver, receive interrupt, DTR, RTS */
284: addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
285: dpstart(&dp->dp_if);
286: splx(s);
287: }
288:
289: /*
290: * Start output on interface. Get another datagram
291: * to send from the interface queue and map it to
292: * the interface before starting output.
293: *
294: */
295: dpstart(ifp)
296: struct ifnet *ifp;
297: {
298: int s, unit = ifp->if_unit, error = 0, len;
299: register struct dp_softc *dp = &dp_softc[unit];
300: register struct dpdevice *addr = dp->dp_addr;
301: register struct mbuf *m;
302: register char *cp;
303: char *cplim;
304:
305: /*
306: * If already doing output, go away and depend on transmit
307: * complete or error.
308: */
309: dpstat.start++;
310: if ((dp->dp_if.if_flags & IFF_OACTIVE) ||
311: (dp->dp_if.if_flags & IFF_RUNNING) == 0)
312: goto out;
313: IF_DEQUEUE(&dp->dp_if.if_snd, m);
314: if (m == 0)
315: goto out;
316: dp->dp_if.if_collisions++;
317: if (m->m_flags & M_PKTHDR)
318: len = m->m_pkthdr.len;
319: else {
320: struct mbuf *m0 = m;
321: for (len = 0; m; m = m->m_next)
322: len += m->m_len;
323: m = m0;
324: dpstat.nohdr++;
325: }
326: if (len < 2)
327: goto out;
328: if (len > DP_MTU) {
329: error = EINVAL;
330: goto out;
331: }
332: dppdma[2*unit].p_mem = cp = dp->dp_obuf;
333: while (m) {
334: struct mbuf *n;
335: bcopy(mtod(m, caddr_t), (caddr_t)cp, m->m_len);
336: cp += m->m_len;
337: MFREE(m, n); m = n;
338: }
339: dppdma[2*unit].p_end = cp - 1;
340: dp->dp_if.if_flags |= IFF_OACTIVE;
341: dp->dp_ostate = DPS_ACTIVE;
342: dp->dp_if.if_collisions--;
343: dp->dp_olen = len;
344: if (dp_log) {
345: register u_char *p = (u_char *)dp->dp_obuf;
346: log(LOG_DEBUG, "dpoutput(%d):%x %x %x %x %x\n",
347: len, p[0], p[1], p[2], p[3], p[4]);
348: }
349: addr->dpsar = DP_SSLM | DP_IDLE;
350: addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
351: addr->dpclr = DP_XIE | DP_XE | dp_ilb;
352: addr->dptdsr = DP_XSM;
353: out:
354: return (error);
355: }
356: /*
357: * Receive done or error interrupt
358: */
359: dprint(unit, pdma, addr)
360: register struct pdma *pdma;
361: register struct dpdevice *addr;
362: {
363: register struct dp_softc *dp = &dp_softc[unit];
364: short rdsr = addr->dprdsr, rcsr = pdma->p_arg;
365:
366: dpstat.rint++;
367: splx(dp->dp_ipl);
368: if (rdsr & DP_RGA) {
369: /* DP_ATA = 0, DP_CHRM = 0, DP_SSLM = 1, (enable aborts),
370: CRC = CCIIT, initially all ones, 2nd addr = 0 */
371: addr->dpsar = DP_SSLM | DP_IDLE;
372: addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
373: dpstat.rga++;
374: return;
375: }
376: if (rdsr & DP_RSM) { /* Received Start of Message */
377: dpstat.rsm++;
378: pdma->p_mem = dp->dp_ibuf;
379: if (rcsr & DP_RDR) {
380: dp->dp_ibuf[0] = rdsr & DP_RBUF;
381: pdma->p_mem++;
382: }
383: dp->dp_flags &= ~DPF_FLUSH;
384: return;
385: }
386: if (rdsr & DP_REM) { /* Received End of Message */
387: dpstat.rem++;
388: if (rcsr & DP_RDR) {
389: *(pdma->p_mem++) = rdsr;
390: dpstat.remchr++;
391: }
392: dp->dp_ilen = pdma->p_mem - dp->dp_ibuf;
393: if (rdsr & DP_REC || dp->dp_flags & DPF_FLUSH) {
394: dp->dp_if.if_ierrors++;
395: } else
396: dpinput(&dp->dp_if, dp->dp_ilen, dp->dp_ibuf);
397: pdma->p_mem = pdma->p_end;
398: dp->dp_flags &= ~ DPF_FLUSH;
399: return;
400: }
401: if (rdsr & DP_ROVR) {
402: dpstat.rovr++;
403: dp->dp_flags |= DPF_FLUSH;
404: return;
405: }
406: if (rcsr & DP_MSC) {
407: dpstat.mchange++;
408: if (0 == (rcsr & DP_DSR)) {
409: log(LOG_DEBUG, "dp%d: lost modem\n", unit);
410: /*dpdown(unit);*/
411: }
412: return;
413: }
414: dp->dp_flags |= DPF_FLUSH;
415: if (pdma->p_mem != pdma->p_end)
416: log(LOG_DEBUG, "dp%d: unexplained receiver interrupt\n", unit);
417: }
418: /*
419: * Transmit complete or error interrupt
420: */
421: dpxint(unit, pdma, addr)
422: register struct pdma *pdma;
423: register struct dpdevice *addr;
424: {
425: register struct dp_softc *dp = &dp_softc[unit];
426: int s;
427:
428: splx(dp->dp_ipl);
429: dpstat.xint++;
430: if (addr->dptdsr & DP_XERR) {
431: log(LOG_DEBUG, "if_dp%d: data late\n", unit);
432: restart:
433: pdma->p_mem = dp->dp_obuf;
434: addr->dptdsr = DP_XSM;
435: dp->dp_if.if_oerrors++;
436: return;
437: }
438: switch (dp->dp_ostate) {
439:
440: case DPS_ACTIVE:
441: if (pdma->p_mem != pdma->p_end) {
442: log(LOG_DEBUG, "if_dp%d: misc error in dpxint\n", unit);
443: goto restart;
444: }
445: addr->dpsar = DP_IDLE|DP_SSLM;
446: addr->dpclr = DP_XE | DP_XIE | dp_ilb;
447: addr->dptdsr = DP_XEM | (0xff & pdma->p_mem[0]);
448: addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
449: dp->dp_ostate = DPS_XEM;
450: break;
451:
452: case DPS_XEM:
453: dpstat.xem++;
454: dp->dp_if.if_opackets++;
455: dp->dp_ostate = DPS_IDLE;
456: dp->dp_if.if_flags &= ~IFF_OACTIVE;
457: if (dp->dp_if.if_snd.ifq_len)
458: dpstart(&dp->dp_if);
459: else {
460: addr->dpsar = DP_IDLE|DP_SSLM;
461: addr->dpclr = DP_XE | dp_ilb;
462: addr->dptdsr = DP_XSM;
463: addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR|DP_RTS;
464: }
465: break;
466:
467: default:
468: log(LOG_DEBUG, "if_dp%d: impossible state in dpxint\n");
469: }
470: }
471: /*
472: * Routine to copy from device buffer into mbufs.
473: *
474: * Warning: This makes the fairly safe assumption that
475: * mbufs have even lengths.
476: */
477: struct mbuf *
478: dpget(rxbuf, totlen, off, ifp)
479: caddr_t rxbuf;
480: int totlen, off;
481: struct ifnet *ifp;
482: {
483: register caddr_t cp;
484: register struct mbuf *m;
485: struct mbuf *top = 0, **mp = ⊤
486: int len;
487: caddr_t packet_end;
488:
489: cp = rxbuf;
490: packet_end = cp + totlen;
491: if (off) {
492: off += 2 * sizeof(u_short);
493: totlen -= 2 *sizeof(u_short);
494: cp = rxbuf + off;
495: }
496:
497: MGETHDR(m, M_DONTWAIT, MT_DATA);
498: if (m == 0)
499: return (0);
500: m->m_pkthdr.rcvif = ifp;
501: m->m_pkthdr.len = totlen;
502: m->m_len = MHLEN;
503:
504: while (totlen > 0) {
505: if (top) {
506: MGET(m, M_DONTWAIT, MT_DATA);
507: if (m == 0) {
508: m_freem(top);
509: return (0);
510: }
511: m->m_len = MLEN;
512: }
513: len = min(totlen, (packet_end - cp));
514: if (len >= MINCLSIZE) {
515: MCLGET(m, M_DONTWAIT);
516: if (m->m_flags & M_EXT)
517: m->m_len = len = min(len, MCLBYTES);
518: else
519: len = m->m_len;
520: } else {
521: /*
522: * Place initial small packet/header at end of mbuf.
523: */
524: if (len < m->m_len) {
525: if (top == 0 && len + max_linkhdr <= m->m_len)
526: m->m_data += max_linkhdr;
527: m->m_len = len;
528: } else
529: len = m->m_len;
530: }
531: bcopy(cp, mtod(m, caddr_t), (u_int)len);
532: *mp = m;
533: mp = &m->m_next;
534: totlen -= len;
535: cp += len;
536: if (cp == packet_end)
537: cp = rxbuf;
538: }
539: return (top);
540: }
541:
542: dpinput(ifp, len, buffer)
543: register struct ifnet *ifp;
544: caddr_t buffer;
545: {
546: register struct ifqueue *inq;
547: register struct mbuf *m;
548: extern struct ifqueue hdintrq, ipintrq;
549: int isr;
550:
551: ifp->if_ipackets++;
552: if (dp_log) {
553: register u_char *p = (u_char *)buffer;
554: log(LOG_DEBUG, "dpinput(%d):%x %x %x %x %x\n",
555: len, p[0], p[1], p[2], p[3], p[4]);
556: }
557:
558: {
559: register struct ifaddr *ifa = ifp->if_addrlist;
560: register u_char *cp = (u_char *)buffer;
561:
562: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
563: if (ifa->ifa_addr->sa_family != AF_LINK)
564: break;
565: if (cp[0] == 0xff && cp[1] == 0x3) {
566: /* This is a UI HDLC Packet, so we'll assume PPP
567: protocol. for now, IP only. */
568: buffer += 4;
569: len -= 4;
570: inq = &ipintrq;
571: isr = NETISR_IP;
572: } else {
573: inq = &hdintrq;
574: isr = NETISR_CCITT;
575: }
576: }
577: if (len <= 0)
578: return;
579:
580: m = dpget(buffer, len , 0, ifp);
581: if (m == 0)
582: return;
583:
584: if(IF_QFULL(inq)) {
585: IF_DROP(inq);
586: m_freem(m);
587: } else {
588: IF_ENQUEUE(inq, m);
589: schednetisr(isr);
590: }
591: }
592:
593: /*
594: * Process an ioctl request.
595: */
596: dpioctl(ifp, cmd, data)
597: register struct ifnet *ifp;
598: int cmd;
599: caddr_t data;
600: {
601: register struct ifaddr *ifa = (struct ifaddr *)data;
602: int s = splimp(), error = 0;
603: struct dp_softc *dp = &dp_softc[ifp->if_unit];
604:
605: dpstat.ioctl++;
606: switch (cmd) {
607: case SIOCSIFCONF_X25:
608: ifp->if_flags |= IFF_UP;
609: error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
610: if (error == 0)
611: dpinit(ifp->if_unit);
612: break;
613:
614: case SIOCSIFADDR:
615: ifa->ifa_rtrequest = x25_rtrequest;
616: break;
617:
618: case SIOCSIFFLAGS:
619: if ((ifp->if_flags & IFF_UP) == 0 &&
620: (ifp->if_flags & IFF_RUNNING))
621: dpdown(ifp->if_unit);
622: else if (ifp->if_flags & IFF_UP &&
623: (ifp->if_flags & IFF_RUNNING) == 0)
624: dpinit(ifp->if_unit);
625: break;
626:
627:
628: default:
629: error = EINVAL;
630: }
631: splx(s);
632: return (error);
633: }
634: /*
635: * Reset a device and mark down.
636: * Flush output queue and drop queue limit.
637: */
638: dpdown(unit)
639: int unit;
640: {
641:
642: register struct dp_softc *dp = &dp_softc[unit];
643: register struct dpdevice *addr = dp->dp_addr;
644:
645: dpstat.down++;
646: if_qflush(&dp->dp_if.if_snd);
647: dp->dp_flags = 0;
648: dp->dp_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
649:
650: addr->dpclr = DP_CLR;
651: DELAY(1000);
652: addr->dpsar = 0;
653: addr->dprcsr = 0;
654: }
655:
656: /*
657: * Watchdog timeout to see that transmitted packets don't
658: * lose interrupts. The device has to be online (the first
659: * transmission may block until the other side comes up).
660: */
661: dptimeout(unit)
662: int unit;
663: {
664: register struct dp_softc *dp;
665:
666: /* currently not armed */
667: dpstat.timeout++;
668: dp = &dp_softc[unit];
669: if (dp->dp_if.if_flags & IFF_OACTIVE) {
670: dpstart(&dp->dp_if);
671: }
672: }
673: /*
674: * For debugging loopback activity.
675: */
676: static char pppheader[4] = { -1, 3, 0, 0x21 };
677: int dp_louts;
678:
679: dptestoutput(ifp, m, dst, rt)
680: register struct ifnet *ifp;
681: register struct mbuf *m;
682: struct sockaddr *dst;
683: struct rtentry *rt;
684: {
685: /*
686: * Queue message on interface, and start output if interface
687: * not yet active.
688: */
689: int s = splimp(), error = 0;
690: dp_louts++;
691: M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
692: if (m == 0) {
693: splx(s);
694: return ENOBUFS;
695: }
696: bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
697: if (IF_QFULL(&ifp->if_snd)) {
698: IF_DROP(&ifp->if_snd);
699: /* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
700: ifp->if_name, ifp->if_unit);*/
701: m_freem(m);
702: error = ENOBUFS;
703: } else {
704: IF_ENQUEUE(&ifp->if_snd, m);
705: if ((ifp->if_flags & IFF_OACTIVE) == 0)
706: (*ifp->if_start)(ifp);
707: }
708: splx(s);
709: return (error);
710: }
711:
712: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.