kernel: Sync ACPICA with Intel's version 20140424.
[dragonfly.git] / sys / netproto / atm / ipatm / ipatm_usrreq.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/ipatm/ipatm_usrreq.c,v 1.5.2.1 2003/02/15 09:25:13 phk Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/ipatm/ipatm_usrreq.c,v 1.7 2006/01/14 13:36:39 swildner Exp $
28  */
29
30 /*
31  * IP Over ATM Support
32  * -------------------
33  *
34  * Process user requests
35  *
36  */
37
38 #include <netproto/atm/kern_include.h>
39
40 #include "ipatm_var.h"
41 #include "ipatm_serv.h"
42
43 /*
44  * Process IP PF_ATM ioctls
45  * 
46  * Called at splnet.
47  *
48  * Arguments:
49  *      code    PF_ATM sub-operation code
50  *      data    pointer to code specific parameter data area
51  *      arg1    pointer to code specific argument
52  *
53  * Returns:
54  *      0       request procesed
55  *      errno   error processing request - reason indicated
56  *
57  */
58 int
59 ipatm_ioctl(int code, caddr_t data, caddr_t arg1)
60 {
61         struct atmaddreq        *aap;
62         struct atmdelreq        *adp;
63         struct atminfreq        *aip;
64         struct air_ip_vcc_rsp   aivr;
65         struct atm_nif  *nip;
66         struct ip_nif   *inp;
67         struct ipvcc    *ivp;
68         struct vccb     *vcp;
69         struct ipatmpvc pv;
70         caddr_t         cp;
71         struct in_addr  ip;
72         int             space, err = 0;
73
74
75         switch (code) {
76
77         case AIOCS_ADD_PVC:
78                 /*
79                  * Add an IP PVC
80                  */
81                 aap = (struct atmaddreq *)data;
82
83                 /*
84                  * Find the IP network interface
85                  */
86                 if ((nip = atm_nifname(aap->aar_pvc_intf)) == NULL) {
87                         err = ENXIO;
88                         break;
89                 }
90
91                 for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
92                         if (inp->inf_nif == nip)
93                                 break;
94                 }
95                 if (inp == NULL) {
96                         err = ENXIO;
97                         break;
98                 }
99
100                 /*
101                  * Validate PVC params
102                  */
103                 if (aap->aar_pvc_aal == ATM_AAL5) {
104                         if ((aap->aar_pvc_encaps != ATM_ENC_LLC) &&
105                             (aap->aar_pvc_encaps != ATM_ENC_NULL)) {
106                                 err = EINVAL;
107                                 break;
108                         }
109                 } else if (aap->aar_pvc_aal == ATM_AAL3_4) {
110                         if (aap->aar_pvc_encaps != ATM_ENC_NULL) {
111                                 err = EINVAL;
112                                 break;
113                         }
114                 } else {
115                         err = EINVAL;
116                         break;
117                 }
118
119                 if (aap->aar_pvc_flags & PVC_DYN) {
120                         /*
121                          * For dynamic PVC destination addressing, the
122                          * network interface must have support for this
123                          */
124                         if ((inp->inf_serv == NULL) ||
125                             (inp->inf_serv->is_arp_pvcopen == NULL)) {
126                                 err = EDESTADDRREQ;
127                                 break;
128                         }
129                 } else {
130                         u_long  dst = ((struct sockaddr_in *)&aap->aar_pvc_dst)
131                                                 ->sin_addr.s_addr;
132
133                         if (dst == INADDR_ANY) {
134                                 err = EINVAL;
135                                 break;
136                         }
137                 }
138
139                 /*
140                  * Build connection request
141                  */
142                 pv.ipp_ipnif = inp;
143                 pv.ipp_vpi = aap->aar_pvc_vpi;
144                 pv.ipp_vci = aap->aar_pvc_vci;
145                 pv.ipp_encaps = aap->aar_pvc_encaps;
146                 pv.ipp_aal = aap->aar_pvc_aal;
147                 if (aap->aar_pvc_flags & PVC_DYN) {
148                         pv.ipp_dst.sin_addr.s_addr = INADDR_ANY;
149                 } else
150                         pv.ipp_dst = *(struct sockaddr_in *)&aap->aar_pvc_dst;
151
152                 /*
153                  * Open a new VCC
154                  */
155                 err = ipatm_openpvc(&pv, &ivp);
156                 break;
157
158         case AIOCS_ADD_ARP:
159                 /*
160                  * Add an ARP mapping
161                  */
162                 aap = (struct atmaddreq *)data;
163
164                 /*
165                  * Validate IP address
166                  */
167                 if (aap->aar_arp_dst.sa_family != AF_INET) {
168                         err = EAFNOSUPPORT;
169                         break;
170                 }
171                 ip = SATOSIN(&aap->aar_arp_dst)->sin_addr;
172
173                 if (aap->aar_arp_intf[0] == '\0') {
174                         /*
175                          * Find the IP network interface associated with
176                          * the supplied IP address
177                          */
178                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
179                                 if (ipatm_chknif(ip, inp) == 0)
180                                         break;
181                         }
182                         if (inp == NULL) {
183                                 err = EADDRNOTAVAIL;
184                                 break;
185                         }
186                 } else {
187                         /*
188                          * Find the specified IP network interface
189                          */
190                         if ((nip = atm_nifname(aap->aar_arp_intf)) == NULL) {
191                                 err = ENXIO;
192                                 break;
193                         }
194                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
195                                 if (inp->inf_nif == nip)
196                                         break;
197                         }
198                         if (inp == NULL) {
199                                 err = ENXIO;
200                                 break;
201                         }
202                 }
203
204                 if ((ip.s_addr == INADDR_ANY) ||
205                     in_broadcast(ip, &inp->inf_nif->nif_if) ||
206                     IN_MULTICAST(ntohl(ip.s_addr))) {
207                         err = EADDRNOTAVAIL;
208                         break;
209                 }
210
211                 /*
212                  * Notify the responsible ARP service
213                  *
214                  * XXX: if there is one.  No idea how this happens, but at
215                  * least don't panic on a NULL pointer if it does.
216                  */
217                 if (inp->inf_serv == NULL) {
218                         err = ENXIO;
219                         break;
220                 }
221                 err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf);
222                 break;
223
224         case AIOCS_DEL_ARP:
225                 /*
226                  * Delete an ARP mapping
227                  */
228                 adp = (struct atmdelreq *)data;
229
230                 /*
231                  * Validate IP address
232                  */
233                 if (adp->adr_arp_dst.sa_family != AF_INET) {
234                         err = EAFNOSUPPORT;
235                         break;
236                 }
237                 ip = SATOSIN(&adp->adr_arp_dst)->sin_addr;
238
239                 if (adp->adr_arp_intf[0] == '\0') {
240                         /*
241                          * Find the IP network interface associated with
242                          * the supplied IP address
243                          */
244                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
245                                 if (ipatm_chknif(ip, inp) == 0)
246                                         break;
247                         }
248                         if (inp == NULL) {
249                                 err = EADDRNOTAVAIL;
250                                 break;
251                         }
252                 } else {
253                         /*
254                          * Find the specified IP network interface
255                          */
256                         if ((nip = atm_nifname(adp->adr_arp_intf)) == NULL) {
257                                 err = ENXIO;
258                                 break;
259                         }
260                         for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
261                                 if (inp->inf_nif == nip)
262                                         break;
263                         }
264                         if (inp == NULL) {
265                                 err = ENXIO;
266                                 break;
267                         }
268                 }
269
270                 if ((ip.s_addr == INADDR_ANY) ||
271                     in_broadcast(ip, &inp->inf_nif->nif_if) ||
272                     IN_MULTICAST(ntohl(ip.s_addr))) {
273                         err = EADDRNOTAVAIL;
274                         break;
275                 }
276
277                 /*
278                  * Notify the responsible ARP service
279                  */
280                 err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf);
281                 break;
282
283         case AIOCS_INF_IPM:
284                 /*
285                  * Get IP VCC information
286                  */
287                 aip = (struct atminfreq *)data;
288
289                 if (aip->air_ip_addr.sa_family != AF_INET)
290                         break;
291                 ip = SATOSIN(&aip->air_ip_addr)->sin_addr;
292
293                 cp = aip->air_buf_addr;
294                 space = aip->air_buf_len;
295
296                 /*
297                  * Loop through all our interfaces
298                  */
299                 for (inp = ipatm_nif_head; inp; inp = inp->inf_next) {
300                         /*
301                          * Check out each VCC
302                          */
303                         for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp;
304                                     ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) {
305
306                                 if ((ip.s_addr != INADDR_ANY) &&
307                                     (ip.s_addr != ivp->iv_dst.s_addr))
308                                         continue;
309
310                                 /*
311                                  * Make sure there's room in user buffer
312                                  */
313                                 if (space < sizeof(aivr)) {
314                                         err = ENOSPC;
315                                         break;
316                                 }
317
318                                 /*
319                                  * Fill in info to be returned
320                                  */
321                                 KM_ZERO((caddr_t)&aivr, sizeof(aivr));
322                                 SATOSIN(&aivr.aip_dst_addr)->sin_family = 
323                                         AF_INET;
324                                 SATOSIN(&aivr.aip_dst_addr)->sin_addr.s_addr = 
325                                         ivp->iv_dst.s_addr;
326                                 strlcpy(aivr.aip_intf,
327                                     inp->inf_nif->nif_if.if_xname,
328                                     sizeof(aivr.aip_intf));
329                                 if ((ivp->iv_conn) &&
330                                     (ivp->iv_conn->co_connvc) &&
331                                     (vcp = ivp->iv_conn->co_connvc->cvc_vcc)) {
332                                         aivr.aip_vpi = vcp->vc_vpi;
333                                         aivr.aip_vci = vcp->vc_vci;
334                                         aivr.aip_sig_proto = vcp->vc_proto;
335                                 } 
336                                 aivr.aip_flags = ivp->iv_flags;
337                                 aivr.aip_state = ivp->iv_state;
338
339                                 /*
340                                  * Copy data to user buffer and 
341                                  * update buffer controls
342                                  */
343                                 err = copyout((caddr_t)&aivr, cp, sizeof(aivr));
344                                 if (err)
345                                         break;
346                                 cp += sizeof(aivr);
347                                 space -= sizeof(aivr);
348                         }
349                         if (err)
350                                 break;
351                 }
352
353                 /*
354                  * Update buffer pointer/count
355                  */
356                 aip->air_buf_addr = cp;
357                 aip->air_buf_len = space;
358                 break;
359
360         default:
361                 err = EOPNOTSUPP;
362         }
363
364         return (err);
365 }
366
367
368 /*
369  * Get Connection's Application/Owner Name
370  * 
371  * Arguments:
372  *      tok     ipatm connection token (pointer to ipvcc)
373  *
374  * Returns:
375  *      addr    pointer to string containing our name
376  *
377  */
378 caddr_t
379 ipatm_getname(void *tok)
380 {
381         return ("IP");
382 }
383