Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dgrp_common.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 1999 Digi International (www.digi.com)
4  * James Puzzo <jamesp at digi dot com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
13  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  * PURPOSE. See the GNU General Public License for more details.
15  *
16  */
17 
18 /*
19  *
20  * Filename:
21  *
22  * dgrp_common.c
23  *
24  * Description:
25  *
26  * Definitions of global variables and functions which are either
27  * shared by the tty, mon, and net drivers; or which cross them
28  * functionally (like the poller).
29  *
30  * Author:
31  *
32  * James A. Puzzo
33  *
34  */
35 
36 #include <linux/errno.h>
37 #include <linux/tty.h>
38 #include <linux/sched.h>
39 #include <linux/cred.h>
40 
41 #include "dgrp_common.h"
42 
47 void dgrp_carrier(struct ch_struct *ch)
48 {
49  struct nd_struct *nd;
50 
51  int virt_carrier = 0;
52  int phys_carrier = 0;
53 
54  /* fix case when the tty has already closed. */
55 
56  if (!ch)
57  return;
58  nd = ch->ch_nd;
59  if (!nd)
60  return;
61 
62  /*
63  * If we are currently waiting to determine the status of the port,
64  * we don't yet know the state of the modem lines. As a result,
65  * we ignore state changes when we are waiting for the modem lines
66  * to be established. We know, as a result of code in dgrp_net_ops,
67  * that we will be called again immediately following the reception
68  * of the status message with the true modem status flags in it.
69  */
70  if (ch->ch_expect & RR_STATUS)
71  return;
72 
73  /*
74  * If CH_HANGUP is set, we gotta keep trying to get all the processes
75  * that have the port open to close the port.
76  * So lets just keep sending a hangup every time we get here.
77  */
78  if ((ch->ch_flag & CH_HANGUP) &&
79  (ch->ch_tun.un_open_count > 0))
80  tty_hangup(ch->ch_tun.un_tty);
81 
82  /*
83  * Compute the effective state of both the physical and virtual
84  * senses of carrier.
85  */
86 
87  if (ch->ch_s_mlast & DM_CD)
88  phys_carrier = 1;
89 
90  if ((ch->ch_s_mlast & DM_CD) ||
91  (ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
92  (ch->ch_flag & CH_CLOCAL))
93  virt_carrier = 1;
94 
95  /*
96  * Test for a VIRTUAL carrier transition to HIGH.
97  *
98  * The CH_HANGUP condition is intended to prevent any action
99  * except for close. As a result, we ignore positive carrier
100  * transitions during CH_HANGUP.
101  */
102  if (((ch->ch_flag & CH_HANGUP) == 0) &&
103  ((ch->ch_flag & CH_VIRT_CD) == 0) &&
104  (virt_carrier == 1)) {
105  /*
106  * When carrier rises, wake any threads waiting
107  * for carrier in the open routine.
108  */
109  nd->nd_tx_work = 1;
110 
111  if (waitqueue_active(&ch->ch_flag_wait))
113  }
114 
115  /*
116  * Test for a PHYSICAL transition to low, so long as we aren't
117  * currently ignoring physical transitions (which is what "virtual
118  * carrier" indicates).
119  *
120  * The transition of the virtual carrier to low really doesn't
121  * matter... it really only means "ignore carrier state", not
122  * "make pretend that carrier is there".
123  */
124  if ((virt_carrier == 0) &&
125  ((ch->ch_flag & CH_PHYS_CD) != 0) &&
126  (phys_carrier == 0)) {
127  /*
128  * When carrier drops:
129  *
130  * Do a Hard Hangup if that is called for.
131  *
132  * Drop carrier on all open units.
133  *
134  * Flush queues, waking up any task waiting in the
135  * line discipline.
136  *
137  * Send a hangup to the control terminal.
138  *
139  * Enable all select calls.
140  */
141 
142  nd->nd_tx_work = 1;
143 
144  ch->ch_flag &= ~(CH_LOW | CH_EMPTY | CH_DRAIN | CH_INPUT);
145 
146  if (waitqueue_active(&ch->ch_flag_wait))
148 
149  if (ch->ch_tun.un_open_count > 0)
150  tty_hangup(ch->ch_tun.un_tty);
151 
152  if (ch->ch_pun.un_open_count > 0)
153  tty_hangup(ch->ch_pun.un_tty);
154  }
155 
156  /*
157  * Make sure that our cached values reflect the current reality.
158  */
159  if (virt_carrier == 1)
160  ch->ch_flag |= CH_VIRT_CD;
161  else
162  ch->ch_flag &= ~CH_VIRT_CD;
163 
164  if (phys_carrier == 1)
165  ch->ch_flag |= CH_PHYS_CD;
166  else
167  ch->ch_flag &= ~CH_PHYS_CD;
168 
169 }
170 
180 int dgrp_chk_perm(int mode, int op)
181 {
182  if (!uid_eq(GLOBAL_ROOT_UID, current_euid()))
183  mode >>= 6;
184  else if (in_egroup_p(GLOBAL_ROOT_GID))
185  mode >>= 3;
186 
187  if ((mode & op & 0007) == op)
188  return 0;
189 
190  if (capable(CAP_SYS_ADMIN))
191  return 0;
192 
193  return -EACCES;
194 }
195 
196 /* dgrp_chk_perm wrapper for permission call in struct inode_operations */
198 {
199  return dgrp_chk_perm(inode->i_mode, op);
200 }