FreeBSD/Linux Kernel Cross Reference
sys/netnatm/natm.c
1 /* $NetBSD: natm.c,v 1.9 2003/06/29 22:32:07 fvdl Exp $ */
2
3 /*
4 *
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * natm.c: native mode ATM access (both aal0 and aal5).
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: natm.c,v 1.9 2003/06/29 22:32:07 fvdl Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/domain.h>
46 #include <sys/ioctl.h>
47 #include <sys/proc.h>
48 #include <sys/protosw.h>
49 #include <sys/mbuf.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52
53 #include <net/if.h>
54 #include <net/if_atm.h>
55 #include <net/netisr.h>
56 #include <net/radix.h>
57 #include <net/route.h>
58
59 #include <netinet/in.h>
60
61 #include <netnatm/natm.h>
62
63 u_long natm5_sendspace = 16*1024;
64 u_long natm5_recvspace = 16*1024;
65
66 u_long natm0_sendspace = 16*1024;
67 u_long natm0_recvspace = 16*1024;
68
69 /*
70 * user requests
71 */
72
73 #if defined(__NetBSD__) || defined(__OpenBSD__)
74 int natm_usrreq(so, req, m, nam, control, p)
75 #elif defined(__FreeBSD__)
76 int natm_usrreq(so, req, m, nam, control)
77 #endif
78
79 struct socket *so;
80 int req;
81 struct mbuf *m, *nam, *control;
82 #if defined(__NetBSD__) || defined(__OpenBSD__)
83 struct proc *p;
84 #endif
85
86 {
87 int error = 0, s, s2;
88 struct natmpcb *npcb;
89 struct sockaddr_natm *snatm;
90 struct atm_pseudoioctl api;
91 struct atm_pseudohdr *aph;
92 struct atm_rawioctl ario;
93 struct ifnet *ifp;
94 int proto = so->so_proto->pr_protocol;
95
96 s = SPLSOFTNET();
97
98 npcb = (struct natmpcb *) so->so_pcb;
99
100 if (npcb == NULL && req != PRU_ATTACH) {
101 error = EINVAL;
102 goto done;
103 }
104
105
106 switch (req) {
107 case PRU_ATTACH: /* attach protocol to up */
108
109 if (npcb) {
110 error = EISCONN;
111 break;
112 }
113
114 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
115 if (proto == PROTO_NATMAAL5)
116 error = soreserve(so, natm5_sendspace, natm5_recvspace);
117 else
118 error = soreserve(so, natm0_sendspace, natm0_recvspace);
119 if (error)
120 break;
121 }
122
123 so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
124 npcb->npcb_socket = so;
125
126 break;
127
128 case PRU_DETACH: /* detach protocol from up */
129
130 /*
131 * we turn on 'drain' *before* we sofree.
132 */
133
134 npcb_free(npcb, NPCB_DESTROY); /* drain */
135 so->so_pcb = NULL;
136 sofree(so);
137
138 break;
139
140 case PRU_CONNECT: /* establish connection to peer */
141
142 /*
143 * validate nam and npcb
144 */
145
146 if (nam->m_len != sizeof(*snatm)) {
147 error = EINVAL;
148 break;
149 }
150 snatm = mtod(nam, struct sockaddr_natm *);
151 if (snatm->snatm_len != sizeof(*snatm) ||
152 (npcb->npcb_flags & NPCB_FREE) == 0) {
153 error = EINVAL;
154 break;
155 }
156 if (snatm->snatm_family != AF_NATM) {
157 error = EAFNOSUPPORT;
158 break;
159 }
160
161 snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
162 since ifunit() uses strcmp */
163
164 /*
165 * convert interface string to ifp, validate.
166 */
167
168 ifp = ifunit(snatm->snatm_if);
169 if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
170 error = ENXIO;
171 break;
172 }
173 if (ifp->if_output != atm_output) {
174 error = EAFNOSUPPORT;
175 break;
176 }
177
178
179 /*
180 * register us with the NATM PCB layer
181 */
182
183 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
184 error = EADDRINUSE;
185 break;
186 }
187
188 /*
189 * enable rx
190 */
191
192 ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
193 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
194 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
195 api.rxhand = npcb;
196 s2 = splnet();
197 if (ifp->if_ioctl == NULL ||
198 ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
199 splx(s2);
200 npcb_free(npcb, NPCB_REMOVE);
201 error = EIO;
202 break;
203 }
204 splx(s2);
205
206 soisconnected(so);
207
208 break;
209
210 case PRU_DISCONNECT: /* disconnect from peer */
211
212 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
213 printf("natm: disconnected check\n");
214 error = EIO;
215 break;
216 }
217 ifp = npcb->npcb_ifp;
218
219 /*
220 * disable rx
221 */
222
223 ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
224 ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
225 ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
226 api.rxhand = npcb;
227 s2 = splnet();
228 if (ifp->if_ioctl != NULL)
229 ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
230 splx(s);
231
232 npcb_free(npcb, NPCB_REMOVE);
233 soisdisconnected(so);
234
235 break;
236
237 case PRU_SHUTDOWN: /* won't send any more data */
238 socantsendmore(so);
239 break;
240
241 case PRU_SEND: /* send this data */
242 if (control && control->m_len) {
243 m_freem(control);
244 m_freem(m);
245 error = EINVAL;
246 break;
247 }
248
249 /*
250 * send the data. we must put an atm_pseudohdr on first
251 */
252
253 M_PREPEND(m, sizeof(*aph), M_WAITOK);
254 if (m == NULL) {
255 error = ENOBUFS;
256 break;
257 }
258 aph = mtod(m, struct atm_pseudohdr *);
259 ATM_PH_VPI(aph) = npcb->npcb_vpi;
260 ATM_PH_SETVCI(aph, npcb->npcb_vci);
261 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
262
263 error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
264
265 break;
266
267 case PRU_SENSE: /* return status into m */
268 /* return zero? */
269 break;
270
271 case PRU_PEERADDR: /* fetch peer's address */
272 snatm = mtod(nam, struct sockaddr_natm *);
273 bzero(snatm, sizeof(*snatm));
274 nam->m_len = snatm->snatm_len = sizeof(*snatm);
275 snatm->snatm_family = AF_NATM;
276 #if defined(__NetBSD__) || defined(__OpenBSD__)
277 bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
278 #elif defined(__FreeBSD__)
279 sprintf(snatm->snatm_if, "%s%d", npcb->npcb_ifp->if_name,
280 npcb->npcb_ifp->if_unit);
281 #endif
282 snatm->snatm_vci = npcb->npcb_vci;
283 snatm->snatm_vpi = npcb->npcb_vpi;
284 break;
285
286 case PRU_CONTROL: /* control operations on protocol */
287 /*
288 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
289 * SIOCXRAWATM and pass it to the driver.
290 */
291 if ((u_long)m == SIOCRAWATM) {
292 if (npcb->npcb_ifp == NULL) {
293 error = ENOTCONN;
294 break;
295 }
296 ario.npcb = npcb;
297 ario.rawvalue = *((int *)nam);
298 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
299 SIOCXRAWATM, (caddr_t) &ario);
300 if (!error) {
301 if (ario.rawvalue)
302 npcb->npcb_flags |= NPCB_RAW;
303 else
304 npcb->npcb_flags &= ~(NPCB_RAW);
305 }
306
307 break;
308 }
309
310 error = EOPNOTSUPP;
311 break;
312
313 case PRU_BIND: /* bind socket to address */
314 case PRU_LISTEN: /* listen for connection */
315 case PRU_ACCEPT: /* accept connection from peer */
316 case PRU_CONNECT2: /* connect two sockets */
317 case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
318 /* (only happens if LISTEN socket) */
319 case PRU_RCVD: /* have taken data; more room now */
320 case PRU_FASTTIMO: /* 200ms timeout */
321 case PRU_SLOWTIMO: /* 500ms timeout */
322 case PRU_RCVOOB: /* retrieve out of band data */
323 case PRU_SENDOOB: /* send out of band data */
324 case PRU_PROTORCV: /* receive from below */
325 case PRU_PROTOSEND: /* send to below */
326 case PRU_SOCKADDR: /* fetch socket's address */
327 #ifdef DIAGNOSTIC
328 printf("natm: PRU #%d unsupported\n", req);
329 #endif
330 error = EOPNOTSUPP;
331 break;
332
333 default: panic("natm usrreq");
334 }
335
336 done:
337 splx(s);
338 return(error);
339 }
340
341 /*
342 * natmintr: splsoftnet interrupt
343 *
344 * note: we expect a socket pointer in rcvif rather than an interface
345 * pointer. we can get the interface pointer from the so's PCB if
346 * we really need it.
347 */
348
349 void
350 natmintr()
351
352 {
353 int s;
354 struct mbuf *m;
355 struct socket *so;
356 struct natmpcb *npcb;
357
358 next:
359 s = splnet();
360 IF_DEQUEUE(&natmintrq, m);
361 splx(s);
362 if (m == NULL)
363 return;
364
365 #ifdef DIAGNOSTIC
366 if ((m->m_flags & M_PKTHDR) == 0)
367 panic("natmintr no HDR");
368 #endif
369
370 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
371 so = npcb->npcb_socket;
372
373 s = splnet(); /* could have atm devs @ different levels */
374 npcb->npcb_inq--;
375 splx(s);
376
377 if (npcb->npcb_flags & NPCB_DRAIN) {
378 m_freem(m);
379 if (npcb->npcb_inq == 0)
380 FREE(npcb, M_PCB); /* done! */
381 goto next;
382 }
383
384 if (npcb->npcb_flags & NPCB_FREE) {
385 m_freem(m); /* drop */
386 goto next;
387 }
388
389 #ifdef NEED_TO_RESTORE_IFP
390 m->m_pkthdr.rcvif = npcb->npcb_ifp;
391 #else
392 #ifdef DIAGNOSTIC
393 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
394 #endif
395 #endif
396
397 if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
398 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
399 #ifdef NATM_STAT
400 natm_sookcnt++;
401 natm_sookbytes += m->m_pkthdr.len;
402 #endif
403 sbappendrecord(&so->so_rcv, m);
404 sorwakeup(so);
405 } else {
406 #ifdef NATM_STAT
407 natm_sodropcnt++;
408 natm_sodropbytes += m->m_pkthdr.len;
409 #endif
410 m_freem(m);
411 }
412
413 goto next;
414 }
415
416 #if defined(__FreeBSD__)
417 NETISR_SET(NETISR_NATM, natmintr);
418 #endif
419
420
421 /*
422 * natm0_sysctl: not used, but here in case we want to add something
423 * later...
424 */
425
426 int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
427
428 int *name;
429 u_int namelen;
430 void *oldp;
431 size_t *oldlenp;
432 void *newp;
433 size_t newlen;
434
435 {
436 /* All sysctl names at this level are terminal. */
437 if (namelen != 1)
438 return (ENOTDIR);
439 return (ENOPROTOOPT);
440 }
441
442 /*
443 * natm5_sysctl: not used, but here in case we want to add something
444 * later...
445 */
446
447 int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
448
449 int *name;
450 u_int namelen;
451 void *oldp;
452 size_t *oldlenp;
453 void *newp;
454 size_t newlen;
455
456 {
457 /* All sysctl names at this level are terminal. */
458 if (namelen != 1)
459 return (ENOTDIR);
460 return (ENOPROTOOPT);
461 }
Cache object: 417e9a4e9d070db52f8522b9fc24aa49
|